From 5338b1d5f2f532096ad734020312e46e6f688280 Mon Sep 17 00:00:00 2001 From: xiao xie <335266746@qq.com> Date: Tue, 15 Nov 2022 12:51:35 +0800 Subject: [PATCH] [imxrt1176]Fix usb (#6589) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 修复USB驱动,实现imxrt1176平台usb host,支持usb3.0读写 --- bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig | 35 +- bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c | 18 +- .../MIMXRT1176/drivers/fsl_os_abstraction.h | 812 ++++++++++ .../drivers/fsl_os_abstraction_config.h | 36 + .../drivers/fsl_os_abstraction_rtthread.c | 917 ++++++++++++ .../drivers/fsl_os_abstraction_rtthread.h | 130 ++ .../MIMXRT1176/drivers/generic_list.c | 475 ++++++ .../MIMXRT1176/drivers/generic_list.h | 203 +++ bsp/imxrt/libraries/MIMXRT1170/SConscript | 4 + bsp/imxrt/libraries/drivers/drv_usbh.c | 25 +- .../libraries/drivers/usb/host/usb_host.h | 5 + .../drivers/usb/host/usb_host_devices.c | 1327 +++++++++++++++++ .../drivers/usb/host/usb_host_ehci.c | 192 ++- .../drivers/usb/host/usb_host_ehci.h | 9 +- .../libraries/drivers/usb/host/usb_host_hci.c | 16 +- bsp/imxrt/libraries/drivers/usb/include/usb.h | 16 + .../drivers/usb/include/usb_host_config.h | 26 +- bsp/imxrt/libraries/drivers/usb/phy/usb_phy.c | 268 ++++ bsp/imxrt/libraries/drivers/usb/phy/usb_phy.h | 18 +- 19 files changed, 4497 insertions(+), 35 deletions(-) create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_config.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.h create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.c create mode 100644 bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.h diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig index 9da703c118..7092b19828 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/Kconfig @@ -27,7 +27,22 @@ menu "On-chip Peripheral Drivers" bool "Enable RTC" select RT_USING_RTC default n + + config BSP_USING_USB + bool "Enable USB" + select RT_USING_USB_HOST + default n + + if BSP_USING_USB + config BSP_USB0_HOST + bool "Enable USB0" + default n + config BSP_USB1_HOST + bool "Enable USB1" + default n + endif + config BSP_USING_SDIO bool "Enable SDIO" select RT_USING_SDIO @@ -52,17 +67,17 @@ menu "On-chip Peripheral Drivers" bool "Enable LPUART1" default y - config BSP_LPUART1_RX_USING_DMA - bool "Enable LPUART1 RX DMA" - depends on BSP_USING_LPUART1 - select BSP_USING_DMA - select RT_SERIAL_USING_DMA - default n + config BSP_LPUART1_RX_USING_DMA + bool "Enable LPUART1 RX DMA" + depends on BSP_USING_LPUART1 + select BSP_USING_DMA + select RT_SERIAL_USING_DMA + default n - config BSP_LPUART1_RX_DMA_CHANNEL - depends on BSP_LPUART1_RX_USING_DMA - int "Set LPUART1 RX DMA channel (0-32)" - default 0 + config BSP_LPUART1_RX_DMA_CHANNEL + depends on BSP_LPUART1_RX_USING_DMA + int "Set LPUART1 RX DMA channel (0-32)" + default 0 config BSP_LPUART1_TX_USING_DMA bool "Enable LPUART1 TX DMA" diff --git a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c index a9dc521eb4..e9f0b90ad2 100644 --- a/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c +++ b/bsp/imxrt/imxrt1170-nxp-evk/m7/board/board.c @@ -126,7 +126,7 @@ static void BOARD_ConfigMPU(void) /* Region 0 setting: Instruction access disabled, No data access permission. */ MPU->RBAR = ARM_MPU_RBAR(0, 0x00000000U); - MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 2, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); + MPU->RASR = ARM_MPU_RASR(1, ARM_MPU_AP_NONE, 0, 0, 0, 0, 0, ARM_MPU_REGION_SIZE_4GB); /* Region 1 setting: Memory with Device type, not shareable, non-cacheable. */ MPU->RBAR = ARM_MPU_RBAR(1, 0x80000000U); @@ -148,6 +148,15 @@ static void BOARD_ConfigMPU(void) MPU->RBAR = ARM_MPU_RBAR(5, 0x20000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_256KB); +#if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH + /* Region 6 setting: Memory with Normal type, not shareable, write through */ + MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_1MB); + + /* Region 7 setting: Memory with Normal type, not shareable, write trough */ + MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_512KB); +#else /* Region 6 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(6, 0x20200000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_1MB); @@ -155,6 +164,7 @@ static void BOARD_ConfigMPU(void) /* Region 7 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(7, 0x20300000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_512KB); +#endif #if defined(XIP_EXTERNAL_FLASH) && (XIP_EXTERNAL_FLASH == 1) /* Region 8 setting: Memory with Normal type, not shareable, outer/inner write back. */ @@ -163,9 +173,15 @@ static void BOARD_ConfigMPU(void) #endif #ifdef USE_SDRAM +#if defined(CACHE_MODE_WRITE_THROUGH) && CACHE_MODE_WRITE_THROUGH + /* Region 9 setting: Memory with Normal type, not shareable, write trough */ + MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U); + MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 0, 0, ARM_MPU_REGION_SIZE_64MB); +#else /* Region 9 setting: Memory with Normal type, not shareable, outer/inner write back */ MPU->RBAR = ARM_MPU_RBAR(9, 0x80000000U); MPU->RASR = ARM_MPU_RASR(0, ARM_MPU_AP_FULL, 0, 0, 1, 1, 0, ARM_MPU_REGION_SIZE_64MB); +#endif #endif while ((size >> i) > 0x1U) diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction.h new file mode 100644 index 0000000000..379bde9c2c --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction.h @@ -0,0 +1,812 @@ +/* + * 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_ + +#include "fsl_common.h" +#include "fsl_os_abstraction_config.h" +#include "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 */ +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; + +#ifdef USE_RTOS +#undef USE_RTOS +#endif + +#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) + +/*! @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 osaWaitForever_c ((uint32_t)(-1)) +#define osaEventFlagsAll_c ((osa_event_flags_t)(0x00FFFFFF)) +#define osThreadStackArray(name) osThread_##name##_stack +#define osThreadStackDef(name, stacksize, instances) \ + 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(FSL_RTOS_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(FSL_RTOS_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 +#else +#define OSA_TASK_DEFINE(name, priority, instances, stackSz, useFloat) \ + 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) &os_thread_def_##name + +#define OSA_TASK_PROTO(name) externosa_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. + * + */ + +/*< 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)] + +/*! + * @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)] + +#include "fsl_os_abstraction_rtthread.h" + +extern const uint8_t gUseRtos_c; + +/* + * alloc the temporary memory to store the status + */ +#define OSA_SR_ALLOC() uint32_t osaCurrentSr; +/* + * 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 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, 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 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 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/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_config.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_config.h new file mode 100644 index 0000000000..234cf972bc --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_config.h @@ -0,0 +1,36 @@ +/*! + * 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 1 +#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 */ + +#endif /* _FSL_OS_ABSTRACTION_CONFIG_H_ */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c new file mode 100644 index 0000000000..524744c251 --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c @@ -0,0 +1,917 @@ +/*! ********************************************************************************* + * 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_rtthread.h" +#include +#include "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; + rt_thread_t taskHandle; +} osa_freertos_task_t; + +typedef struct _osa_event_struct +{ + rt_event_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; + OSA_TASK_HANDLE_DEFINE(mainTaskHandle); +#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 = rt_malloc(length); + + if (RT_NULL != p) + { + rt_memset(p, 0, length); + } + + return p; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_MemoryFree + * Description : Frees the memory previously reserved. + * + *END**************************************************************************/ +void OSA_MemoryFree(void *p) +{ + rt_free(p); +} + +void OSA_EnterCritical(uint32_t *sr) +{ + if (rt_thread_self() != RT_NULL) + rt_enter_critical(); +} + +void OSA_ExitCritical(uint32_t sr) +{ + if (rt_thread_self() != RT_NULL) + rt_exit_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(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(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, osa_task_def_t *thread_def, osa_task_param_t task_param) +{ + assert(sizeof(osa_freertos_task_t) == OSA_TASK_HANDLE_SIZE); + assert(taskHandle); + TaskHandle_t pxCreatedTask; + osa_freertos_task_t *ptask = (osa_freertos_task_t *)taskHandle; + + 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; + OSA_InterruptDisable(); + (void)LIST_AddTail(&s_osaState.taskList, (list_element_handle_t) & (ptask->link)); + OSA_InterruptEnable(); + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} +#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(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) +{ + rt_thread_mdelay(millisec); +} +/*FUNCTION********************************************************************** + * + * Function Name : OSA_TimeGetMsec + * Description : This function gets current time in milliseconds. + * + *END**************************************************************************/ +uint32_t OSA_TimeGetMsec(void) +{ + return rt_tick_get_millisecond(); +} +/*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(semaphoreHandle); + + union + { + rt_sem_t sem; + uint32_t semhandle; + } xSemaHandle; + + xSemaHandle.sem = rt_sem_create("osa_sem", initValue, RT_IPC_FLAG_PRIO); + 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(semaphoreHandle); + rt_sem_t sem = (rt_sem_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + + rt_sem_delete(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) +{ + int32_t timeoutTicks; + assert(semaphoreHandle); + rt_sem_t sem = (rt_sem_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = RT_WAITING_FOREVER; + } + else + { + timeoutTicks = rt_tick_from_millisecond(millisec); + } + + if (RT_EOK != rt_sem_take(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(semaphoreHandle); + rt_sem_t sem = (rt_sem_t)(void *)(uint32_t *)(*(uint32_t *)semaphoreHandle); + rt_sem_release(sem); + return KOSA_StatusSuccess; +} + +/*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(mutexHandle); + + union + { + rt_mutex_t mutex; + uint32_t pmutexHandle; + } xMutexHandle; + + xMutexHandle.mutex = rt_mutex_create("osa_mutex", RT_IPC_FLAG_PRIO); + if (RT_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(mutexHandle); + int32_t timeoutTicks; + rt_mutex_t mutex = (rt_mutex_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = RT_WAITING_FOREVER; + } + else + { + timeoutTicks = rt_tick_from_millisecond(millisec); + } + + if (RT_EOK != rt_mutex_take(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(mutexHandle); + rt_mutex_t mutex = (rt_mutex_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + rt_mutex_release(mutex); + 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(mutexHandle); + rt_mutex_t mutex = (rt_mutex_t)(void *)(uint32_t *)(*(uint32_t *)mutexHandle); + + rt_mutex_delete(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(eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + pEventStruct->handle = rt_event_create("osa_event", RT_IPC_FLAG_PRIO); + if (RT_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) +{ + rt_err_t result; + assert(eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (RT_NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + rt_event_send(pEventStruct->handle, (rt_uint32_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(eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (RT_NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + rt_uint32_t recved; + rt_event_recv(pEventStruct->handle, (rt_uint32_t)flagsToClear, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, 0, &recved); + + 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(eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + rt_uint32_t eventFlags; + + if (RT_NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + if (RT_NULL == pFlagsOfEvent) + { + return KOSA_StatusError; + } + + if (RT_EOK != rt_event_recv(pEventStruct->handle, (rt_uint32_t)flagsMask, RT_EVENT_FLAG_OR, 0, &eventFlags)) + { + eventFlags = 0; + } + + *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(eventHandle); + rt_uint8_t option = 0; + rt_int32_t timeoutTicks; + rt_uint32_t flagsSave; + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + /* Clean FreeRTOS cotrol flags */ + flagsToWait = flagsToWait & 0x00FFFFFFU; + if (RT_NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + + /* Convert timeout from millisecond to tick. */ + if (millisec == osaWaitForever_c) + { + timeoutTicks = RT_WAITING_FOREVER; + } + else + { + timeoutTicks = rt_tick_from_millisecond(millisec); + } + + if (pEventStruct->autoClear != 0U) + { + option |= RT_EVENT_FLAG_CLEAR; + } + option |= waitAll ? RT_EVENT_FLAG_AND : RT_EVENT_FLAG_OR; + + rt_err_t status = rt_event_recv(pEventStruct->handle, (rt_uint32_t)flagsToWait, option, timeoutTicks, &flagsSave); + + flagsSave &= (rt_uint32_t)flagsToWait; + if (RT_NULL != pSetFlags) + { + *pSetFlags = (osa_event_flags_t)flagsSave; + } + + if (RT_EOK != status) + { + return KOSA_StatusTimeout; + } + else + { + return KOSA_StatusSuccess; + } +} + +/*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(eventHandle); + osa_event_struct_t *pEventStruct = (osa_event_struct_t *)eventHandle; + + if (RT_NULL == pEventStruct->handle) + { + return KOSA_StatusError; + } + rt_event_delete(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(msgqHandle); + + union + { + rt_mq_t msgq; + uint32_t pmsgqHandle; + } xMsgqHandle; + + /* Create the message queue where the number and size is specified by msgNo and msgSize */ + xMsgqHandle.msgq = rt_mq_create("osa_mq", msgSize, msgNo, RT_IPC_FLAG_PRIO); + if (RT_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) +{ + assert(msgqHandle); + rt_mq_t handler = (rt_mq_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + if (RT_EOK == rt_mq_send(handler, pMessage, handler->msg_size)) + { + return KOSA_StatusSuccess; + } + else + { + return KOSA_StatusError; + } +} + +/*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(msgqHandle); + rt_mq_t handler = (rt_mq_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + int32_t timeoutTicks; + + if (millisec == osaWaitForever_c) + { + timeoutTicks = RT_WAITING_FOREVER; + } + else + { + timeoutTicks = rt_tick_from_millisecond(millisec); + } + if (RT_EOK != rt_mq_recv(handler, pMessage, handler->msg_size, timeoutTicks)) + { + osaStatus = KOSA_StatusTimeout; /* not able to send it to the queue? */ + } + else + { + osaStatus = KOSA_StatusSuccess; + } + return osaStatus; +} + +/*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(msgqHandle); + rt_mq_t handler = (rt_mq_t)(void *)(uint32_t *)(*(uint32_t *)msgqHandle); + + rt_mq_delete(handler); + return KOSA_StatusSuccess; +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptEnable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptEnable(void) +{ + rt_exit_critical(); +} + +/*FUNCTION********************************************************************** + * + * Function Name : OSA_InterruptDisable + * Description : self explanatory. + * + *END**************************************************************************/ +void OSA_InterruptDisable(void) +{ + rt_enter_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)) + +static OSA_TASK_DEFINE(startup_task, gMainThreadPriority_c, 1, gMainThreadStackSize_c, 0); + +int main(void) +{ + extern void BOARD_InitHardware(void); + /* Initialize MCU clock */ + BOARD_InitHardware(); + LIST_Init((&s_osaState.taskList), 0); + + s_osaState.basePriorityNesting = 0; + s_osaState.interruptDisableCount = 0; + (void)OSA_TaskCreate((osa_task_handle_t)s_osaState.mainTaskHandle, OSA_TASK(startup_task), NULL); + + vTaskStartScheduler(); + return 0; +} +#endif /* FSL_OSA_TASK_ENABLE */ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.h new file mode 100644 index 0000000000..40bd24271a --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/fsl_os_abstraction_rtthread.h @@ -0,0 +1,130 @@ +/*! ********************************************************************************* + * 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_RTTHREAD_H__) +#define __FSL_OS_ABSTRACTION_RTTHREAD_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 +MISRAC_ENABLE + +/*! + * @addtogroup os_abstraction_free_rtos + * @{ + */ + +/******************************************************************************* + * Declarations + ******************************************************************************/ +/*! @brief Type for a task handler, returned by the OSA_TaskCreate function. */ +typedef rt_thread_t task_handler_t; + +/*! @brief Type for a task stack.*/ +typedef rt_uint32_t task_stack_t; + +/*! @brief Type for task parameter */ +typedef void *task_param_t; + +/*! @brief Type for an event flags object.*/ +typedef rt_uint32_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_RTTHREAD_H__ diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.c b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.c new file mode 100644 index 0000000000..80dd21425d --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.c @@ -0,0 +1,475 @@ +/* + * Copyright 2018-2019 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/*! ********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ +#include "generic_list.h" + +static list_status_t LIST_Error_Check(list_handle_t list, list_element_handle_t newElement) +{ + list_status_t listStatus = kLIST_Ok; + list_element_handle_t element = list->head; + + if ((list->max != 0U) && (list->max == list->size)) + { + listStatus = kLIST_Full; /*List is full*/ + } + else + { + while (element != NULL) /*Scan list*/ + { + /* Determine if element is duplicated */ + if (element == newElement) + { + listStatus = kLIST_DuplicateError; + break; + } + element = element->next; + } + } + + return listStatus; +} + +/*! ********************************************************************************* +************************************************************************************* +* Public functions +************************************************************************************* +********************************************************************************** */ +/*! ********************************************************************************* + * \brief Initialises 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 = (uint16_t)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) +{ + uint32_t regPrimask = DisableGlobalIRQ(); + 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++; + } + + EnableGlobalIRQ(regPrimask); + 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) +{ + uint32_t regPrimask = DisableGlobalIRQ(); + 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++; + } + + EnableGlobalIRQ(regPrimask); + 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; + + uint32_t regPrimask = DisableGlobalIRQ(); + + 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*/ + } + + EnableGlobalIRQ(regPrimask); + 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; + uint32_t regPrimask = DisableGlobalIRQ(); + + 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 (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; + } + + EnableGlobalIRQ(regPrimask); + 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; + uint32_t regPrimask = DisableGlobalIRQ(); + + 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 (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 + } + } + + EnableGlobalIRQ(regPrimask); + 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 ((uint32_t)list->max - (uint32_t)list->size); /*Gets the number of free places in the list*/ +} diff --git a/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.h b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.h new file mode 100644 index 0000000000..def00efe8e --- /dev/null +++ b/bsp/imxrt/libraries/MIMXRT1170/MIMXRT1176/drivers/generic_list.h @@ -0,0 +1,203 @@ +/* + * Copyright 2018-2020 NXP + * All rights reserved. + * + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef _GENERIC_LIST_H_ +#define _GENERIC_LIST_H_ + +#include "fsl_common.h" +/*! + * @addtogroup GenericList + * @{ + */ + +/*!********************************************************************************* +************************************************************************************* +* Include +************************************************************************************* +********************************************************************************** */ + +/*! ********************************************************************************* +************************************************************************************* +* Public macro definitions +************************************************************************************* +********************************************************************************** */ +#ifndef GENERIC_LIST_LIGHT +#define GENERIC_LIST_LIGHT (0) +#endif +/*! ********************************************************************************* +************************************************************************************* +* Public type definitions +************************************************************************************* +********************************************************************************** */ +/*! @brief The list status */ +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; + +/*! @brief The list structure*/ +typedef struct list_label +{ + struct list_element_tag *head; /*!< list head */ + struct list_element_tag *tail; /*!< list tail */ + uint16_t size; /*!< list size */ + uint16_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 list - Handle of the 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/bsp/imxrt/libraries/MIMXRT1170/SConscript b/bsp/imxrt/libraries/MIMXRT1170/SConscript index 967053fce5..dabc973a4e 100644 --- a/bsp/imxrt/libraries/MIMXRT1170/SConscript +++ b/bsp/imxrt/libraries/MIMXRT1170/SConscript @@ -51,6 +51,10 @@ if GetDepend(['RT_USING_CAN']): if GetDepend(['BSP_USING_FLEXSPI']): src += ['MIMXRT1176/drivers/fsl_flexspi.c'] + +#fsl os abstract files +src += ['MIMXRT1176/drivers/fsl_os_abstraction_rtthread.c'] +src += ['MIMXRT1176/drivers/generic_list.c'] if rtconfig.PLATFORM in ['gcc']: group = DefineGroup('Libraries', src, depend = [''], CPPPATH = path, ASFLAGS = '$ASFLAGS -D __STARTUP_CLEAR_BSS') diff --git a/bsp/imxrt/libraries/drivers/drv_usbh.c b/bsp/imxrt/libraries/drivers/drv_usbh.c index 69f076c18f..73e16ae9ae 100644 --- a/bsp/imxrt/libraries/drivers/drv_usbh.c +++ b/bsp/imxrt/libraries/drivers/drv_usbh.c @@ -24,8 +24,12 @@ /* USB PHY configuration */ #ifndef BOARD_USB_PHY_D_CAL +#ifdef SOC_IMXRT1170_SERIES +#define BOARD_USB_PHY_D_CAL (0x07U) +#else #define BOARD_USB_PHY_D_CAL (0x0CU) #endif +#endif #ifndef BOARD_USB_PHY_TXCAL45DP #define BOARD_USB_PHY_TXCAL45DP (0x06U) #endif @@ -33,7 +37,12 @@ #define BOARD_USB_PHY_TXCAL45DM (0x06U) #endif -#define USB_HOST_INTERRUPT_PRIORITY 3 +#define USB_HOST_INTERRUPT_PRIORITY 6 + +/* Allocate the memory for the heap. */ +#if defined(configAPPLICATION_ALLOCATED_HEAP) && (configAPPLICATION_ALLOCATED_HEAP) +USB_DMA_NONINIT_DATA_ALIGN(USB_DATA_ALIGN_SIZE) uint8_t ucHeap[configTOTAL_HEAP_SIZE]; +#endif enum { @@ -91,20 +100,22 @@ static void _imxrt_usb_host_send_callback(void *param, usb_host_transfer_t *tran */ static void USB_HostClockInit(usb_controller_index_t controller_id) { + uint32_t usbClockFreq; usb_phy_config_struct_t phyConfig = { BOARD_USB_PHY_D_CAL, BOARD_USB_PHY_TXCAL45DP, BOARD_USB_PHY_TXCAL45DM, }; - uint32_t notUsed = 0; + + usbClockFreq = 24000000; if (controller_id == kUSB_ControllerEhci0) { - CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, 480000000U); - CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, 480000000U); + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usbphy480M, usbClockFreq); + CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, usbClockFreq); } else { - CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, 480000000U); - CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, 480000000U); + CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usbphy480M, usbClockFreq); + CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, usbClockFreq); } USB_EhciPhyInit(controller_id, 24000000U, &phyConfig); @@ -151,7 +162,7 @@ static uint8_t _ehci0_pipe_idx; static int _ehci0_pipe_xfer(upipe_t pipe, rt_uint8_t token, void *buffer, int nbytes, int timeouts) { - int timeout = timeouts; +// int timeout = timeouts; if (!imxrt_usb_host_obj[USBH0_INDEX].connect_status) { diff --git a/bsp/imxrt/libraries/drivers/usb/host/usb_host.h b/bsp/imxrt/libraries/drivers/usb/host/usb_host.h index 6d9167ceac..8f83396ad1 100644 --- a/bsp/imxrt/libraries/drivers/usb/host/usb_host.h +++ b/bsp/imxrt/libraries/drivers/usb/host/usb_host.h @@ -105,8 +105,13 @@ typedef struct _usb_host_process_descriptor_param uint8_t descriptorIndex; /*!< The descriptor index is used to select a specific descriptor (only for configuration and string descriptors) when several descriptors of the same type are implemented in a device */ +#ifdef SOC_IMXRT1170_SERIES + uint16_t languageId; /*!< It specifies the language ID for string descriptors or is reset to zero for other + descriptors */ +#else uint8_t languageId; /*!< It specifies the language ID for string descriptors or is reset to zero for other descriptors */ +#endif uint8_t *descriptorBuffer; /*!< Buffer pointer */ uint16_t descriptorLength; /*!< Buffer data length */ } usb_host_process_descriptor_param_t; diff --git a/bsp/imxrt/libraries/drivers/usb/host/usb_host_devices.c b/bsp/imxrt/libraries/drivers/usb/host/usb_host_devices.c index 2bbc89233a..2798434f6e 100644 --- a/bsp/imxrt/libraries/drivers/usb/host/usb_host_devices.c +++ b/bsp/imxrt/libraries/drivers/usb/host/usb_host_devices.c @@ -182,7 +182,1333 @@ static const usb_host_enum_process_entry_t s_EnumEntries[] = { /******************************************************************************* * Code ******************************************************************************/ +#ifdef SOC_IMXRT1170_SERIES +static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) +{ + /* 0 - retry current transfer, 1 - transfer success process, + * 2 - retry whole process, 3 - fail process + */ + uint8_t nextStep = 0U; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)param; + usb_status_t failReason = kStatus_USB_Success; + uint32_t dataLength; + dataLength = transfer->transferSofar; + (void)USB_HostFreeTransfer(deviceInstance->hostHandle, transfer); /* free transfer */ + + if (status == kStatus_USB_Success) + { + nextStep = 1U; + } + else if (status == kStatus_USB_TransferStall) + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + (void)usb_echo("no response from device\r\n"); +#endif /* USB_HOST_CONFIG_COMPLIANCE_TEST */ + if (deviceInstance->stallRetries > 0U) /* retry same transfer when stall */ + { + nextStep = 0U; + deviceInstance->stallRetries--; + } + else + { + failReason = kStatus_USB_TransferFailed; + nextStep = 2U; + } + } + else if (status == kStatus_USB_TransferCancel) + { + failReason = kStatus_USB_TransferCancel; + nextStep = 3U; + } + else + { + failReason = kStatus_USB_TransferFailed; + nextStep = 2U; + } + + if (nextStep == 1U) + { + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + if (s_EnumEntries[deviceInstance->state - 1U].process == NULL) + { + deviceInstance->state = (uint8_t)s_EnumEntries[deviceInstance->state - 1U].successState; /* next state */ + } + else + { + status = s_EnumEntries[deviceInstance->state - 1U].process( + deviceInstance, dataLength); /* process the previous state result */ + if (status == kStatus_USB_Success) /* process success */ + { + deviceInstance->state = (uint8_t)s_EnumEntries[deviceInstance->state - 1U].successState; + } + else if (status == kStatus_USB_Retry) /* need retry */ + { + deviceInstance->state = (uint8_t)s_EnumEntries[deviceInstance->state - 1U].retryState; + } + else if (status == kStatus_USB_NotSupported) /* device don't suport by the application */ + { + return; /* unrecoverable fail */ + } + else /* process error, next retry */ + { + /* kStatus_USB_Error or kStatus_USB_AllocFail */ + failReason = status; + nextStep = 2U; + } + } + } + + if (nextStep == 2U) + { + if (deviceInstance->enumRetries > 0U) /* next whole retry */ + { + deviceInstance->enumRetries--; + deviceInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + deviceInstance->configurationValue = 0U; + deviceInstance->state = (uint8_t)kStatus_DEV_GetDes8; + } + else + { +#if ((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Device No Response\r\n"); +#endif + nextStep = 3U; + } + } + + /* process the state */ + if (nextStep != 3U) + { + if (USB_HostProcessState(deviceInstance) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("enumation setup error\r\n"); +#endif + failReason = kStatus_USB_Error; + nextStep = 3U; + } + } + + if (nextStep == 3U) + { + (void)USB_HostNotifyDevice(deviceInstance->hostHandle, deviceInstance, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)failReason); + } +} + +static usb_status_t USB_HostProcessState(usb_host_device_instance_t *deviceInstance) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_process_descriptor_param_t getDescriptorParam; + usb_host_transfer_t *transfer; + usb_host_device_enumeration_status_t state; + + /* malloc transfer */ + state = (usb_host_device_enumeration_status_t)deviceInstance->state; + if (state != kStatus_DEV_EnumDone) + { + if (USB_HostMallocTransfer(deviceInstance->hostHandle, &transfer) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error to get transfer\r\n"); +#endif + return kStatus_USB_Error; + } + transfer->callbackFn = USB_HostEnumerationTransferCallback; + transfer->callbackParam = deviceInstance; + + /* reset transfer fields */ + transfer->setupPacket->bmRequestType = 0x00U; + transfer->setupPacket->wIndex = 0U; + transfer->setupPacket->wLength = 0U; + transfer->setupPacket->wValue = 0U; + } + + switch (state) + { + case kStatus_DEV_GetDes8: + case kStatus_DEV_GetDes: /* get descriptor state */ + getDescriptorParam.descriptorLength = (uint16_t)sizeof(usb_descriptor_device_t); + if (deviceInstance->state == (uint8_t)kStatus_DEV_GetDes8) + { + getDescriptorParam.descriptorLength = 8U; + } + getDescriptorParam.descriptorBuffer = (uint8_t *)deviceInstance->deviceDescriptor; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_DEVICE; + getDescriptorParam.descriptorIndex = 0U; + getDescriptorParam.languageId = 0U; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + case kStatus_DEV_SetAddress: /* set address state */ + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_ADDRESS; + status = USB_HostStandardSetAddress(deviceInstance, transfer, &deviceInstance->allocatedAddress); + break; + + case kStatus_DEV_GetCfg9: /* get 9 bytes configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->enumBuffer; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = 9; + getDescriptorParam.languageId = 0; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_GetCfg: /* get configuration state */ + getDescriptorParam.descriptorBuffer = deviceInstance->configurationDesc; + getDescriptorParam.descriptorType = USB_DESCRIPTOR_TYPE_CONFIGURE; + getDescriptorParam.descriptorIndex = deviceInstance->configurationValue; + getDescriptorParam.descriptorLength = deviceInstance->configurationLen; + getDescriptorParam.languageId = 0; + + transfer->setupPacket->bmRequestType |= USB_REQUEST_TYPE_DIR_IN; + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_GET_DESCRIPTOR; + status = USB_HostStandardSetGetDescriptor(deviceInstance, transfer, &getDescriptorParam); + break; + + case kStatus_DEV_SetCfg: /* set configuration state */ + transfer->setupPacket->wValue = + USB_SHORT_TO_LITTLE_ENDIAN(deviceInstance->configuration.configurationDesc->bConfigurationValue); + transfer->setupPacket->bRequest = USB_REQUEST_STANDARD_SET_CONFIGURATION; + status = USB_HostCh9RequestCommon(deviceInstance, transfer, NULL, 0); + break; + + case kStatus_DEV_EnumDone: /* enumeration done state */ + /* notify device enumeration done */ + status = USB_HostNotifyDevice(deviceInstance->hostHandle, deviceInstance, + (uint32_t)kUSB_HostEventEnumerationDone, (uint32_t)kStatus_USB_Success); + if (status == kStatus_USB_Success) + { + deviceInstance->state = (uint8_t)kStatus_DEV_AppUsed; + } + break; + + default: + /*no action*/ + break; + } + + return status; +} + +static usb_status_t USB_HostProcessCallback(usb_host_device_instance_t *deviceInstance, uint32_t dataLength) +{ + usb_host_pipe_t *pipe = (usb_host_pipe_t *)deviceInstance->controlPipe; + usb_status_t status = kStatus_USB_Success; + usb_descriptor_configuration_t *configureDesc; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + void *temp; + usb_host_device_enumeration_status_t state; +#if (defined(USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +#if (defined(USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_host_hub_instance_t *hubInstance4Device = NULL; +#endif +#endif + + state = (usb_host_device_enumeration_status_t)deviceInstance->state; + switch (state) + { + case kStatus_DEV_GetDes8: /* process get 8 bytes descriptor result */ + if (dataLength != 8u) + { + return kStatus_USB_Error; + } + pipe->maxPacketSize = deviceInstance->deviceDescriptor->bMaxPacketSize0; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + (void)hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlPacketSize, deviceInstance->controlPipe); + break; + + case kStatus_DEV_SetAddress: /* process set address result */ + deviceInstance->setAddress = deviceInstance->allocatedAddress; + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + (void)hostInstance->controllerTable->controllerIoctl( + hostInstance->controllerHandle, kUSB_HostUpdateControlEndpointAddress, deviceInstance->controlPipe); + break; + + case kStatus_DEV_GetDes: /* process get full device descriptor result */ + if (dataLength != sizeof(usb_descriptor_device_t)) + { + return kStatus_USB_Error; + } + break; + + case kStatus_DEV_GetCfg9: /* process get 9 bytes configuration result */ + if (dataLength != 9u) + { + return kStatus_USB_Error; + } + temp = (void *)&deviceInstance->enumBuffer[0]; + configureDesc = (usb_descriptor_configuration_t *)temp; + + deviceInstance->configurationLen = USB_SHORT_FROM_LITTLE_ENDIAN_ADDRESS(configureDesc->wTotalLength); + if (deviceInstance->configurationDesc != NULL) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->configurationDesc); +#else + OSA_MemoryFree(deviceInstance->configurationDesc); +#endif + deviceInstance->configurationDesc = NULL; + } + + /* the only configuration descriptor is at least 9 bytes length */ + if (deviceInstance->configurationLen < 9U) + { + return kStatus_USB_Error; + } + /* fix misra 4.14 */ + if (deviceInstance->configurationLen > USB_HOST_CONFIG_MAX_CONFIGURATION_DESCRIPTOR_LENGTH) + { + return kStatus_USB_Error; + } + /* for KHCI, the start address and the length should be 4 byte align */ + if ((deviceInstance->configurationLen & 0x03U) != 0U) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + deviceInstance->configurationDesc = + (uint8_t *)SDK_Malloc((deviceInstance->configurationLen & 0xFFFCu) + 4, USB_CACHE_LINESIZE); +#else + deviceInstance->configurationDesc = + (uint8_t *)OSA_MemoryAllocate((((uint32_t)deviceInstance->configurationLen) & 0xFFFCU) + 4UL); +#endif + } + else + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + deviceInstance->configurationDesc = + (uint8_t *)SDK_Malloc(deviceInstance->configurationLen, USB_CACHE_LINESIZE); +#else + deviceInstance->configurationDesc = (uint8_t *)OSA_MemoryAllocate(deviceInstance->configurationLen); +#endif + } + if (deviceInstance->configurationDesc == NULL) + { + return kStatus_USB_AllocFail; + } + break; + + case kStatus_DEV_GetCfg: /* process get configuration result */ + if (dataLength != deviceInstance->configurationLen) + { +#if (defined(USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) + usb_echo("Host can only provide a maximum of 500mA current\r\n"); +#endif + return kStatus_USB_Error; + } + +#if (defined(USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) +#if (defined(USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + hubInstance4Device = USB_HostHubGetHubDeviceHandle(hostInstance, deviceInstance->hubNumber); + if ((!(((usb_descriptor_configuration_t *)deviceInstance->configurationDesc)->bmAttributes & + USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_MASK)) && + (((usb_descriptor_configuration_t *)deviceInstance->configurationDesc)->bMaxPower > 50) && + (hubInstance4Device != NULL) && + (!(((usb_descriptor_configuration_t *)((usb_host_device_instance_t *)hubInstance4Device->deviceHandle) + ->configurationDesc) + ->bmAttributes & + USB_DESCRIPTOR_CONFIGURE_ATTRIBUTE_SELF_POWERED_MASK))) + { + usb_echo("The device power exceeded\r\n"); + return kStatus_USB_Error; + } +#endif +#endif + temp = (void *)deviceInstance->configurationDesc; + if (((usb_descriptor_configuration_t *)temp)->bMaxPower > USB_HOST_CONFIG_MAX_POWER) + { + return kStatus_USB_Error; + } + deviceInstance->configurationValue++; + if (USB_HostParseDeviceConfigurationDescriptor(deviceInstance) != + kStatus_USB_Success) /* parse configuration descriptor */ + { + return kStatus_USB_Error; + } + + status = USB_HostNotifyDevice(deviceInstance->hostHandle, deviceInstance, (uint32_t)kUSB_HostEventAttach, + (uint32_t)kStatus_USB_Success); + + if (status != kStatus_USB_Success) + { + /* next configuration */ + if (deviceInstance->configurationValue < deviceInstance->deviceDescriptor->bNumConfigurations) + { + return kStatus_USB_Retry; + } + else + { + /* notify application device is not supported */ + (void)USB_HostNotifyDevice(deviceInstance->hostHandle, deviceInstance, + (uint32_t)kUSB_HostEventNotSupported, (uint32_t)kStatus_USB_Success); + return kStatus_USB_NotSupported; + } + } + break; + + case kStatus_DEV_SetCfg: + /* NULL */ + break; + + default: + /*no action*/ + break; + } + + return status; +} + +static usb_status_t USB_HostNotifyDevice(usb_host_handle hostHandle, + usb_host_device_instance_t *deviceInstance, + uint32_t eventCode, + uint32_t eventParameter) +{ + usb_host_instance_t *hostInstance; + usb_status_t status1 = kStatus_USB_Error; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_status_t status2 = kStatus_USB_Error; + uint8_t haveHub; + uint8_t haveNoHub; + uint8_t interfaceIndex; +#endif /* USB_HOST_CONFIG_HUB */ + + eventCode = (((uint32_t)eventParameter << 16U) | (uint32_t)eventCode); + hostInstance = (usb_host_instance_t *)hostHandle; + if (deviceInstance == NULL) + { + (void)hostInstance->deviceCallback(NULL, NULL, eventCode); + return kStatus_USB_InvalidHandle; + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + haveHub = 0U; + haveNoHub = 0U; + for (interfaceIndex = 0U; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (((usb_descriptor_interface_t *)deviceInstance->configuration.interfaceList[interfaceIndex].interfaceDesc) + ->bInterfaceClass == USB_HOST_HUB_CLASS_CODE) + { + haveHub = 1U; + } + else + { + haveNoHub = 1U; + } + } + + if ((hostInstance->deviceCallback != NULL) && + ((haveNoHub == 1U) || (deviceInstance->configuration.interfaceCount == 0U))) + { + /* call host callback function, function is initialized in USB_HostInit */ + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, eventCode); + } + if (0U != haveHub) + { + status2 = USB_HostHubDeviceEvent(hostInstance, deviceInstance, &deviceInstance->configuration, + eventCode); /* notify hub event */ + } + + if ((status1 == kStatus_USB_Success) || (status2 == kStatus_USB_Success)) /* the device is supported */ + { + return kStatus_USB_Success; + } + else if (eventCode == (uint32_t)kUSB_HostEventAttach) /* attach event */ + { + status1 = kStatus_USB_NotSupported; + } + else + { + status1 = kStatus_USB_Error; + } +#else + if (hostInstance->deviceCallback != NULL) + { + /* call host callback function, function is initialized in USB_HostInit */ + status1 = hostInstance->deviceCallback(deviceInstance, &deviceInstance->configuration, eventCode); + } +#endif + return status1; +} + +static uint8_t USB_HostAllocateDeviceAddress(usb_host_instance_t *hostInstance) +{ + uint8_t address = 0U; + uint8_t addressIndex; + uint8_t addressBitIndex; + for (addressIndex = 0U; addressIndex < 8U; ++addressIndex) /* find the idle address position byte */ + { + if (hostInstance->addressBitMap[addressIndex] != 0xFFU) + { + break; + } + } + if (addressIndex < 8U) + { + for (addressBitIndex = 0U; addressBitIndex < 8U; ++addressBitIndex) /* find the idle address position bit */ + { + if (0U == (hostInstance->addressBitMap[addressIndex] & (0x01U << addressBitIndex))) + { + hostInstance->addressBitMap[addressIndex] |= (0x01U << addressBitIndex); /* set the allocated bit */ + address = addressIndex * 8U + addressBitIndex + 1U; /* the address minimum is 1 */ + break; + } + } + } + return address; +} + +static void USB_HostReleaseDeviceAddress(usb_host_instance_t *hostInstance, uint8_t address) +{ + (void)USB_HostLock(); + hostInstance->addressBitMap[((uint32_t)address - 1U) >> 3U] &= + (~(0x01U << (((uint32_t)address - 1U) & 0x07U))); /* reset the allocated bit */ + (void)USB_HostUnlock(); +} + +static usb_status_t USB_HostRemoveDeviceInstance(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *currentInstance; + usb_host_device_instance_t *prevInstance; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + /* search and remove device instance */ + prevInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + if (prevInstance == deviceHandle) + { + hostInstance->deviceList = prevInstance->next; + return kStatus_USB_Success; + } + else + { + currentInstance = prevInstance->next; + } + + while (currentInstance != NULL) + { + if (currentInstance == deviceHandle) + { + prevInstance->next = currentInstance->next; + return kStatus_USB_Success; + } + prevInstance = currentInstance; + currentInstance = currentInstance->next; + } + + return kStatus_USB_Success; +} + +static void USB_HostReleaseDeviceResource(usb_host_instance_t *hostInstance, usb_host_device_instance_t *deviceInstance) +{ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; +#endif + +#if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) + if (deviceInstance == hostInstance->suspendedDevice) + { + hostInstance->suspendedDevice = NULL; + } +#endif + /* release device's address */ + if (deviceInstance->setAddress != 0U) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->setAddress); + } + else + { + if (deviceInstance->allocatedAddress != 0U) + { + USB_HostReleaseDeviceAddress(hostInstance, deviceInstance->allocatedAddress); + } + } + + /* close control pipe */ + if (deviceInstance->controlPipe != NULL) + { + (void)USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + if (USB_HostClosePipe(hostInstance, deviceInstance->controlPipe) != kStatus_USB_Success) + { +#ifdef HOST_ECHO + usb_echo("error when close pipe\r\n"); +#endif + } + deviceInstance->controlPipe = NULL; + } + + /* free configuration buffer */ + if (deviceInstance->configurationDesc != NULL) + { +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->configurationDesc); +#else + OSA_MemoryFree(deviceInstance->configurationDesc); +#endif + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + level = deviceInstance->level; +#endif +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(deviceInstance->deviceDescriptor); +#else + OSA_MemoryFree(deviceInstance->deviceDescriptor); +#endif + /* free device instance buffer */ + OSA_MemoryFree(deviceInstance); + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + /* enable controller attach if root hub */ + if (level == 1U) + { + (void)USB_HostControlBus(hostInstance, (uint8_t)kUSB_HostBusEnableAttach); + } +#else + /* enable controller attach */ + USB_HostControlBus(hostInstance, (uint8_t)kUSB_HostBusEnableAttach); +#endif +} + +static usb_status_t USB_HostParseDeviceConfigurationDescriptor(usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint32_t endPos; + usb_descriptor_union_t *unionDes; + usb_host_interface_t *interfaceParse = NULL; + usb_host_ep_t *epParse; + uint8_t *buffer; + void *temp; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + + temp = (void *)&deviceInstance->configuration; + buffer = (uint8_t *)temp; + /* clear the previous parse result, note: end_pos means buffer index here*/ + for (endPos = 0U; endPos < sizeof(usb_host_configuration_t); endPos++) + { + buffer[endPos] = 0U; + } + for (endPos = 0U; endPos < USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = 0U; + } + + /* parse configuration descriptor */ + temp = (void *)deviceInstance->configurationDesc; + unionDes = (usb_descriptor_union_t *)temp; + endPos = (uint32_t)(deviceInstance->configurationDesc + deviceInstance->configurationLen); + + if (((((uint32_t)unionDes) + 1U) < endPos) && (unionDes->common.bLength == USB_DESCRIPTOR_LENGTH_CONFIGURE) && + (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_CONFIGURE)) + { + /* configuration descriptor */ + temp = (void *)unionDes; + deviceInstance->configuration.configurationDesc = (usb_descriptor_configuration_t *)temp; + deviceInstance->configuration.configurationExtensionLength = 0; + deviceInstance->configuration.configurationExtension = NULL; + deviceInstance->configuration.interfaceCount = 0; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (((((uint32_t)unionDes) + 1U) < endPos) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if (deviceInstance->configuration.configurationExtension == NULL) + { + deviceInstance->configuration.configurationExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00U) || + (unionDes->common.bLength == 0x00U)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + deviceInstance->configuration.configurationExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* interface descriptor */ + deviceInstance->configuration.interfaceCount = 0U; + while ((uint32_t)unionDes < endPos) + { + if (((((uint32_t)unionDes) + 1U) < endPos) && + (unionDes->common.bDescriptorType == USB_DESCRIPTOR_TYPE_INTERFACE)) + { + /* the interface descriptor length is 9 bytes */ + if ((((uint32_t)unionDes) + 9U) > endPos) + { + return kStatus_USB_Error; + } + if (unionDes->interface.bAlternateSetting == 0x00U) + { + if (deviceInstance->configuration.interfaceCount >= USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE) + { +#if (((defined USB_HOST_CONFIG_COMPLIANCE_TEST) && (USB_HOST_CONFIG_COMPLIANCE_TEST)) || defined(HOST_ECHO)) + (void)usb_echo( + "Unsupported Device attached\r\n too many interfaces in one configuration, please increase " + "the USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE value\n"); +#endif + return kStatus_USB_Error; + } + interfaceParse = + &deviceInstance->configuration.interfaceList[deviceInstance->configuration.interfaceCount]; + deviceInstance->configuration.interfaceCount++; + interfaceParse->alternateSettingNumber = 0; + interfaceParse->epCount = 0; + interfaceParse->interfaceDesc = &unionDes->interface; + interfaceParse->interfaceExtensionLength = 0; + interfaceParse->interfaceExtension = NULL; + interfaceParse->interfaceIndex = unionDes->interface.bInterfaceNumber; + if (unionDes->common.bLength == 0x00U) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (((((uint32_t)unionDes) + 1U) < endPos) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { + if (interfaceParse->interfaceExtension == NULL) + { + interfaceParse->interfaceExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00U) || + (unionDes->common.bLength == 0x00U)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + + /* endpoint descriptor */ + if (interfaceParse->interfaceDesc->bNumEndpoints != 0U) + { + if (((((uint32_t)unionDes) + 1U) >= endPos) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) || + (interfaceParse->interfaceDesc->bNumEndpoints > USB_HOST_CONFIG_INTERFACE_MAX_EP)) + { +#ifdef HOST_ECHO + usb_echo("interface descriptor error\n"); +#endif + return kStatus_USB_Error; + } + for (; interfaceParse->epCount < interfaceParse->interfaceDesc->bNumEndpoints; + (interfaceParse->epCount)++) + { + if (((((uint32_t)unionDes) + 1U) >= endPos) || + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT)) + { +#ifdef HOST_ECHO + usb_echo("endpoint descriptor error\n"); +#endif + return kStatus_USB_Error; + } + temp = (void *)&interfaceParse->epList[interfaceParse->epCount]; + epParse = (usb_host_ep_t *)temp; + temp = (void *)unionDes; + epParse->epDesc = (usb_descriptor_endpoint_t *)temp; + epParse->epExtensionLength = 0U; + epParse->epExtension = NULL; + if (unionDes->common.bLength == 0x00U) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (((((uint32_t)unionDes) + 1U) < endPos) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_ENDPOINT) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if (epParse->epExtension == NULL) + { + epParse->epExtension = (uint8_t *)unionDes; + } + if ((unionDes->common.bDescriptorType == 0x00U) || + (unionDes->common.bLength == 0x00U)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + epParse->epExtensionLength += unionDes->common.bLength; + unionDes = + (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + } + else + { + if (interfaceParse == NULL) + { + return kStatus_USB_Error; /* in normal situation this cannot reach */ + } + interfaceParse->alternateSettingNumber++; + if (interfaceParse->interfaceExtension == NULL) + { + interfaceParse->interfaceExtension = (uint8_t *)unionDes; + } + if (unionDes->common.bLength == 0x00U) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + while ((uint32_t)unionDes < endPos) + { + if (((((uint32_t)unionDes) + 1U) < endPos) && + (unionDes->common.bDescriptorType != USB_DESCRIPTOR_TYPE_INTERFACE)) + { + if ((unionDes->common.bDescriptorType == 0x00U) || + (unionDes->common.bLength == 0x00U)) /* the descriptor data is wrong */ + { + return kStatus_USB_Error; + } + interfaceParse->interfaceExtensionLength += unionDes->common.bLength; + unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); + } + else + { + break; + } + } + } + } + else + { + return kStatus_USB_Error; + } + } + } + else + { + return kStatus_USB_Error; + } + + for (endPos = 0U; endPos < deviceInstance->configuration.interfaceCount; ++endPos) + { + deviceInstance->interfaceStatus[endPos] = (uint8_t)kStatus_interface_Attached; + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostAttachDevice(usb_host_handle hostHandle, + uint8_t speed, + uint8_t hubNumber, + uint8_t portNumber, + uint8_t level, + usb_device_handle *deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *newInstance; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + usb_host_device_instance_t *currentInstance; +#endif + uint8_t address; + usb_host_pipe_init_t pipeInit; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + +/* check whether is the device attached? */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + currentInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (currentInstance != NULL) + { + if ((currentInstance->hubNumber == hubNumber) && (currentInstance->portNumber == portNumber)) + { + *deviceHandle = NULL; +#ifdef HOST_ECHO + usb_echo("device has attached\r\n"); +#endif + return kStatus_USB_Busy; + } + else + { + currentInstance = currentInstance->next; + } + } +#else + if (hostInstance->deviceList != NULL) + { + *deviceHandle = NULL; + usb_echo("device has attached\r\n"); + return kStatus_USB_Busy; + } +#endif + + /* Allocate new device instance */ + newInstance = (usb_host_device_instance_t *)OSA_MemoryAllocate(sizeof(usb_host_device_instance_t)); + if (newInstance == NULL) + { +#ifdef HOST_ECHO + usb_echo("allocate dev instance fail\r\n"); +#endif + (void)USB_HostNotifyDevice(hostInstance, NULL, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)kStatus_USB_AllocFail); + return kStatus_USB_AllocFail; + } + + /* new instance fields init */ + newInstance->hostHandle = hostHandle; + newInstance->speed = speed; + newInstance->stallRetries = USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES; + newInstance->enumRetries = USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES; + newInstance->setAddress = 0; + newInstance->deviceAttachState = (uint8_t)kStatus_device_Attached; +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + newInstance->deviceDescriptor = + (usb_descriptor_device_t *)SDK_Malloc(sizeof(usb_descriptor_device_t) + 9, USB_CACHE_LINESIZE); +#else + newInstance->deviceDescriptor = (usb_descriptor_device_t *)OSA_MemoryAllocate(sizeof(usb_descriptor_device_t) + 9U); +#endif + if (newInstance->deviceDescriptor == NULL) + { +#ifdef HOST_ECHO + usb_echo("allocate newInstance->deviceDescriptor fail\r\n"); +#endif +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + OSA_MemoryFree(newInstance->deviceDescriptor); +#endif + OSA_MemoryFree(newInstance); + (void)USB_HostNotifyDevice(hostInstance, NULL, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)kStatus_USB_AllocFail); + return kStatus_USB_AllocFail; + } + newInstance->enumBuffer = (uint8_t *)((uint8_t *)newInstance->deviceDescriptor + sizeof(usb_descriptor_device_t)); +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + newInstance->hubNumber = hubNumber; + newInstance->portNumber = portNumber; + newInstance->level = level; + + if ((speed != USB_SPEED_HIGH) && (level > 1U)) + { + newInstance->hsHubNumber = (uint8_t)USB_HostHubGetHsHubNumber(hostHandle, hubNumber); + newInstance->hsHubPort = (uint8_t)USB_HostHubGetHsHubPort(hostHandle, hubNumber, portNumber); + } + else + { + newInstance->hsHubNumber = hubNumber; + newInstance->hsHubPort = portNumber; + } +#endif /* USB_HOST_CONFIG_HUB */ + + (void)USB_HostLock(); + /* allocate address && insert to the dev list */ + address = USB_HostAllocateDeviceAddress(hostInstance); + if (address == 0U) + { +#ifdef HOST_ECHO + usb_echo("allocate address fail\r\n"); +#endif + (void)USB_HostUnlock(); +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + OSA_MemoryFree(newInstance->deviceDescriptor); +#endif + OSA_MemoryFree(newInstance); + (void)USB_HostNotifyDevice(hostInstance, NULL, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)kStatus_USB_Error); + return kStatus_USB_Error; + } + newInstance->allocatedAddress = address; + + newInstance->next = (usb_host_device_instance_t *)hostInstance->deviceList; + hostInstance->deviceList = newInstance; + newInstance->state = (uint8_t)kStatus_DEV_Initial; + (void)USB_HostUnlock(); + + /* open control pipe */ + pipeInit.devInstance = newInstance; + pipeInit.pipeType = USB_ENDPOINT_CONTROL; + pipeInit.direction = 0; + pipeInit.endpointAddress = 0; + pipeInit.interval = 0; + pipeInit.maxPacketSize = 8; + pipeInit.numberPerUframe = 0; + pipeInit.nakCount = USB_HOST_CONFIG_MAX_NAK; + if (USB_HostOpenPipe(hostHandle, &newInstance->controlPipe, &pipeInit) != kStatus_USB_Success) + { + /* don't need release resource, resource is released when detach */ + *deviceHandle = newInstance; +#if ((defined(USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE)) && (USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE > 0U)) + SDK_Free(newInstance->deviceDescriptor); +#else + OSA_MemoryFree(newInstance->deviceDescriptor); +#endif + OSA_MemoryFree(newInstance); + (void)USB_HostNotifyDevice(hostInstance, NULL, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)kStatus_USB_Error); + return kStatus_USB_Error; + } + + /* start enumeration */ + newInstance->state = (uint8_t)kStatus_DEV_GetDes8; + /* process enumeration state machine */ + if (USB_HostProcessState(newInstance) != kStatus_USB_Success) + { + (void)USB_HostNotifyDevice(hostInstance, newInstance, (uint32_t)kUSB_HostEventEnumerationFail, + (uint32_t)kStatus_USB_Error); + } + + *deviceHandle = newInstance; + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber) +{ + usb_host_device_instance_t *deviceInstance; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + (void)USB_HostLock(); +/* search for device instance handle */ +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; + while (deviceInstance != NULL) + { + if ((deviceInstance->hubNumber == hubNumber) && (deviceInstance->portNumber == portNumber)) + { + break; + } + deviceInstance = deviceInstance->next; + } +#else + deviceInstance = (usb_host_device_instance_t *)hostInstance->deviceList; +#endif + (void)USB_HostUnlock(); + if (deviceInstance != NULL) + { + return USB_HostDetachDeviceInternal(hostHandle, deviceInstance); /* device instance detach */ + } + return kStatus_USB_Success; +} + +usb_status_t USB_HostDetachDeviceInternal(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + deviceInstance->deviceAttachState = (uint8_t)kStatus_device_Detached; /* mark the device is detached from host */ + + if (deviceInstance->state >= (uint8_t)kStatus_DEV_Initial) /* device instance is valid */ + { + /* detach internally */ + if (deviceInstance->state < (uint8_t)kStatus_DEV_AppUsed) /* enumeration is not done */ + { + if (deviceInstance->controlPipe != NULL) + { + (void)USB_HostCancelTransfer(hostInstance, deviceInstance->controlPipe, NULL); + } + + /* remove device instance from host */ + (void)USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); + } + else /* enumeration has be done and notified application */ + { + /* notify application device detach */ + (void)USB_HostNotifyDevice(hostInstance, deviceInstance, (uint32_t)kUSB_HostEventDetach, + (uint32_t)kStatus_USB_Success); + } + } + + return kStatus_USB_Success; +} + +uint8_t USB_HostGetDeviceAttachState(usb_device_handle deviceHandle) +{ + return (NULL != deviceHandle) ? ((usb_host_device_instance_t *)deviceHandle)->deviceAttachState : 0x0U; +} + +usb_status_t USB_HostValidateDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_device_instance_t *searchDev; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidParameter; + } + /* search for the device */ + searchDev = (usb_host_device_instance_t *)((usb_host_instance_t *)hostHandle)->deviceList; + while ((searchDev != NULL) && ((usb_device_handle)searchDev != deviceHandle)) + { + searchDev = searchDev->next; + } + + if (NULL != searchDev) + { + return kStatus_USB_Success; + } + return kStatus_USB_Error; +} + +static usb_status_t USB_HostControlBus(usb_host_handle hostHandle, uint8_t controlType) +{ + usb_status_t status = kStatus_USB_Success; + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + + if (hostHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + /* the callbackFn is initialized in USB_HostGetControllerInterface */ + status = hostInstance->controllerTable->controllerIoctl(hostInstance->controllerHandle, kUSB_HostBusControl, + &controlType); + + return status; +} + +usb_status_t USB_HostOpenDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t index = 0; + + if ((deviceHandle == NULL) || (interfaceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + (void)USB_HostLock(); + /* check host_instance valid? */ + for (; index < (uint8_t)USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1U) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= (uint8_t)USB_HOST_CONFIG_MAX_HOST) + { + (void)USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + (void)USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* search interface and set the interface as opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = (uint8_t)kStatus_interface_Opened; + break; + } + } + (void)USB_HostUnlock(); + + return kStatus_USB_Success; +} + +usb_status_t USB_HostCloseDeviceInterface(usb_device_handle deviceHandle, usb_host_interface_handle interfaceHandle) +{ + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + usb_host_instance_t *hostInstance = NULL; + uint8_t interfaceIndex; + uint8_t removeLabel = 1; + uint8_t index = 0; + + if (deviceHandle == NULL) + { + return kStatus_USB_InvalidHandle; + } + + hostInstance = (usb_host_instance_t *)deviceInstance->hostHandle; + (void)USB_HostLock(); + /* check host_instance valid? */ + for (; index < (uint8_t)USB_HOST_CONFIG_MAX_HOST; ++index) + { + if ((g_UsbHostInstance[index].occupied == 1U) && + ((usb_host_instance_t *)(&g_UsbHostInstance[index]) == (hostInstance))) + { + break; + } + } + if (index >= (uint8_t)USB_HOST_CONFIG_MAX_HOST) + { + (void)USB_HostUnlock(); + return kStatus_USB_Error; + } + + /* check deviceHandle valid? */ + if (USB_HostValidateDevice(hostInstance, deviceHandle) != kStatus_USB_Success) + { + (void)USB_HostUnlock(); + return kStatus_USB_Error; + } + + if (interfaceHandle != NULL) + { + /* search interface and set the interface as detached */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (&deviceInstance->configuration.interfaceList[interfaceIndex] == interfaceHandle) + { + deviceInstance->interfaceStatus[interfaceIndex] = (uint8_t)kStatus_interface_Detached; + break; + } + } + } + + if (deviceInstance->deviceAttachState == (uint8_t)kStatus_device_Detached) /* device is removed from host */ + { + removeLabel = 1; + /* check all the interfaces of the device are not opened */ + for (interfaceIndex = 0; interfaceIndex < deviceInstance->configuration.interfaceCount; ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == (uint8_t)kStatus_interface_Opened) + { + removeLabel = 0U; + break; + } + } + if (removeLabel == 1U) + { + /* remove device instance from host */ + (void)USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + } + (void)USB_HostUnlock(); + + if (removeLabel == 1U) + { + USB_HostReleaseDeviceResource((usb_host_instance_t *)deviceInstance->hostHandle, + deviceInstance); /* release device resource */ + } + } + else + { + (void)USB_HostUnlock(); + } + + return kStatus_USB_Success; +} + +usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle deviceHandle) +{ + usb_host_instance_t *hostInstance = (usb_host_instance_t *)hostHandle; + usb_host_device_instance_t *deviceInstance = (usb_host_device_instance_t *)deviceHandle; + uint8_t interfaceIndex = 0; +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + uint8_t level = 0; + uint8_t devHubNo; + uint8_t devPortNo; +#endif + + if ((hostHandle == NULL) || (deviceHandle == NULL)) + { + return kStatus_USB_InvalidHandle; + } + if (deviceInstance->hostHandle != hostHandle) + { + return kStatus_USB_InvalidParameter; + } + + if (USB_HostValidateDevice(hostInstance, deviceInstance) == kStatus_USB_Success) /* device is valid */ + { +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + devHubNo = deviceInstance->hubNumber; + devPortNo = deviceInstance->portNumber; + level = deviceInstance->level; +#endif + + deviceInstance->deviceAttachState = (uint8_t)kStatus_device_Detached; + if (deviceInstance->state >= (uint8_t)kStatus_DEV_Initial) /* device is valid */ + { + if (deviceInstance->state < + (uint8_t)kStatus_DEV_AppUsed) /* enumeration is not done or application don't use */ + { + /* detach internally */ + (void)USB_HostDetachDeviceInternal(hostHandle, deviceHandle); + } + else /* application use the device */ + { + for (interfaceIndex = 0U; interfaceIndex < deviceInstance->configuration.interfaceCount; + ++interfaceIndex) + { + if (deviceInstance->interfaceStatus[interfaceIndex] == (uint8_t)kStatus_interface_Opened) + { +#ifdef HOST_ECHO + usb_echo("error: there is class instance that is not deinited\r\n"); +#endif + break; + } + } + /* remove device instance from host */ + (void)USB_HostRemoveDeviceInstance(hostInstance, deviceInstance); + USB_HostReleaseDeviceResource(hostInstance, deviceInstance); /* release resource */ + } + } + +#if ((defined USB_HOST_CONFIG_HUB) && (USB_HOST_CONFIG_HUB)) + if (level == 1U) + { + (void)USB_HostControlBus(hostHandle, (uint8_t)kUSB_HostBusReset); /* reset controller port */ + (void)USB_HostControlBus(hostHandle, (uint8_t)kUSB_HostBusRestart); /* restart controller port */ + } + else + { + (void)USB_HostHubRemovePort(hostHandle, devHubNo, devPortNo); /* reset hub port */ + } +#else + USB_HostControlBus(hostHandle, kUSB_HostBusReset); /* reset controller port */ + USB_HostControlBus(hostHandle, kUSB_HostBusRestart); /* restart controller port */ +#endif /* USB_HOST_CONFIG_HUB */ + } + + return kStatus_USB_Success; +} +#else static void USB_HostEnumerationTransferCallback(void *param, usb_host_transfer_t *transfer, usb_status_t status) { /* 0 - retry current transfer, 1 - transfer success process, @@ -1462,3 +2788,4 @@ usb_status_t USB_HostRemoveDevice(usb_host_handle hostHandle, usb_device_handle return kStatus_USB_Success; } +#endif diff --git a/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.c b/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.c index 58059e033d..59105d46ee 100644 --- a/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.c +++ b/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.c @@ -21,6 +21,11 @@ #include "usb_host.h" #endif +//#define USB_GINSTANCE_SIZE (sizeof(usb_host_ehci_instance_t)) +//#if defined(__ICCARM__) /* IAR Workbench */ +//#pragma location = "usb_heap_section" +//static char ginstance_base[USB_GINSTANCE_SIZE]; +//#endif /******************************************************************************* * Definitions ******************************************************************************/ @@ -156,6 +161,15 @@ static void USB_HostEhciZeroMem(uint32_t *buffer, uint32_t length); */ static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms); +#ifdef SOC_IMXRT1170_SERIES +/*! + * @brief host ehci start async schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance); +#endif + /*! * @brief host ehci stop async schedule. * @@ -163,6 +177,15 @@ static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms); */ static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance); +#ifdef SOC_IMXRT1170_SERIES +/*! + * @brief host ehci start periodic schedule. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance); +#endif + /*! * @brief host ehci stop periodic schedule. * @@ -482,6 +505,19 @@ static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstanc usb_host_ehci_pipe_t *ehciPipePointer, usb_host_transfer_t *transfer); + +#ifdef SOC_IMXRT1170_SERIES +/*! + * @brief control ehci bus. + * + * @param ehciInstance ehci instance pointer. + * @param bus_control control code. + * + * @return kStatus_USB_Success or error codes. + */ +static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl); +#endif + /*! * @brief ehci transaction done process function. * @@ -489,7 +525,22 @@ static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstanc */ void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance); +#ifdef SOC_IMXRT1170_SERIES +/*! + * @brief ehci port change interrupt process function. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance); +/*! + * @brief ehci timer0 interrupt process function. + * cancel control/bulk transfer that time out. + * + * @param ehciInstance ehci instance pointer. + */ +static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance); +#endif #if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) /*! @@ -1045,7 +1096,11 @@ static void USB_HostBandwidthHsHostComputeCurrentFsls(usb_host_ehci_instance_t * { usb_host_ehci_pipe_t *ehciPipePointer; uint8_t index; +#ifdef SOC_IMXRT1170_SERIES + uint32_t deviceInfo = 0; +#else uint32_t deviceInfo; +#endif void *temp; for (index = 0; index < 8U; ++index) @@ -1117,7 +1172,11 @@ static void USB_HostBandwidthHsHostComputeCurrentHsAll(usb_host_ehci_instance_t { usb_host_ehci_pipe_t *ehciPipePointer; uint16_t index; +#ifdef SOC_IMXRT1170_SERIES + uint32_t deviceInfo = 0U; +#else uint32_t deviceInfo; +#endif uint16_t frameInterval; void *temp; for (index = 0; index < 8U; ++index) @@ -1790,7 +1849,11 @@ static void USB_HostEhciDelay(USBHS_Type *ehciIpBase, uint32_t ms) } while ((distance & EHCI_MAX_UFRAME_VALUE) < (ms * 8U)); /* compute the distance between sofStart and SofEnd */ } +#ifdef SOC_IMXRT1170_SERIES +static void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance) +#else void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance) +#endif { uint32_t stateSync; @@ -1828,7 +1891,11 @@ static void USB_HostEhciStopAsync(usb_host_ehci_instance_t *ehciInstance) } } +#ifdef SOC_IMXRT1170_SERIES +static void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance) +#else void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance) +#endif { uint32_t stateSync; @@ -3060,6 +3127,9 @@ static uint32_t USB_HostEhciItdArrayRelease(usb_host_ehci_instance_t *ehciInstan /* USB_HostEhciLock(); */ /*set next link pointer to invalid in case hardware access invalid itd structure in special case*/ itdPointer->nextLinkPointer = EHCI_HOST_T_INVALID_VALUE; +#ifdef SOC_IMXRT1170_SERIES + USB_HostEhciZeroMem((uint32_t *)(void *)itdPointer + 1, ((sizeof(usb_host_ehci_itd_t) >> 2) - 4U)); +#endif itdPointer->nextItdPointer = (usb_host_ehci_itd_t *)ehciInstance->ehciItdList; ehciInstance->ehciItdList = itdPointer; ehciInstance->ehciItdNumber++; @@ -3379,7 +3449,10 @@ static usb_status_t USB_HostEhciStartIP(usb_host_ehci_instance_t *ehciInstance) #endif #endif } - +#ifdef SOC_IMXRT1170_SERIES + /* no interrupt threshold */ + ehciInstance->ehciIpBase->USBCMD &= ~USBHS_USBCMD_ITC_MASK; +#endif /* start the controller */ ehciInstance->ehciIpBase->USBCMD |= USBHS_USBCMD_RS_MASK; @@ -3474,8 +3547,11 @@ static usb_status_t USB_HostEhciCancelPipe(usb_host_ehci_instance_t *ehciInstanc return kStatus_USB_Success; } - +#ifdef SOC_IMXRT1170_SERIES +static usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl) +#else usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint8_t busControl) +#endif { usb_status_t status = kStatus_USB_Success; uint32_t portScRegister; @@ -3525,7 +3601,9 @@ usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint ehciInstance->ehciIpBase->PORTSC1 &= ~USBHS_PORTSC1_WKCN_MASK; ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_WKDS_MASK; ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_SUSP_MASK); /* Suspend the device */ - +#if (defined(FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT) && (FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT > 0U)) + PMU->WAKEUP_PM2_MASK1 |= PMU_WAKEUP_PM2_MASK1_USB(1); +#endif ehciInstance->matchTick = 0U; ehciInstance->ehciIpBase->USBINTR |= (USBHS_USBINTR_TIE1_MASK); ehciInstance->busSuspendStatus = kBus_EhciStartSuspend; @@ -3543,8 +3621,11 @@ usb_status_t USB_HostEhciControlBus(usb_host_ehci_instance_t *ehciInstance, uint ehciInstance->busSuspendStatus = kBus_EhciStartResume; #if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) ehciInstance->registerNcBase->USB_OTGn_CTRL &= ~USBNC_USB_OTGn_CTRL_WIE_MASK; +#else +#if (defined(FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT) && (FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT > 0U)) #else ehciInstance->ehciIpBase->USBGENCTRL &= ~USBHS_USBGENCTRL_WU_IE_MASK; +#endif #endif ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK); ehciInstance->ehciIpBase->PORTSC1 |= (USBHS_PORTSC1_FPR_MASK); /* Resume the device */ @@ -3583,7 +3664,11 @@ void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance) ((defined USB_HOST_CONFIG_EHCI_MAX_SITD) && (USB_HOST_CONFIG_EHCI_MAX_SITD))) usb_host_ehci_iso_t *isoPointer; uint32_t dataLength; +#ifdef SOC_IMXRT1170_SERIES + uint32_t speed = 0U; +#else uint32_t speed; +#endif #endif void *temp; uint32_t transferResults; @@ -3693,12 +3778,30 @@ void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance) else { /* remove qtd from qh */ +#ifdef SOC_IMXRT1170_SERIES + do + { + if (vltQtdPointer == NULL) + { + break; + } + else if (0U != (vltQtdPointer->transferResults[0] & EHCI_HOST_QTD_IOC_MASK)) + { + break; + } + else + { + /* no action */ + } + vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer; + } while (true); +#else while ((vltQtdPointer != NULL) && (0U == (transferResults & EHCI_HOST_QTD_IOC_MASK))) /* find the IOC qtd */ { vltQtdPointer = (volatile usb_host_ehci_qtd_t *)vltQtdPointer->nextQtdPointer; } - +#endif vltQhPointer->nextQtdPointer = EHCI_HOST_T_INVALID_VALUE; vltQhPointer->currentQtdPointer = EHCI_HOST_T_INVALID_VALUE; vltQhPointer->transferOverlayResults[0] &= @@ -3823,7 +3926,11 @@ void USB_HostEhciTransactionDone(usb_host_ehci_instance_t *ehciInstance) } } +#ifdef SOC_IMXRT1170_SERIES +static void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance) +#else void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance) +#endif { /* note: only has one port */ uint32_t portScRegister = ehciInstance->ehciIpBase->PORTSC1; @@ -3915,7 +4022,13 @@ void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance) ehciInstance->ehciIpBase->USBINTR &= ~(USBHS_USBINTR_TIE1_MASK); #endif /* disable ehci phy disconnection */ +#ifdef SOC_IMXRT1170_SERIES +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 0); +#endif +#else + USB_EhcihostPhyDisconnectDetectCmd(ehciInstance->controllerId, 0); +#endif /* disable async and periodic */ USB_HostEhciStopAsync(ehciInstance); USB_HostEhciStopPeriodic(ehciInstance); @@ -3924,7 +4037,11 @@ void USB_HostEhciPortChange(usb_host_ehci_instance_t *ehciInstance) } } +#ifdef SOC_IMXRT1170_SERIES +static void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance) +#else void USB_HostEhciTimer0(usb_host_ehci_instance_t *ehciInstance) +#endif { volatile usb_host_ehci_qh_t *vltQhPointer; usb_host_ehci_qtd_t *vltQtdPointer; @@ -4070,25 +4187,55 @@ static void USB_HostEhciTimer1(usb_host_ehci_instance_t *ehciInstance) | USBPHY_CTRL_ENIRQRESUMEDETECT_MASK ; #endif +#endif +#ifdef SOC_IMXRT1170_SERIES +#if (defined(FSL_FEATURE_USBPHY_28FDSOI) && (FSL_FEATURE_USBPHY_28FDSOI > 0U)) + ehciInstance->registerPhyBase->USB1_VBUS_DETECT_SET |= + USBPHY_USB1_VBUS_DETECT_VBUSVALID_TO_SESSVALID_MASK; +#endif #endif ehciInstance->ehciIpBase->PORTSC1 |= USBHS_PORTSC1_PHCD_MASK; +#ifdef SOC_IMXRT1170_SERIES +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) ehciInstance->registerPhyBase->PWD = 0xFFFFFFFFU; while (0U != (ehciInstance->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK))) { __NOP(); } +#endif +#else + ehciInstance->registerPhyBase->PWD = 0xFFFFFFFFU; + while (0U != (ehciInstance->registerPhyBase->CTRL & (USBPHY_CTRL_UTMI_SUSPENDM_MASK))) + { + __NOP(); + } +#endif + #if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WKUP_ID_EN_MASK | USBNC_USB_OTGn_CTRL_WKUP_VBUS_EN_MASK | USBNC_USB_OTGn_CTRL_WKUP_DPDM_EN_MASK; ehciInstance->registerNcBase->USB_OTGn_CTRL |= USBNC_USB_OTGn_CTRL_WIE_MASK; +#else +#ifdef SOC_IMXRT1170_SERIES +#if (defined(FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT) && (FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT > 0U)) +#else + ehciInstance->ehciIpBase->USBGENCTRL = USBHS_USBGENCTRL_WU_IE_MASK; +#endif #else ehciInstance->ehciIpBase->USBGENCTRL = USBHS_USBGENCTRL_WU_IE_MASK; #endif +#endif +#ifdef +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; +#endif +#else + ehciInstance->registerPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; +#endif (void)hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, kUSB_HostEventSuspended); /* call host callback function */ ehciInstance->busSuspendStatus = kBus_EhciSuspended; @@ -4159,8 +4306,14 @@ usb_status_t USB_HostEhciCreate(uint8_t controllerId, ehciInstance->busSuspendStatus = kBus_EhciIdle; #if (defined(USB_HOST_CONFIG_LOW_POWER_MODE) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) +#ifdef SOC_IMXRT1170_SERIES +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) ehciInstance->registerPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); - +#endif +#else + ehciInstance->registerPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); +#endif + #if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) ehciInstance->registerNcBase = (USBNC_Type *)USB_EhciNCGetBase(controllerId); #endif @@ -4386,7 +4539,9 @@ usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle, usb_status_t status; uint32_t speed = 0; usb_host_ehci_instance_t *ehciInstance = (usb_host_ehci_instance_t *)controllerHandle; +#if !defined(SOC_IMXRT1170_SERIES) uint32_t val32; +#endif void *temp; /* get one pipe */ USB_HostEhciLock(); @@ -4444,6 +4599,7 @@ usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle, (uint8_t)ehciPipePointer->pipeCommon.interval); /* FS/LS interrupt interval should be the power of 2, it is used for ehci bandwidth */ } +#if !defined(SOC_IMXRT1170_SERIES) } if ((speed == USB_SPEED_HIGH) && (ehciPipePointer->pipeCommon.interval < 8U)) @@ -4452,6 +4608,7 @@ usb_status_t USB_HostEhciOpenPipe(usb_host_controller_handle controllerHandle, val32 &= (~USBHS_USBCMD_ITC_MASK); val32 |= USBHS_USBCMD_ITC((ehciPipePointer->pipeCommon.interval)); ehciInstance->ehciIpBase->USBCMD = val32; +#endif } } @@ -4824,6 +4981,8 @@ void USB_HostEhciIsrFunction(void *hostHandle) { /*no action*/ } +#else +#if (defined(FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT) && (FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT > 0U)) #else if (0U != (ehciInstance->ehciIpBase->USBGENCTRL & USBHS_USBGENCTRL_WU_IE_MASK)) { @@ -4857,8 +5016,8 @@ void USB_HostEhciIsrFunction(void *hostHandle) { /*no action*/ } +#endif /* FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT */ #endif /* FSL_FEATURE_SOC_USBNC_COUNT */ - #endif /* USB_HOST_CONFIG_LOW_POWER_MODE */ interruptStatus = ehciInstance->ehciIpBase->USBSTS; @@ -4905,6 +5064,27 @@ void USB_HostEhciIsrFunction(void *hostHandle) /*no action */ } } +#if (defined(FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT) && (FSL_FEATURE_USB_ATLANTIC_EHCI_SUPPORT > 0U)) + if ((kBus_EhciSuspended == ehciInstance->busSuspendStatus)) + { + usb_host_instance_t *hostPointer = (usb_host_instance_t *)ehciInstance->hostHandle; + + (void)hostPointer->deviceCallback(hostPointer->suspendedDevice, NULL, + kUSB_HostEventDetectResume); /* call host callback function */ + + uint32_t delay = 100000; + while (delay-- && !(USBOTG->PLL_CONTROL_0 & USBC_PLL_CONTROL_0_PLL_READY_MASK)) + { + } + if (0U != (ehciInstance->ehciIpBase->PORTSC1 & USBHS_PORTSC1_CCS_MASK)) + { + USB_HostEhciStartAsync(ehciInstance); + USB_HostEhciStartPeriodic(ehciInstance); + } + ehciInstance->ehciIpBase->USBCMD |= (USBHS_USBCMD_RS_MASK); + ehciInstance->busSuspendStatus = kBus_EhciStartResume; + } +#endif #endif (void)OSA_EventSet(ehciInstance->taskEventHandle, EHCI_TASK_EVENT_PORT_CHANGE); } diff --git a/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.h b/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.h index 29a0fd2a3f..1af4880c92 100644 --- a/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.h +++ b/bsp/imxrt/libraries/drivers/usb/host/usb_host_ehci.h @@ -309,7 +309,13 @@ typedef struct _usb_host_ehci_instance uint32_t taskEventHandleBuffer[(OSA_EVENT_HANDLE_SIZE + 3) / 4]; /*!< EHCI task event handle buffer*/ #if ((defined(USB_HOST_CONFIG_LOW_POWER_MODE)) && (USB_HOST_CONFIG_LOW_POWER_MODE > 0U)) uint64_t matchTick; +#ifdef SOC_IMXRT1170_SERIES +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) USBPHY_Type *registerPhyBase; /*!< The base address of the PHY register */ +#endif +#else + USBPHY_Type *registerPhyBase; /*!< The base address of the PHY register */ +#endif #if (defined(FSL_FEATURE_SOC_USBNC_COUNT) && (FSL_FEATURE_SOC_USBNC_COUNT > 0U)) USBNC_Type *registerNcBase; /*!< The base address of the USBNC register */ #endif @@ -473,6 +479,7 @@ extern usb_status_t USB_HostEhciIoctl(usb_host_controller_handle controllerHandl uint32_t ioctlEvent, void *ioctlParam); +#if !defined(SOC_IMXRT1170_SERIES) /*! * @brief control ehci bus. * @@ -511,7 +518,7 @@ extern void USB_HostEhciStartAsync(usb_host_ehci_instance_t *ehciInstance); * @param ehciInstance ehci instance pointer. */ extern void USB_HostEhciStartPeriodic(usb_host_ehci_instance_t *ehciInstance); - +#endif /*! @}*/ #ifdef __cplusplus diff --git a/bsp/imxrt/libraries/drivers/usb/host/usb_host_hci.c b/bsp/imxrt/libraries/drivers/usb/host/usb_host_hci.c index 1409868b7b..9ae82ae50c 100644 --- a/bsp/imxrt/libraries/drivers/usb/host/usb_host_hci.c +++ b/bsp/imxrt/libraries/drivers/usb/host/usb_host_hci.c @@ -171,7 +171,7 @@ static usb_host_instance_t *USB_HostGetInstance(void) void *temp; OSA_SR_ALLOC(); OSA_ENTER_CRITICAL(); - for (; i < USB_HOST_CONFIG_MAX_HOST; i++) + for (; i < (uint8_t)USB_HOST_CONFIG_MAX_HOST; i++) { if (g_UsbHostInstance[i].occupied != 1U) { @@ -182,7 +182,7 @@ static usb_host_instance_t *USB_HostGetInstance(void) } g_UsbHostInstance[i].occupied = 1; OSA_EXIT_CRITICAL(); - for (index = 0; index < USB_HOST_CONFIG_MAX_TRANSFERS; ++index) + for (index = 0; index < (uint32_t)USB_HOST_CONFIG_MAX_TRANSFERS; ++index) { temp = (void *)&(s_Setupbuffer[i][index][0]); g_UsbHostInstance[i].transferList[index].setupPacket = (usb_setup_struct_t *)temp; @@ -266,6 +266,7 @@ usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, hos { return kStatus_USB_Error; } + /* HOST instance init*/ hostInstance->controllerId = controllerId; @@ -290,7 +291,7 @@ usb_status_t USB_HostInit(uint8_t controllerId, usb_host_handle *hostHandle, hos transferPrev->next = &hostInstance->transferList[i]; transferPrev = transferPrev->next; } - + /* controller create, the callbackFn is initialized in USB_HostGetControllerInterface */ status = hostInstance->controllerTable->controllerCreate(controllerId, hostInstance, &(hostInstance->controllerHandle)); @@ -698,14 +699,19 @@ usb_status_t USB_HostHelperParseAlternateSetting(usb_host_interface_handle inter } /* parse configuration descriptor */ +#ifdef SOC_IMXRT1170_SERIES + temp = (void *)((usb_host_interface_t *)interfaceHandle)->interfaceExtension; +#else temp = (void *)((usb_host_interface_t *)interfaceHandle)->interfaceDesc; - ; +#endif unionDes = (usb_descriptor_union_t *)temp; /* interface extend descriptor start */ endPosition = (uint32_t)unionDes + ((usb_host_interface_t *)interfaceHandle)->interfaceExtensionLength; /* interface extend descriptor end */ +#if !defined(SOC_IMXRT1170_SERIES) unionDes = (usb_descriptor_union_t *)((uint32_t)unionDes + unionDes->common.bLength); - +#endif + /* search for the alternate setting interface descriptor */ while ((uint32_t)unionDes < endPosition) { diff --git a/bsp/imxrt/libraries/drivers/usb/include/usb.h b/bsp/imxrt/libraries/drivers/usb/include/usb.h index a219f10cec..1472c2a0f8 100644 --- a/bsp/imxrt/libraries/drivers/usb/include/usb.h +++ b/bsp/imxrt/libraries/drivers/usb/include/usb.h @@ -56,6 +56,12 @@ /*! @brief USB stack version definition */ #define USB_MAKE_VERSION(major, minor, bugfix) (((major) << 16) | ((minor) << 8) | (bugfix)) +#ifdef SOC_IMXRT1170_SERIES +/*! @brief USB stack component version definition, changed with component in yaml together */ +#define USB_STACK_COMPONENT_VERSION \ + MAKE_VERSION(USB_STACK_VERSION_MAJOR, USB_STACK_VERSION_MINOR, USB_STACK_VERSION_BUGFIX) +#endif + /*! @brief USB error code */ typedef enum _usb_status { @@ -80,6 +86,11 @@ typedef enum _usb_status kStatus_USB_MSDStatusFail, /*!< For MSD, the CSW status means fail */ kStatus_USB_EHCIAttached, kStatus_USB_EHCIDetached, +#ifdef SOC_IMXRT1170_SERIES + kStatus_USB_DataOverRun, /*!< The amount of data returned by the endpoint exceeded + either the size of the maximum data packet allowed + from the endpoint or the remaining buffer size. */ +#endif } usb_status_t; /*! @brief USB host handle type define */ @@ -120,6 +131,11 @@ typedef enum _usb_controller_index kUSB_ControllerIp3516Hs1 = 11U, /*!< IP3516HS 1U, Currently, there are no platforms which have two IP3516HS IPs, this is reserved to be used in the future. */ +#ifdef SOC_IMXRT1170_SERIES + kUSB_ControllerDwc30 = 12U, /*!< DWC3 0U */ + kUSB_ControllerDwc31 = 13U, /*!< DWC3 1U Currently, there are no platforms which have two Dwc IPs, this is reserved + to be used in the future.*/ +#endif } usb_controller_index_t; /** diff --git a/bsp/imxrt/libraries/drivers/usb/include/usb_host_config.h b/bsp/imxrt/libraries/drivers/usb/include/usb_host_config.h index 8990136352..a3c3b7dbfd 100644 --- a/bsp/imxrt/libraries/drivers/usb/include/usb_host_config.h +++ b/bsp/imxrt/libraries/drivers/usb/include/usb_host_config.h @@ -22,8 +22,11 @@ * - if 0, host ehci driver is disable. * - if greater than 0, host ehci driver is enable. */ +#ifdef SOC_IMXRT1170_SERIES +#define USB_HOST_CONFIG_EHCI (1U) +#else #define USB_HOST_CONFIG_EHCI (2U) - +#endif /*! * @brief host ohci instance count, meantime it indicates ohci enable or disable. * - if 0, host ohci driver is disable. @@ -100,8 +103,13 @@ #define USB_HOST_CONFIG_BUFFER_PROPERTY_CACHEABLE (0U) #endif /*! @brief if 1, enable usb compliance test codes; if 0, disable usb compliance test codes. */ +#ifdef SOC_IMXRT1170_SERIES +#ifndef USB_HOST_CONFIG_COMPLIANCE_TEST #define USB_HOST_CONFIG_COMPLIANCE_TEST (0U) - +#endif +#else +#define USB_HOST_CONFIG_COMPLIANCE_TEST (0U) +#endif /*! @brief if 1, class driver clear stall automatically; if 0, class driver don't clear stall. */ #define USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL (0U) @@ -148,7 +156,17 @@ /* OHCI configuration */ #if ((defined USB_HOST_CONFIG_OHCI) && (USB_HOST_CONFIG_OHCI)) +#ifdef SOC_IMXRT1170_SERIES +/*! + * @brief ohci ED max count. + */ +#define USB_HOST_CONFIG_OHCI_MAX_ED (16U) +/*! + * @brief ohci GTD max count. + */ +#define USB_HOST_CONFIG_OHCI_MAX_GTD (16U) +#else /*! * @brief ohci ED max count. */ @@ -158,7 +176,8 @@ * @brief ohci GTD max count. */ #define USB_HOST_CONFIG_OHCI_MAX_GTD (8U) - +#endif + /*! * @brief ohci ITD max count. */ @@ -243,5 +262,4 @@ * - if greater than 0, host charger detect is enable. */ #define USB_HOST_CONFIG_BATTERY_CHARGER (0U) - #endif /* _USB_HOST_CONFIG_H_ */ diff --git a/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.c b/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.c index 70537b97dc..2ed2b7d3cd 100644 --- a/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.c +++ b/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.c @@ -33,6 +33,273 @@ #include +#ifdef SOC_IMXRT1170_SERIES +void *USB_EhciPhyGetBase(uint8_t controllerId) +{ + void *usbPhyBase = NULL; +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + uint32_t instance; + uint32_t newinstance = 0; + uint32_t usbphy_base_temp[] = USBPHY_BASE_ADDRS; + uint32_t usbphy_base[] = USBPHY_BASE_ADDRS; + uint32_t *temp; + if (controllerId < (uint8_t)kUSB_ControllerEhci0) + { + return NULL; + } + + if ((controllerId == (uint8_t)kUSB_ControllerEhci0) || (controllerId == (uint8_t)kUSB_ControllerEhci1)) + { + controllerId = controllerId - (uint8_t)kUSB_ControllerEhci0; + } + else if ((controllerId == (uint8_t)kUSB_ControllerLpcIp3511Hs0) || + (controllerId == (uint8_t)kUSB_ControllerLpcIp3511Hs1)) + { + controllerId = controllerId - (uint8_t)kUSB_ControllerLpcIp3511Hs0; + } + else if ((controllerId == (uint8_t)kUSB_ControllerIp3516Hs0) || (controllerId == (uint8_t)kUSB_ControllerIp3516Hs1)) + { + controllerId = controllerId - (uint8_t)kUSB_ControllerIp3516Hs0; + } + else + { + /*no action*/ + } + + for (instance = 0; instance < (sizeof(usbphy_base_temp) / sizeof(usbphy_base_temp[0])); instance++) + { + if (0U != usbphy_base_temp[instance]) + { + usbphy_base[newinstance++] = usbphy_base_temp[instance]; + } + } + if (controllerId > newinstance) + { + return NULL; + } + temp = (uint32_t *)usbphy_base[controllerId]; + usbPhyBase = (void *)temp; +#endif + return usbPhyBase; +} + +/*! + * @brief ehci phy initialization. + * + * This function initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return (uint8_t)kStatus_USB_Error; + } + +#if ((defined FSL_FEATURE_SOC_ANATOP_COUNT) && (FSL_FEATURE_SOC_ANATOP_COUNT > 0U)) + ANATOP->HW_ANADIG_REG_3P0.RW = + (ANATOP->HW_ANADIG_REG_3P0.RW & + (~(ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x1F) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_ILIMIT_MASK))) | + ANATOP_HW_ANADIG_REG_3P0_OUTPUT_TRG(0x17) | ANATOP_HW_ANADIG_REG_3P0_ENABLE_LINREG_MASK; + ANATOP->HW_ANADIG_USB2_CHRG_DETECT.SET = + ANATOP_HW_ANADIG_USB2_CHRG_DETECT_CHK_CHRG_B_MASK | ANATOP_HW_ANADIG_USB2_CHRG_DETECT_EN_B_MASK; +#endif + +#if (defined USB_ANALOG) + USB_ANALOG->INSTANCE[controllerId - (uint8_t)kUSB_ControllerEhci0].CHRG_DETECT_SET = + USB_ANALOG_CHRG_DETECT_CHK_CHRG_B(1) | USB_ANALOG_CHRG_DETECT_EN_B(1); +#endif + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; + if (((uint8_t)kUSB_ControllerIp3516Hs0 == controllerId) || ((uint8_t)kUSB_ControllerIp3516Hs1 == controllerId) || + ((uint8_t)kUSB_ControllerLpcIp3511Hs0 == controllerId) || + ((uint8_t)kUSB_ControllerLpcIp3511Hs1 == controllerId)) + { + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_CLKGATE_MASK; + usbPhyBase->CTRL_SET = USBPHY_CTRL_SET_ENAUTOCLR_PHY_PWD_MASK; + } + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return (uint8_t)kStatus_USB_Success; +} + +/*! + * @brief ehci phy initialization for suspend and resume. + * + * This function initialize ehci phy IP for suspend and resume. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] freq the external input clock. + * for example: if the external input clock is 16M, the parameter freq should be 16000000. + * + * @retval kStatus_USB_Success cancel successfully. + * @retval kStatus_USB_Error the freq value is incorrect. + */ +uint32_t USB_EhciLowPowerPhyInit(uint8_t controllerId, uint32_t freq, usb_phy_config_struct_t *phyConfig) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return (uint8_t)kStatus_USB_Error; + } + +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->TRIM_OVERRIDE_EN = 0x001fU; /* override IFR value */ +#endif + +#if ((defined USBPHY_CTRL_AUTORESUME_EN_MASK) && (USBPHY_CTRL_AUTORESUME_EN_MASK > 0U)) + usbPhyBase->CTRL_CLR |= USBPHY_CTRL_AUTORESUME_EN_MASK; +#else + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTO_PWRON_PLL_MASK; +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_ENAUTOCLR_CLKGATE_MASK | USBPHY_CTRL_ENAUTOCLR_PHY_PWD_MASK; + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL2_MASK; /* support LS device. */ + usbPhyBase->CTRL |= USBPHY_CTRL_SET_ENUTMILEVEL3_MASK; /* support external FS Hub with LS device connected. */ + /* PWD register provides overall control of the PHY power state */ + usbPhyBase->PWD = 0U; +#if (defined USBPHY_ANACTRL_PFD_CLKGATE_MASK) + /* now the 480MHz USB clock is up, then configure fractional divider after PLL with PFD + * pfd clock = 480MHz*18/N, where N=18~35 + * Please note that USB1PFDCLK has to be less than 180MHz for RUN or HSRUN mode + */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_FRAC(24); /* N=24 */ + usbPhyBase->ANACTRL |= USBPHY_ANACTRL_PFD_CLK_SEL(1); /* div by 4 */ + + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_DEV_PULLDOWN_MASK; + usbPhyBase->ANACTRL &= ~USBPHY_ANACTRL_PFD_CLKGATE_MASK; + while (0U == (usbPhyBase->ANACTRL & USBPHY_ANACTRL_PFD_STABLE_MASK)) + { + } +#endif + if (NULL != phyConfig) + { + /* Decode to trim the nominal 17.78mA current source for the High Speed TX drivers on USB_DP and USB_DM. */ + usbPhyBase->TX = + ((usbPhyBase->TX & (~(USBPHY_TX_D_CAL_MASK | USBPHY_TX_TXCAL45DM_MASK | USBPHY_TX_TXCAL45DP_MASK))) | + (USBPHY_TX_D_CAL(phyConfig->D_CAL) | USBPHY_TX_TXCAL45DP(phyConfig->TXCAL45DP) | + USBPHY_TX_TXCAL45DM(phyConfig->TXCAL45DM))); + } +#endif + + return (uint8_t)kStatus_USB_Success; +} + +/*! + * @brief ehci phy de-initialization. + * + * This function de-initialize ehci phy IP. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + */ +void USB_EhciPhyDeinit(uint8_t controllerId) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } +#if ((!(defined FSL_FEATURE_SOC_CCM_ANALOG_COUNT)) && (!(defined FSL_FEATURE_SOC_ANATOP_COUNT))) + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_POWER_MASK; /* power down PLL */ + usbPhyBase->PLL_SIC &= ~USBPHY_PLL_SIC_PLL_EN_USB_CLKS_MASK; /* disable USB clock output from USB PHY PLL */ +#endif + usbPhyBase->CTRL |= USBPHY_CTRL_CLKGATE_MASK; /* set to 1U to gate clocks */ +#endif +} + +/*! + * @brief ehci phy disconnect detection enable or disable. + * + * This function enable/disable host ehci disconnect detection. + * + * @param[in] controllerId ehci controller id, please reference to #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable) +{ +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } + + if (0U != enable) + { + usbPhyBase->CTRL |= USBPHY_CTRL_ENHOSTDISCONDETECT_MASK; + } + else + { + usbPhyBase->CTRL &= (~USBPHY_CTRL_ENHOSTDISCONDETECT_MASK); + } +#endif +} + +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) +void USB_PhyDeviceForceEnterFSMode(uint8_t controllerId, uint8_t enable) +{ + USBPHY_Type *usbPhyBase; + + usbPhyBase = (USBPHY_Type *)USB_EhciPhyGetBase(controllerId); + if (NULL == usbPhyBase) + { + return; + } + + if (0U != enable) + { + uint32_t delay = 1000000; + usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK; + while ((0U != (usbPhyBase->USB1_VBUS_DET_STAT & USBPHY_USB1_VBUS_DET_STAT_VBUS_VALID_3V_MASK)) && (0U != delay)) + { + delay--; + } + usbPhyBase->USB1_LOOPBACK_SET = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK; + } + else + { + usbPhyBase->DEBUG0_CLR = USBPHY_DEBUG0_CLKGATE_MASK; + usbPhyBase->USB1_LOOPBACK_CLR = USBPHY_USB1_LOOPBACK_UTMI_TESTSTART_MASK; + } +} +#endif +#endif +#else void *USB_EhciPhyGetBase(uint8_t controllerId) { void *usbPhyBase = NULL; @@ -238,3 +505,4 @@ void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable) } #endif } +#endif \ No newline at end of file diff --git a/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.h b/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.h index 0409f9c8b9..278dc8fe20 100644 --- a/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.h +++ b/bsp/imxrt/libraries/drivers/usb/phy/usb_phy.h @@ -105,7 +105,23 @@ extern void USB_EhciPhyDeinit(uint8_t controllerId); * 0U - disable; */ extern void USB_EhcihostPhyDisconnectDetectCmd(uint8_t controllerId, uint8_t enable); - +#ifdef SOC_IMXRT1170_SERIES +#if ((defined FSL_FEATURE_SOC_USBPHY_COUNT) && (FSL_FEATURE_SOC_USBPHY_COUNT > 0U)) +#if ((defined FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE) && (FSL_FEATURE_USBHSD_HAS_EXIT_HS_ISSUE > 0U)) +/*! + * @brief Force the PHY enter FS Mode + * + * on RT500 and RT600, the device doesn't enter FS Mode after vbus is invalide and the controller works as HS. + * + * @param[in] controllerId EHCI controller ID; See #usb_controller_index_t. + * @param[in] enable + * 1U - enable; + * 0U - disable; + */ +extern void USB_PhyDeviceForceEnterFSMode(uint8_t controllerId, uint8_t enable); +#endif +#endif +#endif #if defined(__cplusplus) } #endif