From 3346cdd1cf9b589196950b13c7fd02a3b24b3720 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Wed, 20 Mar 2024 09:11:19 +0800 Subject: [PATCH 1/4] dts: nxp: add usb uhc support for frdm_k22f and rt1060 - add usb host controller items to device tree - add usb phy items to device tree. - add yaml support for usb controller device tree items. Signed-off-by: Mark Wang --- dts/arm/nxp/nxp_k2x.dtsi | 8 ++++++++ dts/arm/nxp/nxp_rt10xx.dtsi | 32 +++++++++++++++++++++++++++++- dts/bindings/usb/nxp,uhc-ehci.yaml | 12 +++++++++++ dts/bindings/usb/nxp,uhc-khci.yaml | 8 ++++++++ dts/bindings/usb/nxp,usbphy.yaml | 30 ++++++++++++++++++++++++++++ 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 dts/bindings/usb/nxp,uhc-ehci.yaml create mode 100644 dts/bindings/usb/nxp,uhc-khci.yaml create mode 100644 dts/bindings/usb/nxp,usbphy.yaml diff --git a/dts/arm/nxp/nxp_k2x.dtsi b/dts/arm/nxp/nxp_k2x.dtsi index 147ccffde0bb0..72683c86cb621 100644 --- a/dts/arm/nxp/nxp_k2x.dtsi +++ b/dts/arm/nxp/nxp_k2x.dtsi @@ -375,6 +375,14 @@ status = "disabled"; }; + uhc1: usbh@40072000 { + compatible = "nxp,uhc-khci"; + reg = <0x40072000 0x1000>; + interrupts = <53 1>; + interrupt-names = "usb_otg"; + status = "disabled"; + }; + rnga: random@40029000 { compatible = "nxp,kinetis-rnga"; reg = <0x40029000 0x1000>; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 714b4a303bd2d..17677b5c5f53f 100644 --- a/dts/arm/nxp/nxp_rt10xx.dtsi +++ b/dts/arm/nxp/nxp_rt10xx.dtsi @@ -1,5 +1,5 @@ /* - * Copyright 2017,2023 NXP + * Copyright 2017,2023,2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -815,6 +815,36 @@ status = "disabled"; }; + uhc1: usbh@402e0000 { + compatible = "nxp,uhc-ehci"; + reg = <0x402E0000 0x200>; + interrupts = <113 1>; + interrupt-names = "usb_otg"; + clocks = <&usbclk>; + status = "disabled"; + }; + + uhc2: usbh@402e0200 { + compatible = "nxp,uhc-ehci"; + reg = <0x402E0200 0x200>; + interrupts = <112 1>; + interrupt-names = "usb_otg"; + clocks = <&usbclk>; + status = "disabled"; + }; + + usbphy1: usbphy@400d9000 { + compatible = "nxp,usbphy"; + reg = <0x400D9000 0x1000>; + status = "disabled"; + }; + + usbphy2: usbphy@400da000 { + compatible = "nxp,usbphy"; + reg = <0x400DA000 0x1000>; + status = "disabled"; + }; + usdhc1: usdhc@402c0000 { compatible = "nxp,imx-usdhc"; reg = <0x402c0000 0x4000>; diff --git a/dts/bindings/usb/nxp,uhc-ehci.yaml b/dts/bindings/usb/nxp,uhc-ehci.yaml new file mode 100644 index 0000000000000..5f8657fe72279 --- /dev/null +++ b/dts/bindings/usb/nxp,uhc-ehci.yaml @@ -0,0 +1,12 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP EHCI USB host controller + +compatible: "nxp,uhc-ehci" + +include: [usb-controller.yaml] + +properties: + phy_handle: + type: phandle diff --git a/dts/bindings/usb/nxp,uhc-khci.yaml b/dts/bindings/usb/nxp,uhc-khci.yaml new file mode 100644 index 0000000000000..9a3c6b3a04670 --- /dev/null +++ b/dts/bindings/usb/nxp,uhc-khci.yaml @@ -0,0 +1,8 @@ +# # Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP KHCI USB host controller + +compatible: "nxp,uhc-khci" + +include: [usb-controller.yaml] diff --git a/dts/bindings/usb/nxp,usbphy.yaml b/dts/bindings/usb/nxp,usbphy.yaml new file mode 100644 index 0000000000000..8b247b9bbf995 --- /dev/null +++ b/dts/bindings/usb/nxp,usbphy.yaml @@ -0,0 +1,30 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP USB High Speed Phy + +compatible: "nxp,usbphy" + +include: base.yaml + +properties: + d-cal: + type: int + required: true + description: | + It is board level's value that is used to trim the nominal 17.78mA + current source for the High Speed TX drivers on USB_DP and USB_DM. + + txcal45dp: + type: int + required: true + description: | + It is board level's value that is used to trim the nominal 17.78mA + current source for the High Speed TX drivers on USB_DP and USB_DM. + + txcal45dm: + type: int + required: true + description: | + It is board level's value that is used to trim the nominal 17.78mA + current source for the High Speed TX drivers on USB_DP and USB_DM. From f1a28a077f2891626628d6131d82fb540f940654 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Wed, 20 Mar 2024 09:15:14 +0800 Subject: [PATCH 2/4] modules: hal_nxp: improve the fsl_os_abstraction.h for usb host support - add NXP_FSL_OSA to control OSA - add event - add mutex - add OSA_MemoryAllocate define NXP_FSL_OSA_HEAP to enable the OSA heap. the different modules can select NXP_FSL_OSA_HEAP to enable it. define NXP_FSL_OSA_HEAP_CACHEABLE to enable cacheable heap. the different modules can select NXP_FSL_OSA_HEAP_CACHEABLE to enable it. Signed-off-by: Mark Wang --- modules/hal_nxp/Kconfig | 13 ++++- modules/hal_nxp/fsl_os_abstraction.h | 45 +++++++++++++++ modules/hal_nxp/fsl_os_abstraction_zephyr.c | 63 +++++++++++++++++++++ 3 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 modules/hal_nxp/fsl_os_abstraction_zephyr.c diff --git a/modules/hal_nxp/Kconfig b/modules/hal_nxp/Kconfig index aaec4e84abace..b97bb4bc50bfe 100644 --- a/modules/hal_nxp/Kconfig +++ b/modules/hal_nxp/Kconfig @@ -4,4 +4,15 @@ # SPDX-License-Identifier: Apache-2.0 # -# file is empty and kept as a place holder if/when Kconfig is needed +config NXP_FSL_OSA + bool + +if NXP_FSL_OSA + +config NXP_FSL_OSA_HEAP + bool + +config NXP_FSL_OSA_HEAP_CACHEABLE + bool + +endif # NXP_FSL_OSA diff --git a/modules/hal_nxp/fsl_os_abstraction.h b/modules/hal_nxp/fsl_os_abstraction.h index 1f02b68609780..1763cba0e4173 100644 --- a/modules/hal_nxp/fsl_os_abstraction.h +++ b/modules/hal_nxp/fsl_os_abstraction.h @@ -8,10 +8,55 @@ #define __FSL_OS_ABSTRACTION__ #include +#include + +typedef enum _osa_status { + KOSA_StatusSuccess = 0, /*!< Success */ + KOSA_StatusError = 1, /*!< Failed */ + KOSA_StatusTimeout = 2, /*!< Timeout occurs while waiting */ + KOSA_StatusIdle = 3, /*!< Used for bare metal only, the wait object is not ready + * and timeout still not occur + */ +} osa_status_t; /* enter critical macros */ #define OSA_SR_ALLOC() int osa_current_sr #define OSA_ENTER_CRITICAL() osa_current_sr = irq_lock() #define OSA_EXIT_CRITICAL() irq_unlock(osa_current_sr) +typedef struct k_mutex *osa_mutex_handle_t; +#define OSA_MUTEX_HANDLE_SIZE (sizeof(struct k_mutex)) +#define OSA_MutexCreate(p) k_mutex_init(p) +#define OSA_MutexDestroy(p) (p) +#define OSA_MutexLock(p, t) k_mutex_lock(p, K_FOREVER) +#define OSA_MutexUnlock(p) k_mutex_unlock(p) + +typedef uint32_t osa_event_flags_t; +typedef struct k_event *osa_event_handle_t; +#define OSA_EVENT_HANDLE_SIZE (sizeof(struct k_event)) +static inline osa_status_t OSA_EventCreate(osa_event_handle_t eventHandle, uint8_t autoClear) +{ + k_event_init(eventHandle); + return KOSA_StatusSuccess; +} +#define OSA_EventDestroy(p) (p) +#define OSA_EventSet(p, e) k_event_post(p, e) +#define OSA_EventClear(p, e) k_event_clear(p, e) +static inline 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) +{ + *pSetFlags = k_event_wait(eventHandle, flagsToWait, false, K_FOREVER); + if (*pSetFlags != 0) { + k_event_clear(eventHandle, *pSetFlags); + return KOSA_StatusSuccess; + } + return KOSA_StatusError; +} + +void *OSA_MemoryAllocate(uint32_t memLength); +void OSA_MemoryFree(void *p); + #endif /* __FSL_OS_ABSTRACTION__ */ diff --git a/modules/hal_nxp/fsl_os_abstraction_zephyr.c b/modules/hal_nxp/fsl_os_abstraction_zephyr.c new file mode 100644 index 0000000000000..7ae3e7e656397 --- /dev/null +++ b/modules/hal_nxp/fsl_os_abstraction_zephyr.c @@ -0,0 +1,63 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include "fsl_os_abstraction.h" + +#ifdef CONFIG_NXP_FSL_OSA + +#ifdef CONFIG_NXP_FSL_OSA_HEAP +/* calculate the required heap size of mcux usb host controller */ +#ifdef CONFIG_USB_UHC_NXP_MCUX +#include "usb_host_config.h" +#include "usb_host_mcux_drv_port.h" +#ifdef CONFIG_USB_UHC_NXP_EHCI +#include "usb_host_ehci.h" +#define UHC_NXP_EHCI_ALLOC_SIZE (sizeof(usb_host_ehci_instance_t) * \ + DT_NUM_INST_STATUS_OKAY(nxp_uhc_ehci)) +#else +#define UHC_NXP_EHCI_ALLOC_SIZE (0) +#endif + +#ifdef CONFIG_USB_UHC_NXP_KHCI +#include "usb_host_khci.h" +#define UHC_NXP_KHCI_ALLOC_SIZE ((sizeof(usb_khci_host_state_struct_t) + \ + USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER + 4 + sizeof(usb_host_pipe_t) * \ + USB_HOST_CONFIG_MAX_PIPES) * DT_NUM_INST_STATUS_OKAY(nxp_uhc_khci)) +#else +#define UHC_NXP_KHCI_ALLOC_SIZE (0) +#endif + +#define UHC_NXP_MCUX_RERUIRED_SIZE (UHC_NXP_EHCI_ALLOC_SIZE + UHC_NXP_KHCI_ALLOC_SIZE) +#else +#define UHC_NXP_MCUX_RERUIRED_SIZE (0) +#endif + +/* define the heap size based on the enabled modules */ +#ifdef CONFIG_NXP_FSL_OSA_HEAP_CACHEABLE +K_HEAP_DEFINE_NOCACHE(fsl_osa_alloc_pool, UHC_NXP_MCUX_RERUIRED_SIZE); +#else +K_HEAP_DEFINE(fsl_osa_alloc_pool, UHC_NXP_MCUX_RERUIRED_SIZE); +#endif + +void *OSA_MemoryAllocate(uint32_t memLength) +{ + void *p = (void *)k_heap_alloc(&fsl_osa_alloc_pool, memLength, K_NO_WAIT); + + if (p != NULL) { + (void)memset(p, 0, memLength); + } + + return p; +} + +void OSA_MemoryFree(void *p) +{ + k_heap_free(&fsl_osa_alloc_pool, p); +} + +#endif /* CONFIG_NXP_FSL_OSA_HEAP */ + +#endif /* CONFIG_NXP_FSL_OSA */ From 49bd514264d638fb35b55a8ef2030814a5af5ff4 Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Wed, 20 Mar 2024 09:18:37 +0800 Subject: [PATCH 3/4] drivers: uhc: implement nxp mcux uhc driver - uhc_mcux.c is based on SDK USB Host controller driver. - support EHCI (usb_host_ehci.c) and KHCI (usb_host_khci.c) now. - add related Kconfig. - add usb_host_config.h - update modules/hal_nxp and modules/hal_nxp/usb cmake file for usb host. - update hal_nxp revision to contain the support of usb host controllers. Signed-off-by: Mark Wang --- drivers/usb/uhc/CMakeLists.txt | 2 + drivers/usb/uhc/Kconfig | 1 + drivers/usb/uhc/Kconfig.mcux | 43 ++ drivers/usb/uhc/uhc_mcux.c | 783 ++++++++++++++++++++++++++ modules/hal_nxp/CMakeLists.txt | 6 + modules/hal_nxp/usb/CMakeLists.txt | 8 +- modules/hal_nxp/usb/usb_host_config.h | 43 ++ west.yml | 2 +- 8 files changed, 886 insertions(+), 2 deletions(-) create mode 100644 drivers/usb/uhc/Kconfig.mcux create mode 100644 drivers/usb/uhc/uhc_mcux.c create mode 100644 modules/hal_nxp/usb/usb_host_config.h diff --git a/drivers/usb/uhc/CMakeLists.txt b/drivers/usb/uhc/CMakeLists.txt index 7f38ffd314649..f40abf03faaa2 100644 --- a/drivers/usb/uhc/CMakeLists.txt +++ b/drivers/usb/uhc/CMakeLists.txt @@ -1,4 +1,5 @@ # Copyright (c) 2022 Nordic Semiconductor +# Copyright 2024 NXP # SPDX-License-Identifier: Apache-2.0 zephyr_library() @@ -6,3 +7,4 @@ zephyr_library() zephyr_library_sources(uhc_common.c) zephyr_library_sources_ifdef(CONFIG_UHC_MAX3421E uhc_max3421e.c) zephyr_library_sources_ifdef(CONFIG_UHC_VIRTUAL uhc_virtual.c) +zephyr_library_sources_ifdef(CONFIG_USB_UHC_NXP_MCUX uhc_mcux.c) diff --git a/drivers/usb/uhc/Kconfig b/drivers/usb/uhc/Kconfig index e6da1d4d3dffb..052e9437f6ae2 100644 --- a/drivers/usb/uhc/Kconfig +++ b/drivers/usb/uhc/Kconfig @@ -38,5 +38,6 @@ source "subsys/logging/Kconfig.template.log_config" source "drivers/usb/uhc/Kconfig.max3421e" source "drivers/usb/uhc/Kconfig.virtual" +source "drivers/usb/uhc/Kconfig.mcux" endif # UHC_DRIVER diff --git a/drivers/usb/uhc/Kconfig.mcux b/drivers/usb/uhc/Kconfig.mcux new file mode 100644 index 0000000000000..ec05d17cb45bb --- /dev/null +++ b/drivers/usb/uhc/Kconfig.mcux @@ -0,0 +1,43 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config USB_UHC_NXP_EHCI + bool "NXP MCUX USB EHCI Host controller driver" + default y + depends on DT_HAS_NXP_UHC_EHCI_ENABLED + select USB_UHC_NXP_MCUX + help + NXP MCUX USB Host Controller Driver for EHCI. + +config USB_UHC_NXP_KHCI + bool "NXP MCUX USB KHCI Host controller driver" + default y + depends on DT_HAS_NXP_UHC_KHCI_ENABLED + select USB_UHC_NXP_MCUX + help + NXP MCUX USB Host Controller Driver for KHCI. + +config USB_UHC_NXP_MCUX + bool + # Hidden option to simplify MCUX uhc requirement + select EVENTS + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + select NXP_FSL_OSA + select NXP_FSL_OSA_HEAP + +config USB_UHC_NXP_PHY + bool "NXP MCUX USB Phy" + default y + depends on DT_HAS_NXP_USBPHY_ENABLED + help + NXP MCUX USB Phy. + +if USB_UHC_NXP_MCUX + +config UHC_MCUX_THREAD_STACK_SIZE + int "MCUX UHC Driver internal thread stack size" + default 2048 + help + Size of the stack used in the driver. + +endif #USB_UHC_NXP_MCUX diff --git a/drivers/usb/uhc/uhc_mcux.c b/drivers/usb/uhc/uhc_mcux.c new file mode 100644 index 0000000000000..a29424ae00682 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux.c @@ -0,0 +1,783 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "uhc_common.h" +#include "usb.h" +#include "usb_host_config.h" +#include "usb_host_mcux_drv_port.h" +#include "usbh_device.h" +#ifdef CONFIG_USB_UHC_NXP_PHY +#include "usb_phy.h" +#endif + +#include +LOG_MODULE_REGISTER(uhc_mcux, CONFIG_UHC_DRIVER_LOG_LEVEL); + +static K_KERNEL_STACK_DEFINE(drv_stack, CONFIG_UHC_MCUX_THREAD_STACK_SIZE); + +K_MEM_SLAB_DEFINE_STATIC(mcux_uhc_transfer_pool, sizeof(usb_host_transfer_t), + USB_HOST_CONFIG_MAX_TRANSFERS, sizeof(void *)); + +#if defined(CONFIG_NOCACHE_MEMORY) +K_HEAP_DEFINE_NOCACHE(mcux_transfer_alloc_pool, USB_HOST_CONFIG_MAX_TRANSFERS * 8u + + 1024u * USB_HOST_CONFIG_MAX_TRANSFERS); +#endif + +#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct uhc_mcux_data, host_instance) + +#ifdef CONFIG_USB_UHC_NXP_EHCI +#include "usb_host_ehci.h" +static const usb_host_controller_interface_t mcux_ehci_usb_iface = { + USB_HostEhciCreate, USB_HostEhciDestory, USB_HostEhciOpenPipe, USB_HostEhciClosePipe, + USB_HostEhciWritePipe, USB_HostEhciReadpipe, USB_HostEhciIoctl, +}; +#endif + +#ifdef CONFIG_USB_UHC_NXP_KHCI +#include "usb_host_khci.h" +static const usb_host_controller_interface_t mcux_khci_usb_iface = { + USB_HostKhciCreate, USB_HostKhciDestory, USB_HostKhciOpenPipe, USB_HostKhciClosePipe, + USB_HostKhciWritePipe, USB_HostKhciReadpipe, USB_HostKciIoctl, +}; +#endif + +struct uhc_mcux_ep_handle { + uint8_t ep; + void *udev; + usb_host_pipe_handle mcux_ep_handle; +}; + +struct uhc_mcux_data { + const struct device *dev; + struct uhc_mcux_ep_handle ep_handles[USB_HOST_CONFIG_MAX_PIPES]; + usb_host_instance_t host_instance; + struct k_thread drv_stack_data; + bool need_update_addr; + uint8_t top_device_speed; + uint8_t controller_id; +}; + +struct uhc_mcux_config { + const usb_host_controller_interface_t *mcux_if; + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); + uint32_t base; +#ifdef CONFIG_USB_UHC_NXP_PHY + uint8_t need_to_init_phy; + uint8_t D_CAL; + uint8_t TXCAL45DP; + uint8_t TXCAL45DM; +#endif +}; + +#if defined(CONFIG_NOCACHE_MEMORY) +/* allocate non-cached buffer for usb */ +static void *uhc_mcux_nocache_alloc(uint32_t size) +{ + void *p = (void *)k_heap_alloc(&mcux_transfer_alloc_pool, size, K_NO_WAIT); + + if (p != NULL) { + (void)memset(p, 0, size); + } + + return p; +} + +/* free the allocated non-cached buffer */ +static void uhc_mcux_nocache_free(void *p) +{ + k_heap_free(&mcux_transfer_alloc_pool, p); +} +#endif + +static int uhc_mcux_bus_control(const struct device *dev, usb_host_bus_control_t type) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + usb_status_t status; + + status = config->mcux_if->controllerIoctl( + priv->host_instance.controllerHandle, kUSB_HostBusControl, &type); + if (status != kStatus_USB_Success) { + return -EIO; + } + return 0; +} + +/*! + * @brief Controller driver calls this function when device attach. + * + * This function will be called by the MCUX SDK host controller layer. + * + * @param hostHandle Host instance handle. + * @param speed Device speed. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * @param level Device level. root device's level is 1. + * @param deviceHandle Return device handle. + * + * @return kStatus_USB_Success or error codes. + */ +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) +{ + enum uhc_event_type type; + struct uhc_mcux_data *priv; + + if (speed == USB_SPEED_HIGH) { + type = UHC_EVT_DEV_CONNECTED_HS; + } else if (speed == USB_SPEED_FULL) { + type = UHC_EVT_DEV_CONNECTED_FS; + } else { + type = UHC_EVT_DEV_CONNECTED_LS; + } + + priv = (struct uhc_mcux_data *)(PRV_DATA_HANDLE(hostHandle)); + priv->top_device_speed = speed; + uhc_submit_event(priv->dev, type, 0); + return kStatus_USB_Success; +} + +/*! + * @brief Controller driver calls this function when device detaches. + * + * This function will be called by the MCUX SDK host controller layer. + * + * @param hostHandle Host instance handle. + * @param hubNumber Device hub no. root device's hub no. is 0. + * @param portNumber Device port no. root device's port no. is 0. + * + * @return kStatus_USB_Success or error codes. + */ +usb_status_t USB_HostDetachDevice(usb_host_handle hostHandle, uint8_t hubNumber, uint8_t portNumber) +{ + struct uhc_mcux_data *priv; + + priv = (struct uhc_mcux_data *)(PRV_DATA_HANDLE(hostHandle)); + uhc_submit_event(priv->dev, UHC_EVT_DEV_REMOVED, 0); + uhc_mcux_bus_control(priv->dev, kUSB_HostBusEnableAttach); + return kStatus_USB_Success; +} + +/*! + * @brief Controller driver calls this function to get the device information. + * + * This function gets the device information. + * This function will be called by the MCUX SDK host controller layer. + * + * @param[in] deviceHandle Removing device handle. + * @param[in] infoCode See the enumeration host_dev_info_t. + * @param[out] infoValue Return the information value. + * + * @retval kStatus_USB_Success Close successfully. + * @retval kStatus_USB_InvalidParameter The deviceHandle or info_value is a NULL pointer. + * @retval kStatus_USB_Error The info_code is not the host_dev_info_t value. + */ +usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, + uint32_t infoCode, + uint32_t *infoValue) +{ + struct usb_device *device = (struct usb_device *)deviceHandle; + const struct device *dev = device->ctx->dev; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + usb_host_dev_info_t devInfo; + + if ((deviceHandle == NULL) || (infoValue == NULL)) { + return kStatus_USB_InvalidParameter; + } + devInfo = (usb_host_dev_info_t)infoCode; + switch (devInfo) { + case kUSB_HostGetDeviceAddress: /* device address */ + *infoValue = device->addr; + break; + + case kUSB_HostGetDeviceHubNumber: /* device hub address */ + case kUSB_HostGetDevicePortNumber: /* device port no */ + case kUSB_HostGetDeviceHSHubNumber: /* device high-speed hub address */ + case kUSB_HostGetDeviceHSHubPort: /* device high-speed hub port no */ + case kUSB_HostGetHubThinkTime: /* device hub think time */ + *infoValue = 0; + break; + case kUSB_HostGetDeviceLevel: /* device level */ + *infoValue = 1; + break; + + case kUSB_HostGetDeviceSpeed: /* device speed */ + /* current usb host stack doesn't support hub, + * so only one device can connect, so it is OK. + */ + *infoValue = (uint32_t)priv->top_device_speed; + break; + + default: + /*no action*/ + break; + } + + return kStatus_USB_Success; +} + +/*! + * @brief Host callback function. + * + * This function will be called by the MCUX SDK host controller layer. + * This callback function is used to notify application device attach/detach event. + * This callback pointer is passed when initializing the host. + * + * @param deviceHandle The device handle, which indicates the attached device. + * @param configurationHandle The configuration handle contains the attached device's + * configuration information. + * @param event_code The callback event code; See the enumeration host_event_t. + * + * @return A USB error code or kStatus_USB_Success. + * @retval kStatus_USB_Success Application handles the attached device successfully. + * @retval kStatus_USB_NotSupported Application don't support the attached device. + * @retval kStatus_USB_Error Application handles the attached device falsely. + */ +static usb_status_t mcux_host_callback(usb_device_handle deviceHandle, + usb_host_configuration_handle configurationHandle, + uint32_t eventCode) +{ + /* TODO: nothing need to do here currently. + * It will be used when implementing suspend/resume in future. + */ + return kStatus_USB_Success; +} + +#ifdef CONFIG_USB_UHC_NXP_EHCI +static void uhc_mcux_ehci_thread(void *p1, void *p2, void *p3) +{ + struct uhc_data *data = ((struct device *)(p1))->data; + struct uhc_mcux_data *priv = data->priv; + + while (true) { + USB_HostEhciTaskFunction((void *)(&priv->host_instance)); + } +} + +static void uhc_mcux_ehci_isr(const struct device *dev) +{ + struct uhc_data *data = (dev)->data; + struct uhc_mcux_data *priv = data->priv; + + USB_HostEhciIsrFunction((void *)(&priv->host_instance)); +} +#endif + +#ifdef CONFIG_USB_UHC_NXP_KHCI +static void uhc_mcux_khci_thread(void *p1, void *p2, void *p3) +{ + struct uhc_data *data = ((struct device *)(p1))->data; + struct uhc_mcux_data *priv = data->priv; + + while (true) { + USB_HostKhciTaskFunction((void *)(&priv->host_instance)); + } +} + +static void uhc_mcux_khci_isr(const struct device *dev) +{ + struct uhc_data *data = ((struct device *)(dev))->data; + struct uhc_mcux_data *priv = data->priv; + + USB_HostKhciIsrFunction((void *)(&priv->host_instance)); +} +#endif + +static int uhc_mcux_lock(const struct device *dev) +{ + struct uhc_data *data = dev->data; + + return k_mutex_lock(&data->mutex, K_FOREVER); +} + +static int uhc_mcux_unlock(const struct device *dev) +{ + struct uhc_data *data = dev->data; + + return k_mutex_unlock(&data->mutex); +} + +static int uhc_mcux_init(const struct device *dev) +{ +#ifdef CONFIG_USB_UHC_NXP_PHY + usb_phy_config_struct_t phy_config; +#endif + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + k_thread_entry_t thread_entry = NULL; + usb_status_t status; + uint8_t index; +#ifdef CONFIG_USB_UHC_NXP_EHCI +#if defined(USBHS_STACK_BASE_ADDRS) + uint32_t usb_base_addrs[] = USBHS_STACK_BASE_ADDRS; +#else + uint32_t usb_base_addrs[] = USBHS_BASE_ADDRS; +#endif +#endif +#ifdef CONFIG_USB_UHC_NXP_KHCI + uint32_t usb_base_addrs[] = USB_BASE_ADDRS; +#endif + + /* get the right controller id */ + priv->controller_id = 0xFFu; /* invalid value */ +#ifdef CONFIG_USB_UHC_NXP_EHCI + for (index = 0; index < ARRAY_SIZE(usb_base_addrs); index++) { + if (usb_base_addrs[index] == config->base) { + priv->controller_id = kUSB_ControllerEhci0 + index; + break; + } + } + + if ((priv->controller_id >= kUSB_ControllerEhci0) && + (priv->controller_id <= kUSB_ControllerEhci1)) { + thread_entry = uhc_mcux_ehci_thread; + } +#endif +#ifdef CONFIG_USB_UHC_NXP_KHCI + for (index = 0; index < ARRAY_SIZE(usb_base_addrs); index++) { + if (usb_base_addrs[index] == config->base) { + priv->controller_id = kUSB_ControllerKhci0 + index; + break; + } + } + + if ((priv->controller_id >= kUSB_ControllerKhci0) && + (priv->controller_id <= kUSB_ControllerKhci1)) { + thread_entry = uhc_mcux_khci_thread; + } +#endif + if (thread_entry == NULL) { + return -ENOMEM; + } + +#ifdef CONFIG_USB_UHC_NXP_PHY + if (config->need_to_init_phy) { + phy_config.D_CAL = config->D_CAL; + phy_config.TXCAL45DP = config->TXCAL45DP; + phy_config.TXCAL45DM = config->TXCAL45DM; + USB_EhciPhyInit(priv->controller_id, 0u, &phy_config); + } +#endif + + priv->dev = dev; + /* Init MCUX USB host driver. */ + priv->host_instance.deviceCallback = mcux_host_callback; + status = config->mcux_if->controllerCreate(priv->controller_id, + &priv->host_instance, &(priv->host_instance.controllerHandle)); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + + /* Create MCUX USB host driver task */ + k_mutex_init(&data->mutex); + if (thread_entry != NULL) { + k_thread_create(&priv->drv_stack_data, drv_stack, + K_KERNEL_STACK_SIZEOF(drv_stack), + thread_entry, + (void *)dev, NULL, NULL, + K_PRIO_COOP(2), 0, K_NO_WAIT); + k_thread_name_set(&priv->drv_stack_data, "uhc_mcux"); + } + + return 0; +} + +static int uhc_mcux_enable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + /* enable interrupt. */ + config->irq_enable_func(dev); + return 0; +} + +static int uhc_mcux_disable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + /* disable interrupt. */ + config->irq_disable_func(dev); + return 0; +} + +static int uhc_mcux_shutdown(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + + /* disable interrupt. */ + config->irq_disable_func(dev); + /* disable MCUX USB host drive task */ + k_thread_abort(&priv->drv_stack_data); + /* de-init USB Host driver */ + config->mcux_if->controllerDestory(priv->host_instance.controllerHandle); + return 0; +} + +/* Signal bus reset, 50ms SE0 signal */ +static int uhc_mcux_bus_reset(const struct device *dev) +{ + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + int ret; + + ret = uhc_mcux_bus_control(dev, kUSB_HostBusReset); + if (ret == 0) { + ret = uhc_mcux_bus_control(dev, kUSB_HostBusRestart); + } + + if (ret == 0) { + priv->need_update_addr = true; + } + return ret; +} + +/* Enable SOF generator */ +static int uhc_mcux_sof_enable(const struct device *dev) +{ + /* MCUX doesn't need it. */ + return 0; +} + +/* Disable SOF generator and suspend bus */ +static int uhc_mcux_bus_suspend(const struct device *dev) +{ + return uhc_mcux_bus_control(dev, kUSB_HostBusSuspend); +} + +/* Signal bus resume event, 20ms K-state + low-speed EOP */ +static int uhc_mcux_bus_resume(const struct device *dev) +{ + return uhc_mcux_bus_control(dev, kUSB_HostBusResume); +} + +static void uhc_mcux_transfer_callback(void *param, usb_host_transfer_t *transfer, + usb_status_t status) +{ + const struct device *dev = (const struct device *)param; + struct uhc_transfer *const xfer = (struct uhc_transfer *const)(transfer->uhc_xfer); + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + int err = -EIO; + + if (status == kStatus_USB_Success) { + err = 0; + + /* TODO: temp workaround because current stack doesn't support it. */ + if ((xfer->ep == 0) && (transfer->setupPacket->bRequest == USB_SREQ_SET_ADDRESS)) { + priv->need_update_addr = true; + } + } + +#if defined(CONFIG_NOCACHE_MEMORY) + if (transfer->setupPacket != NULL) { + uhc_mcux_nocache_free(transfer->setupPacket); + } +#endif + if ((xfer->buf != NULL) && (transfer->transferBuffer != NULL)) { + if (transfer->transferSofar > 0) { +#if defined(CONFIG_NOCACHE_MEMORY) + memcpy(xfer->buf->__buf, transfer->transferBuffer, transfer->transferSofar); +#endif + net_buf_add(xfer->buf, transfer->transferSofar); + } +#if defined(CONFIG_NOCACHE_MEMORY) + uhc_mcux_nocache_free(transfer->transferBuffer); +#endif + } + + transfer->setupPacket = NULL; + transfer->transferBuffer = NULL; + k_mem_slab_free(&mcux_uhc_transfer_pool, transfer); + uhc_xfer_return(dev, xfer, err); +} + +static int uhc_mcux_enqueue(const struct device *dev, + struct uhc_transfer *const xfer) +{ + uint8_t index; + usb_host_pipe_handle mcux_ep_handle = NULL; + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = data->priv; + usb_status_t status; + usb_host_transfer_t *mcux_xfer; + uint8_t ep; + + uhc_xfer_append(dev, xfer); + + /* firstly check and init the mcux endpoint handle */ + for (index = 0; index < USB_HOST_CONFIG_MAX_PIPES; ++index) { + ep = xfer->ep; + if (ep == 0x80) { + ep = 0; + } + + if ((priv->ep_handles[index].mcux_ep_handle != NULL) && + (priv->ep_handles[index].ep == ep) && + (priv->ep_handles[index].udev == xfer->udev)) { + mcux_ep_handle = priv->ep_handles[index].mcux_ep_handle; + break; + } + } + + /* Initialize mcux endpoint pipe */ + if (mcux_ep_handle == NULL) { + usb_host_pipe_init_t pipe_init; + + for (index = 0; index < USB_HOST_CONFIG_MAX_PIPES; ++index) { + if (priv->ep_handles[index].mcux_ep_handle == NULL) { + break; + } + } + + if (index >= USB_HOST_CONFIG_MAX_PIPES) { + return -ENOMEM; + } + + pipe_init.devInstance = xfer->udev; + pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK; + pipe_init.maxPacketSize = xfer->mps; + pipe_init.endpointAddress = xfer->ep & 0x7Fu; + if (xfer->ep & 0x80u) { + pipe_init.direction = USB_IN; + } else { + pipe_init.direction = USB_OUT; + } + /* Current Zephyr Host stack is experimental, the endpoint's interval, + * 'number per uframe' and the endpoint type cannot be got yet. + */ + pipe_init.numberPerUframe = 0; /* TODO: need right way to implement it. */ + pipe_init.interval = 0; /* TODO: need right way to implement it. */ + /* TODO: need right way to implement it. */ + if (xfer->ep == 0) { + pipe_init.pipeType = USB_ENDPOINT_CONTROL; + } else { + pipe_init.pipeType = USB_ENDPOINT_BULK; + } + + status = config->mcux_if->controllerOpenPipe(priv->host_instance.controllerHandle, + &mcux_ep_handle, &pipe_init); + priv->ep_handles[index].mcux_ep_handle = mcux_ep_handle; + priv->ep_handles[index].udev = xfer->udev; + + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + } + + /* give the transfer to MCUX drv. */ + if (k_mem_slab_alloc(&mcux_uhc_transfer_pool, (void **)&mcux_xfer, K_NO_WAIT)) { + return -ENOMEM; + } + mcux_xfer->uhc_xfer = xfer; + mcux_xfer->transferPipe = mcux_ep_handle; + mcux_xfer->transferSofar = 0; + mcux_xfer->next = NULL; + mcux_xfer->setupStatus = 0; + mcux_xfer->callbackFn = uhc_mcux_transfer_callback; + mcux_xfer->callbackParam = (void *)dev; +#if defined(CONFIG_NOCACHE_MEMORY) + mcux_xfer->setupPacket = uhc_mcux_nocache_alloc(8u); + memcpy(mcux_xfer->setupPacket, xfer->setup_pkt, 8u); +#else + mcux_xfer->setupPacket = (usb_setup_struct_t *)&xfer->setup_pkt[0]; +#endif + if (xfer->buf != NULL) { + mcux_xfer->transferLength = xfer->buf->size; +#if defined(CONFIG_NOCACHE_MEMORY) + mcux_xfer->transferBuffer = uhc_mcux_nocache_alloc(mcux_xfer->transferLength); +#else + mcux_xfer->transferBuffer = xfer->buf->__buf; +#endif + } else { + mcux_xfer->transferBuffer = NULL; + mcux_xfer->transferLength = 0; + } + + if ((xfer->ep == 0) || (xfer->ep == 0x80)) { + if (priv->need_update_addr) { + priv->need_update_addr = false; + (void)config->mcux_if->controllerIoctl( + priv->host_instance.controllerHandle, + kUSB_HostUpdateControlEndpointAddress, + mcux_ep_handle); + } + if ((mcux_xfer->setupPacket->bmRequestType & USB_REQUEST_TYPE_DIR_MASK) == + USB_REQUEST_TYPE_DIR_IN) { + mcux_xfer->direction = USB_IN; + } else { + mcux_xfer->direction = USB_OUT; + } + uhc_mcux_lock(dev); + status = config->mcux_if->controllerWritePipe(priv->host_instance.controllerHandle, + mcux_ep_handle, mcux_xfer); + uhc_mcux_unlock(dev); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + } + + return 0; +} + +static int uhc_mcux_dequeue(const struct device *dev, + struct uhc_transfer *const xfer) +{ + /* TODO */ + return 0; +} + +static const struct uhc_api mcux_uhc_api = { + .lock = uhc_mcux_lock, + .unlock = uhc_mcux_unlock, + .init = uhc_mcux_init, + .enable = uhc_mcux_enable, + .disable = uhc_mcux_disable, + .shutdown = uhc_mcux_shutdown, + + .bus_reset = uhc_mcux_bus_reset, + .sof_enable = uhc_mcux_sof_enable, + .bus_suspend = uhc_mcux_bus_suspend, + .bus_resume = uhc_mcux_bus_resume, + + .ep_enqueue = uhc_mcux_enqueue, + .ep_dequeue = uhc_mcux_dequeue, +}; + +static int mcux_driver_preinit(const struct device *dev) +{ + LOG_DBG("MCUX controller initialized"); + + return 0; +} + +#ifdef CONFIG_USB_UHC_NXP_EHCI +#define DT_DRV_COMPAT nxp_uhc_ehci + +#ifdef CONFIG_USB_UHC_NXP_PHY +#define UHC_MCUX_PHY_CONFIGURE(n) \ + .need_to_init_phy = DT_NODE_HAS_PROP(DT_DRV_INST(n), phy_handle) ? 1u : 0u, \ + .D_CAL = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), d_cal, 0), \ + .TXCAL45DP = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), txcal45dp, 0), \ + .TXCAL45DM = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), txcal45dm, 0), +#else +#define UHC_MCUX_PHY_CONFIGURE(n) +#endif + + +#define UHC_MCUX_EHCI_DEVICE_DEFINE(n) \ + static void uhc_irq_enable_func##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + uhc_mcux_ehci_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static void uhc_irq_disable_func##n(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(n)); \ + } \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + UHC_MCUX_PHY_CONFIGURE(n) \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .base = (uint32_t) DT_INST_REG_ADDR(n), \ + .mcux_if = &mcux_ehci_usb_iface, \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, mcux_driver_preinit, NULL, \ + &uhc_data_##n, &priv_config_##n, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &mcux_uhc_api); + +DT_INST_FOREACH_STATUS_OKAY(UHC_MCUX_EHCI_DEVICE_DEFINE) + +#undef DT_DRV_COMPAT +#endif + +#ifdef CONFIG_USB_UHC_NXP_KHCI +#define DT_DRV_COMPAT nxp_uhc_khci + +#ifdef CONFIG_USB_UHC_NXP_PHY +#define UHC_MCUX_PHY_CONFIGURE(n) \ + .need_to_init_phy = 0u, +#else +#define UHC_MCUX_PHY_CONFIGURE(n) +#endif + +#define UHC_MCUX_KHCI_DEVICE_DEFINE(n) \ + static void uhc_irq_enable_func##n(const struct device *dev) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + uhc_mcux_khci_isr, \ + DEVICE_DT_INST_GET(n), 0); \ + \ + irq_enable(DT_INST_IRQN(n)); \ + } \ + \ + static void uhc_irq_disable_func##n(const struct device *dev) \ + { \ + irq_disable(DT_INST_IRQN(n)); \ + } \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + UHC_MCUX_PHY_CONFIGURE(n) \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .base = (uint32_t) DT_INST_REG_ADDR(n), \ + .mcux_if = &mcux_khci_usb_iface, \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, mcux_driver_preinit, NULL, \ + &uhc_data_##n, &priv_config_##n, \ + POST_KERNEL, \ + CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &mcux_uhc_api); + +DT_INST_FOREACH_STATUS_OKAY(UHC_MCUX_KHCI_DEVICE_DEFINE) +#endif diff --git a/modules/hal_nxp/CMakeLists.txt b/modules/hal_nxp/CMakeLists.txt index 2f2e53d22ea85..14525c502a340 100644 --- a/modules/hal_nxp/CMakeLists.txt +++ b/modules/hal_nxp/CMakeLists.txt @@ -1,5 +1,6 @@ # # Copyright (c) 2021 Linaro, Limited +# Copyright 2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -7,6 +8,10 @@ if(CONFIG_HAS_MCUX OR CONFIG_HAS_IMX_HAL OR CONFIG_HAS_NXP_S32_HAL) add_subdirectory(${ZEPHYR_CURRENT_MODULE_DIR} hal_nxp) add_subdirectory_ifdef(CONFIG_USB_DEVICE_DRIVER usb) + add_subdirectory_ifdef(CONFIG_UHC_DRIVER usb) + if (CONFIG_NXP_FSL_OSA) + zephyr_sources(fsl_os_abstraction_zephyr.c) + endif() zephyr_sources_ifdef(CONFIG_PWM_MCUX_CTIMER ${ZEPHYR_CURRENT_MODULE_DIR}/mcux/mcux-sdk/drivers/ctimer/fsl_ctimer.c) zephyr_include_directories_ifdef(CONFIG_PWM_MCUX_CTIMER @@ -22,5 +27,6 @@ if(CONFIG_HAS_MCUX OR CONFIG_HAS_IMX_HAL OR CONFIG_HAS_NXP_S32_HAL) if(CONFIG_NOCACHE_MEMORY) zephyr_compile_definitions_ifdef(CONFIG_USB_DEVICE_DRIVER DATA_SECTION_IS_CACHEABLE=1) + zephyr_compile_definitions_ifdef(CONFIG_UHC_DRIVER DATA_SECTION_IS_CACHEABLE=1) endif() endif() diff --git a/modules/hal_nxp/usb/CMakeLists.txt b/modules/hal_nxp/usb/CMakeLists.txt index 380aa3aef87af..aa0e2b2fbc125 100644 --- a/modules/hal_nxp/usb/CMakeLists.txt +++ b/modules/hal_nxp/usb/CMakeLists.txt @@ -1,6 +1,12 @@ # -# Copyright (c) 2021, NXP +# Copyright (c) 2021,2024 NXP # # SPDX-License-Identifier: Apache-2.0 # zephyr_include_directories(.) +if(CONFIG_USB_UHC_NXP_MCUX) +zephyr_include_directories(${ZEPHYR_BASE}/subsys/usb/host) +if(CONFIG_USB_UHC_NXP_PHY) +zephyr_include_directories(${ZEPHYR_HAL_NXP_MODULE_DIR}/mcux/middleware/mcux-sdk-middleware-usb/phy) +endif() +endif() diff --git a/modules/hal_nxp/usb/usb_host_config.h b/modules/hal_nxp/usb/usb_host_config.h new file mode 100644 index 0000000000000..c5be22b371733 --- /dev/null +++ b/modules/hal_nxp/usb/usb_host_config.h @@ -0,0 +1,43 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __USB_HOST_CONFIG_H__ +#define __USB_HOST_CONFIG_H__ + +#include +#include "usb.h" + +/****************************************************************************** + * Definitions + *****************************************************************************/ +/* EHCI instance count */ +#ifdef CONFIG_USB_UHC_NXP_EHCI +#define USB_HOST_CONFIG_EHCI (2U) +#define USB_HOST_CONFIG_EHCI_FRAME_LIST_SIZE (1024U) +#define USB_HOST_CONFIG_EHCI_MAX_QH (8U) +#define USB_HOST_CONFIG_EHCI_MAX_QTD (8U) +#define USB_HOST_CONFIG_EHCI_MAX_ITD (0U) +#define USB_HOST_CONFIG_EHCI_MAX_SITD (0U) +#endif /* CONFIG_USB_DC_NXP_EHCI */ + +#ifdef CONFIG_USB_UHC_NXP_KHCI +#define USB_HOST_CONFIG_KHCI (1U) +#define USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER (64U) +#endif /* CONFIG_USB_UHC_NXP_KHCI */ + +#define USB_HOST_CONFIG_MAX_HOST (USB_HOST_CONFIG_KHCI + USB_HOST_CONFIG_EHCI) + +#define USB_HOST_CONFIG_MAX_PIPES (16U) +#define USB_HOST_CONFIG_MAX_TRANSFERS (16U) +#define USB_HOST_CONFIG_INTERFACE_MAX_EP (4U) +#define USB_HOST_CONFIG_CONFIGURATION_MAX_INTERFACE (5U) +#define USB_HOST_CONFIG_MAX_POWER (250U) +#define USB_HOST_CONFIG_ENUMERATION_MAX_RETRIES (3U) +#define USB_HOST_CONFIG_ENUMERATION_MAX_STALL_RETRIES (1U) +#define USB_HOST_CONFIG_MAX_NAK (3000U) +#define USB_HOST_CONFIG_CLASS_AUTO_CLEAR_STALL (0U) + +#endif /* __USB_HOST_CONFIG_H__ */ diff --git a/west.yml b/west.yml index 4eee37fa81ac5..612cb48e38e5e 100644 --- a/west.yml +++ b/west.yml @@ -193,7 +193,7 @@ manifest: groups: - hal - name: hal_nxp - revision: f6c7108caf50684742689bfab838048208963f4f + revision: pull/327/head path: modules/hal/nxp groups: - hal From 3437c2de3e930c633b58116f5ef7f29f22a2f0fc Mon Sep 17 00:00:00 2001 From: Mark Wang Date: Wed, 20 Mar 2024 09:21:47 +0800 Subject: [PATCH 4/4] boards: nxp: add uhc suport for frdm_k22f and rt1060 - add uhc related items to dts. - add clock initialization - add BM4 if CONFIG_USB_UHC_NXP_KHCI is enabled Signed-off-by: Mark Wang --- boards/nxp/frdm_k22f/frdm_k22f.dts | 4 ++++ boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts | 24 ++++++++++++++++++++ include/zephyr/arch/arm/mpu/nxp_mpu.h | 2 +- soc/nxp/imxrt/imxrt10xx/soc.c | 10 ++++++-- soc/nxp/kinetis/k2x/soc.c | 2 +- 5 files changed, 38 insertions(+), 4 deletions(-) diff --git a/boards/nxp/frdm_k22f/frdm_k22f.dts b/boards/nxp/frdm_k22f/frdm_k22f.dts index e11db24edfcc1..573d424c2023f 100644 --- a/boards/nxp/frdm_k22f/frdm_k22f.dts +++ b/boards/nxp/frdm_k22f/frdm_k22f.dts @@ -174,6 +174,10 @@ zephyr_udc0: &usbotg { num-bidir-endpoints = <8>; }; +zephyr_uhc0: &uhc1 { + status = "okay"; +}; + &gpioa { status = "okay"; }; diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts index 7438f4b38b002..e79335e82b345 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dts @@ -187,6 +187,30 @@ zephyr_udc0: &usb1 { status = "okay"; }; +zephyr_uhc0: &uhc1 { + status = "okay"; + phy_handle = <&usbphy1>; +}; + +zephyr_uhc1: &uhc2 { + status = "okay"; + phy_handle = <&usbphy2>; +}; + +&usbphy1 { + status = "okay"; + d-cal = <12>; + txcal45dp = <6>; + txcal45dm = <6>; +}; + +&usbphy2 { + status = "okay"; + d-cal = <12>; + txcal45dp = <6>; + txcal45dm = <6>; +}; + &flexpwm2_pwm3 { status = "okay"; pinctrl-0 = <&pinmux_flexpwm2_3>; diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index b95565658027c..fa7bbba6f543b 100644 --- a/include/zephyr/arch/arm/mpu/nxp_mpu.h +++ b/include/zephyr/arch/arm/mpu/nxp_mpu.h @@ -34,7 +34,7 @@ #define BM4_WE_SHIFT 24 #define BM4_RE_SHIFT 25 -#if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS +#if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS || CONFIG_USB_UHC_NXP_KHCI #define BM4_PERMISSIONS ((1 << BM4_RE_SHIFT) | (1 << BM4_WE_SHIFT)) #else #define BM4_PERMISSIONS 0 diff --git a/soc/nxp/imxrt/imxrt10xx/soc.c b/soc/nxp/imxrt/imxrt10xx/soc.c index 0e4bae616a6af..2fe2edd581a5d 100644 --- a/soc/nxp/imxrt/imxrt10xx/soc.c +++ b/soc/nxp/imxrt/imxrt10xx/soc.c @@ -224,21 +224,27 @@ static ALWAYS_INLINE void clock_init(void) kIOMUXC_GPR_ENET2RefClkMode, true); #endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && \ + (CONFIG_USB_DC_NXP_EHCI || CONFIG_USB_UHC_NXP_EHCI) CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency)); CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency)); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI USB_EhciPhyInit(kUSB_ControllerEhci0, CPU_XTAL_CLK_HZ, &usbPhyConfig); #endif +#endif -#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) && CONFIG_USB_DC_NXP_EHCI +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb2), okay) && \ + (CONFIG_USB_DC_NXP_EHCI || CONFIG_USB_UHC_NXP_EHCI) CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency)); CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency)); +#if DT_NODE_HAS_STATUS(DT_NODELABEL(usb1), okay) && CONFIG_USB_DC_NXP_EHCI USB_EhciPhyInit(kUSB_ControllerEhci1, CPU_XTAL_CLK_HZ, &usbPhyConfig); #endif +#endif #if DT_NODE_HAS_STATUS(DT_NODELABEL(usdhc1), okay) && CONFIG_IMX_USDHC /* Configure USDHC clock source and divider */ diff --git a/soc/nxp/kinetis/k2x/soc.c b/soc/nxp/kinetis/k2x/soc.c index d5108fb49d905..82bc59a263226 100644 --- a/soc/nxp/kinetis/k2x/soc.c +++ b/soc/nxp/kinetis/k2x/soc.c @@ -102,7 +102,7 @@ static ALWAYS_INLINE void clock_init(void) CLOCK_SetSimConfig(&simConfig); -#if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS +#if CONFIG_USB_KINETIS || CONFIG_UDC_KINETIS || CONFIG_USB_UHC_NXP_KHCI CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcPll0, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); #endif