diff --git a/boards/nxp/frdm_k22f/frdm_k22f.dts b/boards/nxp/frdm_k22f/frdm_k22f.dts index 69439718a36d..74454a7d69f3 100644 --- a/boards/nxp/frdm_k22f/frdm_k22f.dts +++ b/boards/nxp/frdm_k22f/frdm_k22f.dts @@ -178,6 +178,10 @@ zephyr_udc0: &usbotg { num-bidir-endpoints = <8>; }; +zephyr_uhc0: &usbh { + status = "okay"; +}; + &gpioa { status = "okay"; }; diff --git a/boards/nxp/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi b/boards/nxp/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi index dbf467f3c166..f363d52a886c 100644 --- a/boards/nxp/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi +++ b/boards/nxp/lpcxpresso55s28/lpcxpresso55s28-pinctrl.dtsi @@ -46,4 +46,22 @@ }; }; + pinmux_usbhfs: pinmux_usbhfs { + group0 { + pinmux = , + , + ; + bias-pull-up; + slew-rate = "standard"; + }; + }; + + pinmux_usbhhs: pinmux_usbhhs { + group0 { + pinmux = , + ; + bias-pull-up; + slew-rate = "standard"; + }; + }; }; diff --git a/boards/nxp/lpcxpresso55s28/lpcxpresso55s28.dts b/boards/nxp/lpcxpresso55s28/lpcxpresso55s28.dts index a2407a2004ac..d9d46ed50ed1 100644 --- a/boards/nxp/lpcxpresso55s28/lpcxpresso55s28.dts +++ b/boards/nxp/lpcxpresso55s28/lpcxpresso55s28.dts @@ -127,3 +127,23 @@ zephyr_udc0: &usbhs { status = "okay"; }; + +zephyr_uhc0: &usbhfs { + pinctrl-0 = <&pinmux_usbhfs>; + pinctrl-names = "default"; + status = "okay"; +}; + +zephyr_uhc1: &usbhhs { + pinctrl-0 = <&pinmux_usbhhs>; + pinctrl-names = "default"; + status = "okay"; + phy_handle = <&usbphy1>; +}; + +&usbphy1 { + status = "okay"; + tx-d-cal = <5>; + tx-cal-45-dp-ohms = <10>; + tx-cal-45-dm-ohms = <10>; +}; diff --git a/boards/nxp/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi b/boards/nxp/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi index 969979363885..bbc196e7eab8 100644 --- a/boards/nxp/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi +++ b/boards/nxp/lpcxpresso55s69/lpcxpresso55s69-pinctrl.dtsi @@ -2,7 +2,7 @@ * NOTE: File generated by gen_board_pinctrl.py * from LPCXpresso55S69.mex * - * Copyright 2022 NXP + * Copyright 2022,2024 NXP * SPDX-License-Identifier: Apache-2.0 */ @@ -108,4 +108,23 @@ slew-rate = "standard"; }; }; + + pinmux_usbhfs: pinmux_usbhfs { + group0 { + pinmux = , + , + ; + bias-pull-up; + slew-rate = "standard"; + }; + }; + + pinmux_usbhhs: pinmux_usbhhs { + group0 { + pinmux = , + ; + bias-pull-up; + slew-rate = "standard"; + }; + }; }; diff --git a/boards/nxp/lpcxpresso55s69/lpcxpresso55s69_lpc55s69_cpu0.dts b/boards/nxp/lpcxpresso55s69/lpcxpresso55s69_lpc55s69_cpu0.dts index e87cb04fc799..aa4a06140747 100644 --- a/boards/nxp/lpcxpresso55s69/lpcxpresso55s69_lpc55s69_cpu0.dts +++ b/boards/nxp/lpcxpresso55s69/lpcxpresso55s69_lpc55s69_cpu0.dts @@ -155,6 +155,19 @@ zephyr_udc0: &usbhs { phy_handle = <&usbphy1>; }; +zephyr_uhc0: &usbhfs { + pinctrl-0 = <&pinmux_usbhfs>; + pinctrl-names = "default"; + status = "okay"; +}; + +zephyr_uhc1: &usbhhs { + pinctrl-0 = <&pinmux_usbhhs>; + pinctrl-names = "default"; + status = "okay"; + phy_handle = <&usbphy1>; +}; + &usbphy1 { status = "okay"; tx-d-cal = <5>; diff --git a/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dtsi b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dtsi index 3879b04cb506..707cc9606cba 100644 --- a/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dtsi +++ b/boards/nxp/mimxrt1050_evk/mimxrt1050_evk.dtsi @@ -210,6 +210,30 @@ zephyr_udc0: &usb1 { status = "okay"; }; +zephyr_uhc0: &usbh1 { + status = "okay"; + phy_handle = <&usbphy1>; +}; + +zephyr_uhc1: &usbh2 { + status = "okay"; + phy_handle = <&usbphy2>; +}; + +&usbphy1 { + status = "okay"; + tx-d-cal = <12>; + tx-cal-45-dp-ohms = <6>; + tx-cal-45-dm-ohms = <6>; +}; + +&usbphy2 { + status = "okay"; + tx-d-cal = <12>; + tx-cal-45-dp-ohms = <6>; + tx-cal-45-dm-ohms = <6>; +}; + &usdhc1 { status = "okay"; pwr-gpios = <&gpio1 5 GPIO_ACTIVE_HIGH>; diff --git a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dtsi b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dtsi index 84dbaac3ae4a..6356991c860c 100644 --- a/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dtsi +++ b/boards/nxp/mimxrt1060_evk/mimxrt1060_evk.dtsi @@ -188,6 +188,16 @@ zephyr_udc0: &usb1 { phy_handle = <&usbphy1>; }; +zephyr_uhc0: &usbh1 { + status = "okay"; + phy_handle = <&usbphy1>; +}; + +zephyr_uhc1: &usbh2 { + status = "okay"; + phy_handle = <&usbphy2>; +}; + &usbphy1 { status = "okay"; tx-d-cal = <12>; @@ -195,6 +205,13 @@ zephyr_udc0: &usb1 { tx-cal-45-dm-ohms = <6>; }; +&usbphy2 { + status = "okay"; + tx-d-cal = <12>; + tx-cal-45-dp-ohms = <6>; + tx-cal-45-dm-ohms = <6>; +}; + &csi { pinctrl-0 = <&pinmux_csi>; pinctrl-names = "default"; diff --git a/drivers/usb/udc/Kconfig.mcux b/drivers/usb/udc/Kconfig.mcux index be744a1122eb..019dc4f35685 100644 --- a/drivers/usb/udc/Kconfig.mcux +++ b/drivers/usb/udc/Kconfig.mcux @@ -7,6 +7,7 @@ config UDC_NXP_EHCI depends on DT_HAS_NXP_EHCI_ENABLED select PINCTRL select NOCACHE_MEMORY if HAS_MCUX_CACHE && CPU_HAS_DCACHE + select DYNAMIC_INTERRUPTS imply UDC_BUF_FORCE_NOCACHE imply UDC_WORKQUEUE help diff --git a/drivers/usb/udc/udc_mcux_ehci.c b/drivers/usb/udc/udc_mcux_ehci.c index 179e9282b18f..612626523d79 100644 --- a/drivers/usb/udc/udc_mcux_ehci.c +++ b/drivers/usb/udc/udc_mcux_ehci.c @@ -871,10 +871,10 @@ static usb_phy_config_struct_t phy_config_##n = { \ \ static void udc_irq_enable_func##n(const struct device *dev) \ { \ - IRQ_CONNECT(DT_INST_IRQN(n), \ - DT_INST_IRQ(n, priority), \ - udc_mcux_isr, \ - DEVICE_DT_INST_GET(n), 0); \ + irq_connect_dynamic(DT_INST_IRQN(n), \ + DT_INST_IRQ(n, priority), \ + (void (*)(const void *))udc_mcux_isr, \ + DEVICE_DT_INST_GET(n), 0); \ \ irq_enable(DT_INST_IRQN(n)); \ } \ diff --git a/drivers/usb/uhc/CMakeLists.txt b/drivers/usb/uhc/CMakeLists.txt index 7f38ffd31464..69f1cea8433b 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,7 @@ 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_UHC_NXP_EHCI uhc_mcux_common.c uhc_mcux_ehci.c) +zephyr_library_sources_ifdef(CONFIG_UHC_NXP_KHCI uhc_mcux_common.c uhc_mcux_khci.c) +zephyr_library_sources_ifdef(CONFIG_UHC_NXP_OHCI uhc_mcux_common.c uhc_mcux_ohci.c) +zephyr_library_sources_ifdef(CONFIG_UHC_NXP_IP3516HS uhc_mcux_common.c uhc_mcux_ip3516hs.c) diff --git a/drivers/usb/uhc/Kconfig b/drivers/usb/uhc/Kconfig index e6da1d4d3dff..052e9437f6ae 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 000000000000..d772a36f2d3c --- /dev/null +++ b/drivers/usb/uhc/Kconfig.mcux @@ -0,0 +1,47 @@ +# Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +config UHC_NXP_EHCI + bool "NXP MCUX USB EHCI Host controller driver" + default y + depends on DT_HAS_NXP_UHC_EHCI_ENABLED + select EVENTS + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + select DYNAMIC_INTERRUPTS + help + NXP MCUX USB Host Controller Driver for EHCI. + +config UHC_NXP_KHCI + bool "NXP MCUX USB KHCI Host controller driver" + default y + depends on DT_HAS_NXP_UHC_KHCI_ENABLED + select EVENTS + help + NXP MCUX USB Host Controller Driver for KHCI. + +config UHC_NXP_IP3516HS + bool "NXP MCUX USB IP3516HS Host controller driver" + default y + depends on DT_HAS_NXP_UHC_IP3516HS_ENABLED + select EVENTS + select NOCACHE_MEMORY if ARCH_HAS_NOCACHE_MEMORY_SUPPORT + help + NXP MCUX USB Host Controller Driver for ip3516hs. + +config UHC_NXP_OHCI + bool "NXP MCUX USB IP3516HS Host controller driver" + default y + depends on DT_HAS_NXP_UHC_OHCI_ENABLED + select EVENTS + help + NXP MCUX USB Host Controller Driver for ohci. + +config HEAP_MEM_POOL_ADD_SIZE_UHC_MCUX + int "The heap that NXP hal usb host controller drivers need" + default 4096 + +config UHC_NXP_THREAD_STACK_SIZE + int "MCUX UHC Driver internal thread stack size" + default 2048 + help + Size of the stack used in the driver. diff --git a/drivers/usb/uhc/uhc_mcux_common.c b/drivers/usb/uhc/uhc_mcux_common.c new file mode 100644 index 000000000000..e5a5993c2e8d --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_common.c @@ -0,0 +1,252 @@ +/* + * 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 "uhc_mcux_common.h" + +#include +LOG_MODULE_REGISTER(uhc_mcux, CONFIG_UHC_DRIVER_LOG_LEVEL); + +#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct uhc_mcux_data, mcux_host) + +int uhc_mcux_lock(const struct device *dev) +{ + struct uhc_data *data = dev->data; + + return k_mutex_lock(&data->mutex, K_FOREVER); +} + +int uhc_mcux_unlock(const struct device *dev) +{ + struct uhc_data *data = dev->data; + + return k_mutex_unlock(&data->mutex); +} + +int uhc_mcux_control(const struct device *dev, uint32_t control, void *param) +{ + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_status_t status; + + status = priv->mcux_if->controllerIoctl(priv->mcux_host.controllerHandle, control, param); + if (status != kStatus_USB_Success) { + return -EIO; + } + + return 0; +} + +int uhc_mcux_bus_control(const struct device *dev, usb_host_bus_control_t type) +{ + return uhc_mcux_control(dev, kUSB_HostBusControl, &type); +} + +/* Controller driver calls this function when device attach. */ +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)); + uhc_submit_event(priv->dev, type, 0); + + return kStatus_USB_Success; +} + +/* Controller driver calls this function when device detaches. */ +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; +} + +/* MCUX Controller driver calls this function to get the device information. */ +usb_status_t USB_HostHelperGetPeripheralInformation(usb_device_handle deviceHandle, + uint32_t infoCode, uint32_t *infoValue) +{ + /* The deviceHandle is struct uhc_transfer because Zephyr environment doesn't allow + * to call upper layer API to get usb device information from controller driver. + * The device information should be able to obtain from the struct uhc_transfer. + */ + struct uhc_transfer *const xfer = (struct uhc_transfer *const)deviceHandle; + usb_host_dev_info_t info_code; + + if ((deviceHandle == NULL) || (infoValue == NULL)) { + return kStatus_USB_InvalidParameter; + } + info_code = (usb_host_dev_info_t)infoCode; + switch (info_code) { + case kUSB_HostGetDeviceAddress: + *infoValue = (uint8_t)xfer->addr; + break; + + case kUSB_HostGetDeviceHubNumber: + case kUSB_HostGetDevicePortNumber: + case kUSB_HostGetDeviceHSHubNumber: + case kUSB_HostGetDeviceHSHubPort: + case kUSB_HostGetHubThinkTime: + *infoValue = 0; + break; + case kUSB_HostGetDeviceLevel: + *infoValue = 1; + break; + + case kUSB_HostGetDeviceSpeed: + /* TODO: workaround. current stack doesn't support to + * get spped from controller driver. + */ + *infoValue = UHC_EVT_DEV_CONNECTED_HS; + break; + + default: + break; + } + + return kStatus_USB_Success; +} + +static usb_host_pipe_handle uhc_mcux_get_hal_ep(struct uhc_mcux_data *priv, void *udev, uint8_t ep) +{ + usb_host_pipe_handle mcux_ep_handle = NULL; + + /* if already initialized */ + for (uint8_t i = 0; i < USB_HOST_CONFIG_MAX_PIPES; i++) { + uint8_t mcux_ep = ep; + + if (mcux_ep == USB_CONTROL_EP_IN) { + mcux_ep = 0; + } + + if ((priv->ep_handles[i].mcux_ep_handle != NULL) && + (priv->ep_handles[i].ep == mcux_ep) && (priv->ep_handles[i].udev == udev)) { + mcux_ep_handle = priv->ep_handles[i].mcux_ep_handle; + break; + } + } + + return mcux_ep_handle; +} + +usb_host_pipe_handle uhc_mcux_init_hal_ep(const struct device *dev, struct uhc_transfer *const xfer) +{ + usb_status_t status; + usb_host_pipe_handle mcux_ep_handle = NULL; + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_host_pipe_init_t pipe_init; + uint8_t i; + + /* if already initialized */ + mcux_ep_handle = uhc_mcux_get_hal_ep(priv, xfer->udev, xfer->ep); + if (mcux_ep_handle != NULL) { + return mcux_ep_handle; + } + + /* Initialize mcux hal endpoint pipe + * TODO: Need one way to release the pipe. + * Otherwise the priv->ep_handles will be used up after + * supporting hub and connecting/disconnecting multiple times. + * For example: add endpoint/pipe init and de-init controller + * interafce to resolve the issue. + */ + for (i = 0; i < USB_HOST_CONFIG_MAX_PIPES; i++) { + if (priv->ep_handles[i].mcux_ep_handle == NULL) { + break; + } + } + + if (i >= USB_HOST_CONFIG_MAX_PIPES) { + return NULL; + } + + /* USB_HostHelperGetPeripheralInformation uses this value as first parameter */ + pipe_init.devInstance = xfer; + pipe_init.nakCount = USB_HOST_CONFIG_MAX_NAK; + pipe_init.maxPacketSize = xfer->mps; + pipe_init.endpointAddress = USB_EP_GET_IDX(xfer->ep); + pipe_init.direction = USB_EP_GET_DIR(xfer->ep) ? USB_IN : 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 (pipe_init.endpointAddress == 0) { + pipe_init.pipeType = USB_ENDPOINT_CONTROL; + } else { + pipe_init.pipeType = USB_ENDPOINT_BULK; + } + + status = priv->mcux_if->controllerOpenPipe(priv->mcux_host.controllerHandle, + &mcux_ep_handle, &pipe_init); + + if (status != kStatus_USB_Success) { + return NULL; + } + priv->ep_handles[i].mcux_ep_handle = mcux_ep_handle; + priv->ep_handles[i].udev = xfer->udev; + + return mcux_ep_handle; +} + +int uhc_mcux_hal_init_transfer_common(const struct device *dev, usb_host_transfer_t *mcux_xfer, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer, + host_inner_transfer_callback_t cb) +{ + /* USB_HostHelperGetPeripheralInformation uses this value as first parameter */ + ((usb_host_pipe_t *)mcux_ep_handle)->deviceHandle = xfer; + 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 = cb; + mcux_xfer->callbackParam = (void *)dev; + mcux_xfer->setupPacket = (usb_setup_struct_t *)&xfer->setup_pkt[0]; + if (xfer->buf != NULL) { + mcux_xfer->transferLength = xfer->buf->size; + mcux_xfer->transferBuffer = xfer->buf->__buf; + } else { + mcux_xfer->transferBuffer = NULL; + mcux_xfer->transferLength = 0; + } + + if (USB_EP_GET_IDX(xfer->ep) == 0) { + mcux_xfer->direction = USB_REQTYPE_GET_DIR(mcux_xfer->setupPacket->bmRequestType) + ? USB_IN + : USB_OUT; + } + + return 0; +} diff --git a/drivers/usb/uhc/uhc_mcux_common.h b/drivers/usb/uhc/uhc_mcux_common.h new file mode 100644 index 000000000000..4d6533f9abd0 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_common.h @@ -0,0 +1,47 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef ZEPHYR_INCLUDE_UHC_MCUX_COMMON_H +#define ZEPHYR_INCLUDE_UHC_MCUX_COMMON_H + +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; + const usb_host_controller_interface_t *mcux_if; + struct uhc_mcux_ep_handle ep_handles[USB_HOST_CONFIG_MAX_PIPES]; + usb_host_instance_t mcux_host; + struct k_thread drv_stack_data; + uint8_t controller_id; /* MCUX hal controller id, 0xFF is invalid value */ +}; + +/* call MCUX HAL controller driver to control controller */ +int uhc_mcux_control(const struct device *dev, uint32_t control, void *param); + +/* call MCUX HAL controller driver to control controller */ +int uhc_mcux_bus_control(const struct device *dev, usb_host_bus_control_t type); + +/* MCUX controller driver common lock function */ +int uhc_mcux_lock(const struct device *dev); + +/* MCUX controller driver common unlock function */ +int uhc_mcux_unlock(const struct device *dev); + +/* Initialize endpoint for MCUX HAL driver */ +usb_host_pipe_handle uhc_mcux_init_hal_ep(const struct device *dev, + struct uhc_transfer *const xfer); + +/* Initialize transfer for MCUX HAL driver */ +int uhc_mcux_hal_init_transfer_common(const struct device *dev, usb_host_transfer_t *mcux_xfer, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer, + host_inner_transfer_callback_t cb); + +#endif /* ZEPHYR_INCLUDE_UHC_MCUX_COMMON_H */ diff --git a/drivers/usb/uhc/uhc_mcux_ehci.c b/drivers/usb/uhc/uhc_mcux_ehci.c new file mode 100644 index 000000000000..e792d9367e65 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_ehci.c @@ -0,0 +1,427 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_uhc_ehci + +#include +#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 "uhc_mcux_common.h" +#include "usb_host_ehci.h" +#include "usb_phy.h" + +#include +LOG_MODULE_DECLARE(uhc_mcux); + +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, mcux_host) + +struct uhc_mcux_config { + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); + uintptr_t base; + usb_phy_config_struct_t *phy_config; + k_thread_stack_t *drv_stack; + const struct pinctrl_dev_config *pincfg; +}; + +#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 void uhc_mcux_thread(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + while (true) { + USB_HostEhciTaskFunction((void *)(&priv->mcux_host)); + } +} + +static void uhc_mcux_isr(const struct device *dev) +{ + struct uhc_mcux_data *priv = uhc_get_private(dev); + + USB_HostEhciIsrFunction((void *)(&priv->mcux_host)); +} + +/* MCUX controller dirver uses this callback to notify upper layer suspend related event */ +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; +} + +static int uhc_mcux_init(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_mcux_data *priv = uhc_get_private(dev); + k_thread_entry_t thread_entry = NULL; + usb_status_t status; + + if ((priv->controller_id >= kUSB_ControllerEhci0) && + (priv->controller_id <= kUSB_ControllerEhci1)) { + thread_entry = uhc_mcux_thread; + } + + if (thread_entry == NULL) { + return -ENOMEM; + } + +#ifdef CONFIG_DT_HAS_NXP_USBPHY_ENABLED + if (config->phy_config != NULL) { + USB_EhciPhyInit(priv->controller_id, 0u, config->phy_config); + } +#endif + + priv->dev = dev; + /* Init MCUX USB host driver. */ + priv->mcux_host.deviceCallback = mcux_host_callback; + status = priv->mcux_if->controllerCreate(priv->controller_id, &priv->mcux_host, + &(priv->mcux_host.controllerHandle)); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + + /* Create MCUX USB host driver task */ + k_thread_create(&priv->drv_stack_data, config->drv_stack, CONFIG_UHC_NXP_THREAD_STACK_SIZE, + thread_entry, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); + k_thread_name_set(&priv->drv_stack_data, "uhc_mcux_ehci"); + + return 0; +} + +static int uhc_mcux_enable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + config->irq_enable_func(dev); + + return 0; +} + +static int uhc_mcux_disable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + 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_mcux_data *priv = uhc_get_private(dev); + + config->irq_disable_func(dev); + k_thread_abort(&priv->drv_stack_data); + priv->mcux_if->controllerDestory(priv->mcux_host.controllerHandle); + + return 0; +} + +/* Signal bus reset, 50ms SE0 signal */ +static int uhc_mcux_bus_reset(const struct device *dev) +{ + int ret; + + ret = uhc_mcux_bus_control(dev, kUSB_HostBusReset); + if (ret == 0) { + ret = uhc_mcux_bus_control(dev, kUSB_HostBusRestart); + } + + 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); +} + +/* MCUX hal controller driver transfer callback */ +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); + int err = -EIO; + + if (status == kStatus_USB_Success) { + err = 0; + + if ((xfer->ep == 0) && (transfer->setupPacket->bRequest == USB_SREQ_SET_ADDRESS)) { + usb_host_pipe_handle mcux_ep_handle; + + /* set address to let USB_HostHelperGetPeripheralInformation get right value + */ + xfer->addr = (uint8_t)transfer->setupPacket->wValue; + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle != NULL) { + uhc_mcux_control(dev, kUSB_HostUpdateControlEndpointAddress, + mcux_ep_handle); + } + } + } + +#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 usb_host_transfer_t *uhc_mcux_hal_init_transfer(const struct device *dev, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer) +{ + usb_host_transfer_t *mcux_xfer; + + if (k_mem_slab_alloc(&mcux_uhc_transfer_pool, (void **)&mcux_xfer, K_NO_WAIT)) { + return NULL; + } + (void)uhc_mcux_hal_init_transfer_common(dev, mcux_xfer, mcux_ep_handle, xfer, + uhc_mcux_transfer_callback); +#if defined(CONFIG_NOCACHE_MEMORY) + mcux_xfer->setupPacket = uhc_mcux_nocache_alloc(8u); + memcpy(mcux_xfer->setupPacket, xfer->setup_pkt, 8u); + if (xfer->buf != NULL) { + mcux_xfer->transferBuffer = uhc_mcux_nocache_alloc(mcux_xfer->transferLength); + } +#endif + + return mcux_xfer; +} + +static int uhc_mcux_enqueue(const struct device *dev, struct uhc_transfer *const xfer) +{ + usb_host_pipe_handle mcux_ep_handle; + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_status_t status; + usb_host_transfer_t *mcux_xfer; + + uhc_xfer_append(dev, xfer); + + /* firstly check and init the mcux endpoint handle */ + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle == NULL) { + return -ENOMEM; + } + + /* Initialize MCUX hal transfer. */ + mcux_xfer = uhc_mcux_hal_init_transfer(dev, mcux_ep_handle, xfer); + if (mcux_xfer == NULL) { + return -ENOMEM; + } + + uhc_mcux_lock(dev); + /* give the transfer to MCUX drv. */ + status = priv->mcux_if->controllerWritePipe(priv->mcux_host.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 inline void uhc_mcux_get_hal_driver_id(struct uhc_mcux_data *priv, + const struct uhc_mcux_config *config) +{ + /* + * MCUX USB controller drivers use an ID to tell the HAL drivers + * which controller is being used. This part of the code converts + * the base address to the ID value. + */ +#if defined(USBHS_STACK_BASE_ADDRS) + uintptr_t usb_base_addrs[] = USBHS_STACK_BASE_ADDRS; +#else + uintptr_t usb_base_addrs[] = USBHS_BASE_ADDRS; +#endif + + /* get the right controller id */ + priv->controller_id = 0xFFu; /* invalid value */ + for (uint8_t i = 0; i < ARRAY_SIZE(usb_base_addrs); i++) { + if (usb_base_addrs[i] == config->base) { + priv->controller_id = kUSB_ControllerEhci0 + i; + break; + } + } +} + +static int uhc_mcux_driver_preinit(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + uhc_mcux_get_hal_driver_id(priv, config); + if (priv->controller_id == 0xFFu) { + return -ENOMEM; + } + + k_mutex_init(&data->mutex); + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + LOG_DBG("MCUX controller initialized"); + + 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 const usb_host_controller_interface_t uhc_mcux_if = { + USB_HostEhciCreate, USB_HostEhciDestory, USB_HostEhciOpenPipe, USB_HostEhciClosePipe, + USB_HostEhciWritePipe, USB_HostEhciReadpipe, USB_HostEhciIoctl, +}; + +#define UHC_MCUX_PHY_DEFINE(n) \ + static usb_phy_config_struct_t phy_config_##n = { \ + .D_CAL = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_d_cal, 0), \ + .TXCAL45DP = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_cal_45_dp_ohms, 0), \ + .TXCAL45DM = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_cal_45_dm_ohms, 0), \ + } + +#define UHC_MCUX_PHY_DEFINE_OR(n) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), phy_handle), (UHC_MCUX_PHY_DEFINE(n)), ()) + +#define UHC_MCUX_PHY_CFG_PTR_OR_NULL(n) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), phy_handle), (&phy_config_##n), (NULL)) + +#define UHC_MCUX_EHCI_DEVICE_DEFINE(n) \ + UHC_MCUX_PHY_DEFINE_OR(n); \ + \ + static void uhc_irq_enable_func##n(const struct device *dev) \ + { \ + irq_connect_dynamic(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \ + (void (*)(const void *))uhc_mcux_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 K_KERNEL_STACK_DEFINE(drv_stack_##n, CONFIG_UHC_NXP_THREAD_STACK_SIZE); \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .phy_config = UHC_MCUX_PHY_CFG_PTR_OR_NULL(n), \ + .drv_stack = drv_stack_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + .mcux_if = &uhc_mcux_if, \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uhc_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) diff --git a/drivers/usb/uhc/uhc_mcux_ip3516hs.c b/drivers/usb/uhc/uhc_mcux_ip3516hs.c new file mode 100644 index 000000000000..7e0a2403b863 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_ip3516hs.c @@ -0,0 +1,380 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_uhc_ip3516hs + +#include +#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 "uhc_mcux_common.h" +#include "usb_host_ip3516hs.h" +#include "usb_phy.h" + +#include +LOG_MODULE_DECLARE(uhc_mcux); + +K_MEM_SLAB_DEFINE_STATIC(mcux_uhc_transfer_pool, sizeof(usb_host_transfer_t), + USB_HOST_CONFIG_MAX_TRANSFERS, sizeof(void *)); + +#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct uhc_mcux_data, mcux_host) + +struct uhc_mcux_config { + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); + uintptr_t base; + usb_phy_config_struct_t *phy_config; + k_thread_stack_t *drv_stack; + const struct pinctrl_dev_config *pincfg; +}; + +static void uhc_mcux_thread(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + while (true) { + USB_HostIp3516HsTaskFunction((void *)(&priv->mcux_host)); + } +} + +static void uhc_mcux_isr(const struct device *dev) +{ + struct uhc_mcux_data *priv = uhc_get_private(dev); + + USB_HostIp3516HsIsrFunction((void *)(&priv->mcux_host)); +} + +/* MCUX controller dirver uses this callback to notify upper layer suspend related event */ +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; +} + +static int uhc_mcux_init(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_mcux_data *priv = uhc_get_private(dev); + k_thread_entry_t thread_entry = NULL; + usb_status_t status; + + if ((priv->controller_id >= kUSB_ControllerIp3516Hs0) && + (priv->controller_id <= kUSB_ControllerIp3516Hs1)) { + thread_entry = uhc_mcux_thread; + } + + if (thread_entry == NULL) { + return -ENOMEM; + } + +#ifdef CONFIG_DT_HAS_NXP_USBPHY_ENABLED + if (config->phy_config != NULL) { + USB_EhciPhyInit(priv->controller_id, 0u, config->phy_config); + } +#endif + + priv->dev = dev; + /* Init MCUX USB host driver. */ + priv->mcux_host.deviceCallback = mcux_host_callback; + status = priv->mcux_if->controllerCreate(priv->controller_id, &priv->mcux_host, + &(priv->mcux_host.controllerHandle)); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + + /* Create MCUX USB host driver task */ + k_thread_create(&priv->drv_stack_data, config->drv_stack, CONFIG_UHC_NXP_THREAD_STACK_SIZE, + thread_entry, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); + k_thread_name_set(&priv->drv_stack_data, "uhc_mcux_ip3516hs"); + + return 0; +} + +static int uhc_mcux_enable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + config->irq_enable_func(dev); + + return 0; +} + +static int uhc_mcux_disable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + 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_mcux_data *priv = uhc_get_private(dev); + + config->irq_disable_func(dev); + k_thread_abort(&priv->drv_stack_data); + priv->mcux_if->controllerDestory(priv->mcux_host.controllerHandle); + + return 0; +} + +/* Signal bus reset, 50ms SE0 signal */ +static int uhc_mcux_bus_reset(const struct device *dev) +{ + int ret; + + ret = uhc_mcux_bus_control(dev, kUSB_HostBusReset); + if (ret == 0) { + ret = uhc_mcux_bus_control(dev, kUSB_HostBusRestart); + } + + 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); +} + +/* MCUX hal controller driver transfer callback */ +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); + int err = -EIO; + + if (status == kStatus_USB_Success) { + err = 0; + + if ((xfer->ep == 0) && (transfer->setupPacket->bRequest == USB_SREQ_SET_ADDRESS)) { + usb_host_pipe_handle mcux_ep_handle; + + /* set address to let USB_HostHelperGetPeripheralInformation get right value + */ + xfer->addr = (uint8_t)transfer->setupPacket->wValue; + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle != NULL) { + uhc_mcux_control(dev, kUSB_HostUpdateControlEndpointAddress, + mcux_ep_handle); + } + } + } + + if ((xfer->buf != NULL) && (transfer->transferBuffer != NULL)) { + if (transfer->transferSofar > 0) { + net_buf_add(xfer->buf, transfer->transferSofar); + } + } + + transfer->setupPacket = NULL; + transfer->transferBuffer = NULL; + k_mem_slab_free(&mcux_uhc_transfer_pool, transfer); + uhc_xfer_return(dev, xfer, err); +} + +static usb_host_transfer_t *uhc_mcux_hal_init_transfer(const struct device *dev, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer) +{ + usb_host_transfer_t *mcux_xfer; + + if (k_mem_slab_alloc(&mcux_uhc_transfer_pool, (void **)&mcux_xfer, K_NO_WAIT)) { + return NULL; + } + (void)uhc_mcux_hal_init_transfer_common(dev, mcux_xfer, mcux_ep_handle, xfer, + uhc_mcux_transfer_callback); + + return mcux_xfer; +} + +static int uhc_mcux_enqueue(const struct device *dev, struct uhc_transfer *const xfer) +{ + usb_host_pipe_handle mcux_ep_handle; + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_status_t status; + usb_host_transfer_t *mcux_xfer; + + uhc_xfer_append(dev, xfer); + + /* firstly check and init the mcux endpoint handle */ + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle == NULL) { + return -ENOMEM; + } + + /* Initialize MCUX hal transfer. */ + mcux_xfer = uhc_mcux_hal_init_transfer(dev, mcux_ep_handle, xfer); + if (mcux_xfer == NULL) { + return -ENOMEM; + } + + uhc_mcux_lock(dev); + /* give the transfer to MCUX drv. */ + status = priv->mcux_if->controllerWritePipe(priv->mcux_host.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 inline void uhc_mcux_get_hal_driver_id(struct uhc_mcux_data *priv, + const struct uhc_mcux_config *config) +{ + /* + * MCUX USB controller drivers use an ID to tell the HAL drivers + * which controller is being used. This part of the code converts + * the base address to the ID value. + */ + uintptr_t usb_base_addrs[] = USBHSH_BASE_ADDRS; + + /* get the right controller id */ + priv->controller_id = 0xFFu; /* invalid value */ + for (uint8_t i = 0; i < ARRAY_SIZE(usb_base_addrs); i++) { + if (usb_base_addrs[i] == config->base) { + priv->controller_id = kUSB_ControllerIp3516Hs0 + i; + break; + } + } +} + +static int uhc_mcux_driver_preinit(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + uhc_mcux_get_hal_driver_id(priv, config); + if (priv->controller_id == 0xFFu) { + return -ENOMEM; + } + + k_mutex_init(&data->mutex); + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + LOG_DBG("MCUX controller initialized"); + + 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 const usb_host_controller_interface_t uhc_mcux_if = { + USB_HostIp3516HsCreate, USB_HostIp3516HsDestory, USB_HostIp3516HsOpenPipe, + USB_HostIp3516HsClosePipe, USB_HostIp3516HsWritePipe, USB_HostIp3516HsReadPipe, + USB_HostIp3516HsIoctl, +}; + +#define UHC_MCUX_PHY_DEFINE(n) \ + static usb_phy_config_struct_t phy_config_##n = { \ + .D_CAL = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_d_cal, 0), \ + .TXCAL45DP = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_cal_45_dp_ohms, 0), \ + .TXCAL45DM = DT_PROP_OR(DT_INST_PHANDLE(n, phy_handle), tx_cal_45_dm_ohms, 0), \ + } + +#define UHC_MCUX_PHY_DEFINE_OR(n) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), phy_handle), (UHC_MCUX_PHY_DEFINE(n)), ()) + +#define UHC_MCUX_PHY_CFG_PTR_OR_NULL(n) \ + COND_CODE_1(DT_NODE_HAS_PROP(DT_DRV_INST(n), phy_handle), (&phy_config_##n), (NULL)) + +#define UHC_MCUX_IP3516HS_DEVICE_DEFINE(n) \ + UHC_MCUX_PHY_DEFINE_OR(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_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 K_KERNEL_STACK_DEFINE(drv_stack_##n, CONFIG_UHC_NXP_THREAD_STACK_SIZE); \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .phy_config = UHC_MCUX_PHY_CFG_PTR_OR_NULL(n), \ + .drv_stack = drv_stack_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + .mcux_if = &uhc_mcux_if, \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uhc_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_IP3516HS_DEVICE_DEFINE) diff --git a/drivers/usb/uhc/uhc_mcux_khci.c b/drivers/usb/uhc/uhc_mcux_khci.c new file mode 100644 index 000000000000..e85b6af599a2 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_khci.c @@ -0,0 +1,355 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_uhc_khci + +#include +#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 "uhc_mcux_common.h" +#include "usb_host_khci.h" + +#include +LOG_MODULE_DECLARE(uhc_mcux); + +K_MEM_SLAB_DEFINE_STATIC(mcux_uhc_transfer_pool, sizeof(usb_host_transfer_t), + USB_HOST_CONFIG_MAX_TRANSFERS, sizeof(void *)); + +#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct uhc_mcux_data, mcux_host) + +struct uhc_mcux_config { + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); + uintptr_t base; + k_thread_stack_t *drv_stack; + const struct pinctrl_dev_config *pincfg; +}; + +static void uhc_mcux_thread(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + while (true) { + USB_HostKhciTaskFunction((void *)(&priv->mcux_host)); + } +} + +static void uhc_mcux_isr(const struct device *dev) +{ + struct uhc_mcux_data *priv = uhc_get_private(dev); + + USB_HostKhciIsrFunction((void *)(&priv->mcux_host)); +} + +/* MCUX controller dirver uses this callback to notify upper layer suspend related event */ +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; +} + +static int uhc_mcux_init(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_mcux_data *priv = uhc_get_private(dev); + k_thread_entry_t thread_entry = NULL; + usb_status_t status; + + if ((priv->controller_id >= kUSB_ControllerKhci0) && + (priv->controller_id <= kUSB_ControllerKhci1)) { + thread_entry = uhc_mcux_thread; + } + + if (thread_entry == NULL) { + return -ENOMEM; + } + + priv->dev = dev; + /* Init MCUX USB host driver. */ + priv->mcux_host.deviceCallback = mcux_host_callback; + status = priv->mcux_if->controllerCreate(priv->controller_id, &priv->mcux_host, + &(priv->mcux_host.controllerHandle)); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + + /* Create MCUX USB host driver task */ + k_thread_create(&priv->drv_stack_data, config->drv_stack, CONFIG_UHC_NXP_THREAD_STACK_SIZE, + thread_entry, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); + k_thread_name_set(&priv->drv_stack_data, "uhc_mcux_khci"); + + return 0; +} + +static int uhc_mcux_enable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + config->irq_enable_func(dev); + + return 0; +} + +static int uhc_mcux_disable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + 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_mcux_data *priv = uhc_get_private(dev); + + config->irq_disable_func(dev); + k_thread_abort(&priv->drv_stack_data); + priv->mcux_if->controllerDestory(priv->mcux_host.controllerHandle); + + return 0; +} + +/* Signal bus reset, 50ms SE0 signal */ +static int uhc_mcux_bus_reset(const struct device *dev) +{ + int ret; + + ret = uhc_mcux_bus_control(dev, kUSB_HostBusReset); + if (ret == 0) { + ret = uhc_mcux_bus_control(dev, kUSB_HostBusRestart); + } + + 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); +} + +/* MCUX hal controller driver transfer callback */ +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); + int err = -EIO; + + if (status == kStatus_USB_Success) { + err = 0; + + if ((xfer->ep == 0) && (transfer->setupPacket->bRequest == USB_SREQ_SET_ADDRESS)) { + usb_host_pipe_handle mcux_ep_handle; + + /* set address to let USB_HostHelperGetPeripheralInformation get right value + */ + xfer->addr = (uint8_t)transfer->setupPacket->wValue; + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle != NULL) { + uhc_mcux_control(dev, kUSB_HostUpdateControlEndpointAddress, + mcux_ep_handle); + } + } + } + + if ((xfer->buf != NULL) && (transfer->transferBuffer != NULL)) { + if (transfer->transferSofar > 0) { + net_buf_add(xfer->buf, transfer->transferSofar); + } + } + + transfer->setupPacket = NULL; + transfer->transferBuffer = NULL; + k_mem_slab_free(&mcux_uhc_transfer_pool, transfer); + uhc_xfer_return(dev, xfer, err); +} + +static usb_host_transfer_t *uhc_mcux_hal_init_transfer(const struct device *dev, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer) +{ + usb_host_transfer_t *mcux_xfer; + + if (k_mem_slab_alloc(&mcux_uhc_transfer_pool, (void **)&mcux_xfer, K_NO_WAIT)) { + return NULL; + } + (void)uhc_mcux_hal_init_transfer_common(dev, mcux_xfer, mcux_ep_handle, xfer, + uhc_mcux_transfer_callback); + + return mcux_xfer; +} + +static int uhc_mcux_enqueue(const struct device *dev, struct uhc_transfer *const xfer) +{ + usb_host_pipe_handle mcux_ep_handle; + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_status_t status; + usb_host_transfer_t *mcux_xfer; + + uhc_xfer_append(dev, xfer); + + /* firstly check and init the mcux endpoint handle */ + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle == NULL) { + return -ENOMEM; + } + + /* Initialize MCUX hal transfer. */ + mcux_xfer = uhc_mcux_hal_init_transfer(dev, mcux_ep_handle, xfer); + if (mcux_xfer == NULL) { + return -ENOMEM; + } + + uhc_mcux_lock(dev); + /* give the transfer to MCUX drv. */ + status = priv->mcux_if->controllerWritePipe(priv->mcux_host.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 inline void uhc_mcux_get_hal_driver_id(struct uhc_mcux_data *priv, + const struct uhc_mcux_config *config) +{ + /* + * MCUX USB controller drivers use an ID to tell the HAL drivers + * which controller is being used. This part of the code converts + * the base address to the ID value. + */ + uintptr_t usb_base_addrs[] = USB_BASE_ADDRS; + + /* get the right controller id */ + priv->controller_id = 0xFFu; /* invalid value */ + for (uint8_t i = 0; i < ARRAY_SIZE(usb_base_addrs); i++) { + if (usb_base_addrs[i] == config->base) { + priv->controller_id = kUSB_ControllerKhci0 + i; + break; + } + } +} + +static int uhc_mcux_driver_preinit(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + uhc_mcux_get_hal_driver_id(priv, config); + if (priv->controller_id == 0xFFu) { + return -ENOMEM; + } + + k_mutex_init(&data->mutex); + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + LOG_DBG("MCUX controller initialized"); + + 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 const usb_host_controller_interface_t uhc_mcux_if = { + USB_HostKhciCreate, USB_HostKhciDestory, USB_HostKhciOpenPipe, USB_HostKhciClosePipe, + USB_HostKhciWritePipe, USB_HostKhciReadpipe, USB_HostKciIoctl, +}; + +#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_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 K_KERNEL_STACK_DEFINE(drv_stack_##n, CONFIG_UHC_NXP_THREAD_STACK_SIZE); \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .drv_stack = drv_stack_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + .mcux_if = &uhc_mcux_if, \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uhc_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) diff --git a/drivers/usb/uhc/uhc_mcux_ohci.c b/drivers/usb/uhc/uhc_mcux_ohci.c new file mode 100644 index 000000000000..589168ca3664 --- /dev/null +++ b/drivers/usb/uhc/uhc_mcux_ohci.c @@ -0,0 +1,355 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT nxp_uhc_ohci + +#include +#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 "uhc_mcux_common.h" +#include "usb_host_ohci.h" + +#include +LOG_MODULE_DECLARE(uhc_mcux); + +K_MEM_SLAB_DEFINE_STATIC(mcux_uhc_transfer_pool, sizeof(usb_host_transfer_t), + USB_HOST_CONFIG_MAX_TRANSFERS, sizeof(void *)); + +#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct uhc_mcux_data, mcux_host) + +struct uhc_mcux_config { + void (*irq_enable_func)(const struct device *dev); + void (*irq_disable_func)(const struct device *dev); + uintptr_t base; + k_thread_stack_t *drv_stack; + const struct pinctrl_dev_config *pincfg; +}; + +static void uhc_mcux_thread(void *p1, void *p2, void *p3) +{ + const struct device *dev = p1; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + while (true) { + USB_HostOhciTaskFunction((void *)(&priv->mcux_host)); + } +} + +static void uhc_mcux_isr(const struct device *dev) +{ + struct uhc_mcux_data *priv = uhc_get_private(dev); + + USB_HostOhciIsrFunction((void *)(&priv->mcux_host)); +} + +/* MCUX controller dirver uses this callback to notify upper layer suspend related event */ +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; +} + +static int uhc_mcux_init(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_mcux_data *priv = uhc_get_private(dev); + k_thread_entry_t thread_entry = NULL; + usb_status_t status; + + if ((priv->controller_id >= kUSB_ControllerOhci0) && + (priv->controller_id <= kUSB_ControllerOhci1)) { + thread_entry = uhc_mcux_thread; + } + + if (thread_entry == NULL) { + return -ENOMEM; + } + + priv->dev = dev; + /* Init MCUX USB host driver. */ + priv->mcux_host.deviceCallback = mcux_host_callback; + status = priv->mcux_if->controllerCreate(priv->controller_id, &priv->mcux_host, + &(priv->mcux_host.controllerHandle)); + if (status != kStatus_USB_Success) { + return -ENOMEM; + } + + /* Create MCUX USB host driver task */ + k_thread_create(&priv->drv_stack_data, config->drv_stack, CONFIG_UHC_NXP_THREAD_STACK_SIZE, + thread_entry, (void *)dev, NULL, NULL, K_PRIO_COOP(2), 0, K_NO_WAIT); + k_thread_name_set(&priv->drv_stack_data, "uhc_mcux_ohci"); + + return 0; +} + +static int uhc_mcux_enable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + config->irq_enable_func(dev); + + return 0; +} + +static int uhc_mcux_disable(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + + 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_mcux_data *priv = uhc_get_private(dev); + + config->irq_disable_func(dev); + k_thread_abort(&priv->drv_stack_data); + priv->mcux_if->controllerDestory(priv->mcux_host.controllerHandle); + + return 0; +} + +/* Signal bus reset, 50ms SE0 signal */ +static int uhc_mcux_bus_reset(const struct device *dev) +{ + int ret; + + ret = uhc_mcux_bus_control(dev, kUSB_HostBusReset); + if (ret == 0) { + ret = uhc_mcux_bus_control(dev, kUSB_HostBusRestart); + } + + 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); +} + +/* MCUX hal controller driver transfer callback */ +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); + int err = -EIO; + + if (status == kStatus_USB_Success) { + err = 0; + + if ((xfer->ep == 0) && (transfer->setupPacket->bRequest == USB_SREQ_SET_ADDRESS)) { + usb_host_pipe_handle mcux_ep_handle; + + /* set address to let USB_HostHelperGetPeripheralInformation get right value + */ + xfer->addr = (uint8_t)transfer->setupPacket->wValue; + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle != NULL) { + uhc_mcux_control(dev, kUSB_HostUpdateControlEndpointAddress, + mcux_ep_handle); + } + } + } + + if ((xfer->buf != NULL) && (transfer->transferBuffer != NULL)) { + if (transfer->transferSofar > 0) { + net_buf_add(xfer->buf, transfer->transferSofar); + } + } + + transfer->setupPacket = NULL; + transfer->transferBuffer = NULL; + k_mem_slab_free(&mcux_uhc_transfer_pool, transfer); + uhc_xfer_return(dev, xfer, err); +} + +static usb_host_transfer_t *uhc_mcux_hal_init_transfer(const struct device *dev, + usb_host_pipe_handle mcux_ep_handle, + struct uhc_transfer *const xfer) +{ + usb_host_transfer_t *mcux_xfer; + + if (k_mem_slab_alloc(&mcux_uhc_transfer_pool, (void **)&mcux_xfer, K_NO_WAIT)) { + return NULL; + } + (void)uhc_mcux_hal_init_transfer_common(dev, mcux_xfer, mcux_ep_handle, xfer, + uhc_mcux_transfer_callback); + + return mcux_xfer; +} + +static int uhc_mcux_enqueue(const struct device *dev, struct uhc_transfer *const xfer) +{ + usb_host_pipe_handle mcux_ep_handle; + struct uhc_mcux_data *priv = uhc_get_private(dev); + usb_status_t status; + usb_host_transfer_t *mcux_xfer; + + uhc_xfer_append(dev, xfer); + + /* firstly check and init the mcux endpoint handle */ + mcux_ep_handle = uhc_mcux_init_hal_ep(dev, xfer); + if (mcux_ep_handle == NULL) { + return -ENOMEM; + } + + /* Initialize MCUX hal transfer. */ + mcux_xfer = uhc_mcux_hal_init_transfer(dev, mcux_ep_handle, xfer); + if (mcux_xfer == NULL) { + return -ENOMEM; + } + + uhc_mcux_lock(dev); + /* give the transfer to MCUX drv. */ + status = priv->mcux_if->controllerWritePipe(priv->mcux_host.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 inline void uhc_mcux_get_hal_driver_id(struct uhc_mcux_data *priv, + const struct uhc_mcux_config *config) +{ + /* + * MCUX USB controller drivers use an ID to tell the HAL drivers + * which controller is being used. This part of the code converts + * the base address to the ID value. + */ + uintptr_t usb_base_addrs[] = USBFSH_BASE_ADDRS; + + /* get the right controller id */ + priv->controller_id = 0xFFu; /* invalid value */ + for (uint8_t i = 0; i < ARRAY_SIZE(usb_base_addrs); i++) { + if (usb_base_addrs[i] == config->base) { + priv->controller_id = kUSB_ControllerOhci0 + i; + break; + } + } +} + +static int uhc_mcux_driver_preinit(const struct device *dev) +{ + const struct uhc_mcux_config *config = dev->config; + struct uhc_data *data = dev->data; + struct uhc_mcux_data *priv = uhc_get_private(dev); + + uhc_mcux_get_hal_driver_id(priv, config); + if (priv->controller_id == 0xFFu) { + return -ENOMEM; + } + + k_mutex_init(&data->mutex); + pinctrl_apply_state(config->pincfg, PINCTRL_STATE_DEFAULT); + LOG_DBG("MCUX controller initialized"); + + 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 const usb_host_controller_interface_t uhc_mcux_if = { + USB_HostOhciCreate, USB_HostOhciDestory, USB_HostOhciOpenPipe, USB_HostOhciClosePipe, + USB_HostOhciWritePipe, USB_HostOhciReadPipe, USB_HostOhciIoctl, +}; + +#define UHC_MCUX_OHCI_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_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 K_KERNEL_STACK_DEFINE(drv_stack_##n, CONFIG_UHC_NXP_THREAD_STACK_SIZE); \ + \ + PINCTRL_DT_INST_DEFINE(n); \ + \ + static struct uhc_mcux_config priv_config_##n = { \ + .base = DT_INST_REG_ADDR(n), \ + .irq_enable_func = uhc_irq_enable_func##n, \ + .irq_disable_func = uhc_irq_disable_func##n, \ + .drv_stack = drv_stack_##n, \ + .pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \ + }; \ + \ + static struct uhc_mcux_data priv_data_##n = { \ + .mcux_if = &uhc_mcux_if, \ + }; \ + \ + static struct uhc_data uhc_data_##n = { \ + .mutex = Z_MUTEX_INITIALIZER(uhc_data_##n.mutex), \ + .priv = &priv_data_##n, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(n, uhc_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_OHCI_DEVICE_DEFINE) diff --git a/dts/arm/nxp/nxp_k2x.dtsi b/dts/arm/nxp/nxp_k2x.dtsi index 0df1010f8b54..062d5d1611c9 100644 --- a/dts/arm/nxp/nxp_k2x.dtsi +++ b/dts/arm/nxp/nxp_k2x.dtsi @@ -1,5 +1,6 @@ /* * Copyright (c) 2018 Prevas A/S + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -375,6 +376,14 @@ status = "disabled"; }; + usbh: 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_lpc55S2x_common.dtsi b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi index 184c2feeaddb..31f626afb4c3 100644 --- a/dts/arm/nxp/nxp_lpc55S2x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S2x_common.dtsi @@ -320,6 +320,27 @@ num-bidir-endpoints = <6>; status = "disabled"; }; + + usbhfs: usbhfs@A2000 { + compatible = "nxp,uhc-ohci"; + reg = <0xa2000 0x1000>; + interrupts = <28 1>; + maximum-speed = "full-speed"; + status = "disabled"; + }; + + usbhhs: usbhhs@A3000 { + compatible = "nxp,uhc-ip3516hs"; + reg = <0xa3000 0x1000>; + interrupts = <47 1>; + status = "disabled"; + }; + + usbphy1: usbphy@38000 { + compatible = "nxp,usbphy"; + reg = <0x38000 0x1000>; + status = "disabled"; + }; }; &nvic { diff --git a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi index 07883ab82530..8ef73b8aca51 100644 --- a/dts/arm/nxp/nxp_lpc55S6x_common.dtsi +++ b/dts/arm/nxp/nxp_lpc55S6x_common.dtsi @@ -390,6 +390,21 @@ status = "disabled"; }; + usbhfs: usbhfs@A2000 { + compatible = "nxp,uhc-ohci"; + reg = <0xa2000 0x1000>; + interrupts = <28 1>; + maximum-speed = "full-speed"; + status = "disabled"; + }; + + usbhhs: usbhhs@A3000 { + compatible = "nxp,uhc-ip3516hs"; + reg = <0xa3000 0x1000>; + interrupts = <47 1>; + status = "disabled"; + }; + usbphy1: usbphy@38000 { compatible = "nxp,usbphy"; reg = <0x38000 0x1000>; diff --git a/dts/arm/nxp/nxp_rt10xx.dtsi b/dts/arm/nxp/nxp_rt10xx.dtsi index 849bbedcd644..faaaadc321e0 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 */ @@ -835,6 +835,24 @@ status = "disabled"; }; + usbh1: usbh@402e0000 { + compatible = "nxp,uhc-ehci"; + reg = <0x402E0000 0x200>; + interrupts = <113 1>; + interrupt-names = "usb_otg"; + clocks = <&usbclk>; + status = "disabled"; + }; + + usbh2: 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>; diff --git a/dts/bindings/usb/nxp,uhc-ehci.yaml b/dts/bindings/usb/nxp,uhc-ehci.yaml new file mode 100644 index 000000000000..5f8657fe7227 --- /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-ip3516hs.yaml b/dts/bindings/usb/nxp,uhc-ip3516hs.yaml new file mode 100644 index 000000000000..d09b5b9f056d --- /dev/null +++ b/dts/bindings/usb/nxp,uhc-ip3516hs.yaml @@ -0,0 +1,12 @@ +# # Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP IP3516HS USB host controller + +compatible: "nxp,uhc-ip3516hs" + +include: [usb-controller.yaml, pinctrl-device.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 000000000000..9a3c6b3a0467 --- /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,uhc-ohci.yaml b/dts/bindings/usb/nxp,uhc-ohci.yaml new file mode 100644 index 000000000000..b39f2c359a9c --- /dev/null +++ b/dts/bindings/usb/nxp,uhc-ohci.yaml @@ -0,0 +1,8 @@ +# # Copyright 2024 NXP +# SPDX-License-Identifier: Apache-2.0 + +description: NXP OHCI USB host controller + +compatible: "nxp,uhc-ohci" + +include: [usb-controller.yaml, pinctrl-device.yaml] diff --git a/include/zephyr/arch/arm/mpu/nxp_mpu.h b/include/zephyr/arch/arm/mpu/nxp_mpu.h index b95565658027..881d3be15aa2 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_UHC_NXP_KHCI #define BM4_PERMISSIONS ((1 << BM4_RE_SHIFT) | (1 << BM4_WE_SHIFT)) #else #define BM4_PERMISSIONS 0 diff --git a/modules/hal_nxp/CMakeLists.txt b/modules/hal_nxp/CMakeLists.txt index c338728c19a8..2cd1748c43b2 100644 --- a/modules/hal_nxp/CMakeLists.txt +++ b/modules/hal_nxp/CMakeLists.txt @@ -7,8 +7,9 @@ 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_UDC_DRIVER usb) + if(CONFIG_USB_DEVICE_DRIVER OR CONFIG_UDC_DRIVER OR CONFIG_UHC_DRIVER) + add_subdirectory(usb) + 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 @@ -25,6 +26,7 @@ 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_UDC_DRIVER DATA_SECTION_IS_CACHEABLE=1) + zephyr_compile_definitions_ifdef(CONFIG_UHC_DRIVER DATA_SECTION_IS_CACHEABLE=1) endif() zephyr_compile_definitions_ifdef(CONFIG_ETH_NXP_IMX_NETC FSL_ETH_ENABLE_CACHE_CONTROL=1) 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 000000000000..bf5f058abebd --- /dev/null +++ b/modules/hal_nxp/usb/usb_host_config.h @@ -0,0 +1,67 @@ +/* + * Copyright 2024 NXP + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#ifndef __USB_HOST_CONFIG_H__ +#define __USB_HOST_CONFIG_H__ + +#include + +/****************************************************************************** + * Definitions + *****************************************************************************/ +/* EHCI instance count */ +#ifdef CONFIG_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) +#else +#define USB_HOST_CONFIG_EHCI (0U) +#endif /* CONFIG_USB_DC_NXP_EHCI */ + +#ifdef CONFIG_UHC_NXP_KHCI +#define USB_HOST_CONFIG_KHCI (1U) +#define USB_HOST_CONFIG_KHCI_DMA_ALIGN_BUFFER (64U) +#else +#define USB_HOST_CONFIG_KHCI (0U) +#endif /* CONFIG_UHC_NXP_KHCI */ + +#ifdef CONFIG_UHC_NXP_IP3516HS +#define USB_HOST_CONFIG_IP3516HS (1U) +#define USB_HOST_CONFIG_IP3516HS_MAX_PIPE (32U) +#define USB_HOST_CONFIG_IP3516HS_MAX_ATL (32U) +#define USB_HOST_CONFIG_IP3516HS_MAX_INT (32U) +#define USB_HOST_CONFIG_IP3516HS_MAX_ISO (0U) +#else +#define USB_HOST_CONFIG_IP3516HS (0U) +#endif /* CONFIG_UHC_NXP_IP3516HS */ + +#ifdef CONFIG_UHC_NXP_OHCI +#define USB_HOST_CONFIG_OHCI (1U) +#define USB_HOST_CONFIG_OHCI_MAX_ED (8U) +#define USB_HOST_CONFIG_OHCI_MAX_GTD (8U) +#define USB_HOST_CONFIG_OHCI_MAX_ITD (8U) +#else +#define USB_HOST_CONFIG_OHCI (0U) +#endif /* CONFIG_UHC_NXP_OHCI */ + +#define USB_HOST_CONFIG_MAX_HOST \ + (USB_HOST_CONFIG_KHCI + USB_HOST_CONFIG_EHCI + USB_HOST_CONFIG_IP3516HS + \ + USB_HOST_CONFIG_OHCI) + +#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/soc/nxp/imxrt/imxrt10xx/soc.c b/soc/nxp/imxrt/imxrt10xx/soc.c index 941ae1d34747..80a07d57b717 100644 --- a/soc/nxp/imxrt/imxrt10xx/soc.c +++ b/soc/nxp/imxrt/imxrt10xx/soc.c @@ -1,5 +1,5 @@ /* - * Copyright 2017-2023 NXP + * Copyright 2017-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -243,8 +243,9 @@ static ALWAYS_INLINE void clock_init(void) kIOMUXC_GPR_ENET2RefClkMode, true); #endif -#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && \ - (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI) +#if ((DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb1)) && \ + (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)) ||\ + (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usbh1)) && (CONFIG_UHC_NXP_EHCI))) CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb1), clocks, clock_frequency)); CLOCK_EnableUsbhs0Clock(kCLOCK_Usb480M, @@ -254,8 +255,9 @@ static ALWAYS_INLINE void clock_init(void) #endif #endif -#if DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb2)) && \ - (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI) +#if ((DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usb2)) && \ + (CONFIG_USB_DC_NXP_EHCI || CONFIG_UDC_NXP_EHCI)) ||\ + (DT_NODE_HAS_STATUS_OKAY(DT_NODELABEL(usbh2)) && (CONFIG_UHC_NXP_EHCI))) CLOCK_EnableUsbhs1PhyPllClock(kCLOCK_Usb480M, DT_PROP_BY_PHANDLE(DT_NODELABEL(usb2), clocks, clock_frequency)); CLOCK_EnableUsbhs1Clock(kCLOCK_Usb480M, diff --git a/soc/nxp/imxrt/imxrt6xx/cm33/CMakeLists.txt b/soc/nxp/imxrt/imxrt6xx/cm33/CMakeLists.txt index 8ea9e211c2b9..014a1d4c7435 100644 --- a/soc/nxp/imxrt/imxrt6xx/cm33/CMakeLists.txt +++ b/soc/nxp/imxrt/imxrt6xx/cm33/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2020, NXP +# Copyright (c) 2020,2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -19,6 +19,7 @@ zephyr_library_include_directories( zephyr_compile_definitions_ifdef(CONFIG_USB_DEVICE_DRIVER USB_STACK_USE_DEDICATED_RAM=1) zephyr_compile_definitions_ifdef(CONFIG_UDC_DRIVER USB_STACK_USE_DEDICATED_RAM=1) +zephyr_compile_definitions_ifdef(CONFIG_UHC_DRIVER USB_STACK_USE_DEDICATED_RAM=1) if(CONFIG_FLASH_MCUX_FLEXSPI_XIP) zephyr_code_relocate(FILES flash_clock_setup.c LOCATION RAM) diff --git a/soc/nxp/kinetis/k2x/soc.c b/soc/nxp/kinetis/k2x/soc.c index e89526f55568..853442856901 100644 --- a/soc/nxp/kinetis/k2x/soc.c +++ b/soc/nxp/kinetis/k2x/soc.c @@ -3,6 +3,7 @@ * Copyright (c) 2016, Freescale Semiconductor, Inc. * Copyright (c) 2018 Prevas A/S * Copyright (c) 2019 Thomas Burdick + * Copyright 2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -102,7 +103,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_UHC_NXP_KHCI CLOCK_EnableUsbfs0Clock(kCLOCK_UsbSrcPll0, CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); #endif diff --git a/soc/nxp/lpc/lpc55xxx/CMakeLists.txt b/soc/nxp/lpc/lpc55xxx/CMakeLists.txt index 4dae5afa7eee..e0d7cb005029 100644 --- a/soc/nxp/lpc/lpc55xxx/CMakeLists.txt +++ b/soc/nxp/lpc/lpc55xxx/CMakeLists.txt @@ -1,5 +1,5 @@ # -# Copyright (c) 2019, NXP +# Copyright (c) 2019,2024 NXP # # SPDX-License-Identifier: Apache-2.0 # @@ -16,9 +16,12 @@ zephyr_linker_sources_ifdef(CONFIG_USB_DEVICE_DRIVER SECTIONS usb.ld) zephyr_linker_sources_ifdef(CONFIG_UDC_DRIVER SECTIONS usb.ld) + zephyr_linker_sources_ifdef(CONFIG_UHC_DRIVER + SECTIONS usb.ld) zephyr_compile_definitions_ifdef(CONFIG_USB_DEVICE_DRIVER USB_STACK_USE_DEDICATED_RAM=1) zephyr_compile_definitions_ifdef(CONFIG_UDC_DRIVER USB_STACK_USE_DEDICATED_RAM=1) +zephyr_compile_definitions_ifdef(CONFIG_UHC_DRIVER USB_STACK_USE_DEDICATED_RAM=1) endif() # CMSIS SystemInit allows us to skip enabling clock to SRAM banks via diff --git a/soc/nxp/lpc/lpc55xxx/soc.c b/soc/nxp/lpc/lpc55xxx/soc.c index 7b7332d0b61b..df2f8676e26f 100644 --- a/soc/nxp/lpc/lpc55xxx/soc.c +++ b/soc/nxp/lpc/lpc55xxx/soc.c @@ -1,4 +1,4 @@ -/* Copyright 2017, 2019-2023 NXP +/* Copyright 2017, 2019-2024 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,7 +26,7 @@ #ifdef CONFIG_GPIO_MCUX_LPC #include #endif -#if CONFIG_USB_DC_NXP_LPCIP3511 || CONFIG_UDC_NXP_IP3511 +#if CONFIG_USB_DC_NXP_LPCIP3511 || CONFIG_UDC_NXP_IP3511 || CONFIG_UHC_NXP_IP3516HS #include "usb_phy.h" #include "usb.h" #endif @@ -287,6 +287,48 @@ static ALWAYS_INLINE void clock_init(void) #endif /* CONFIG_USB_DC_NXP_LPCIP3511 */ +#if CONFIG_UHC_NXP_OHCI + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhfs), nxp_uhc_ohci, okay) + /* set BOD VBAT level to 1.65V */ + POWER_SetBodVbatLevel(kPOWER_BodVbatLevel1650mv, kPOWER_BodHystLevel50mv, false); + NVIC_ClearPendingIRQ(USB0_IRQn); + NVIC_ClearPendingIRQ(USB0_NEEDCLK_IRQn); + /*< Turn on USB Phy */ +#if defined(CONFIG_SOC_LPC55S36) + POWER_DisablePD(kPDRUNCFG_PD_USBFSPHY); +#else + POWER_DisablePD(kPDRUNCFG_PD_USB0_PHY); +#endif + RESET_PeripheralReset(kUSB1H_RST_SHIFT_RSTn); + RESET_PeripheralReset(kUSB1D_RST_SHIFT_RSTn); + RESET_PeripheralReset(kUSB1_RST_SHIFT_RSTn); + RESET_PeripheralReset(kUSB1RAM_RST_SHIFT_RSTn); + CLOCK_EnableUsbfs0HostClock(kCLOCK_UsbfsSrcPll0, 48000000U); +#if defined(FSL_FEATURE_USBHSD_USB_RAM) && (FSL_FEATURE_USBHSD_USB_RAM) + memset((uint8_t *)FSL_FEATURE_USBHSD_USB_RAM_BASE_ADDRESS, 0, FSL_FEATURE_USBHSD_USB_RAM); +#endif +#endif + +#endif + +#if CONFIG_UHC_NXP_IP3516HS + +#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(usbhhs), nxp_uhc_ip3516hs, okay) + /*< Turn on USB Phy */ +#if !defined(CONFIG_SOC_LPC55S36) + POWER_DisablePD(kPDRUNCFG_PD_USB1_PHY); +#endif + CLOCK_EnableUsbhs0PhyPllClock(kCLOCK_UsbPhySrcExt, CLK_CLK_IN); + CLOCK_EnableUsbhs0HostClock(kCLOCK_UsbSrcUnused, 0U); + USB_EhciPhyInit(kUSB_ControllerLpcIp3511Hs0, CLK_CLK_IN, NULL); +#if defined(FSL_FEATURE_USBHSD_USB_RAM) && (FSL_FEATURE_USBHSD_USB_RAM) + memset((uint8_t *)FSL_FEATURE_USBHSD_USB_RAM_BASE_ADDRESS, 0, FSL_FEATURE_USBHSD_USB_RAM); +#endif +#endif + +#endif + DT_FOREACH_STATUS_OKAY(nxp_lpc_ctimer, CTIMER_CLOCK_SETUP) DT_FOREACH_STATUS_OKAY(nxp_ctimer_pwm, CTIMER_CLOCK_SETUP) diff --git a/west.yml b/west.yml index 0d16fad63317..27ff4f6a5aba 100644 --- a/west.yml +++ b/west.yml @@ -203,7 +203,7 @@ manifest: groups: - hal - name: hal_nxp - revision: b5f6470ec7ccd7f1c9a2c929fa93eae9fb001d9e + revision: pull/496/head path: modules/hal/nxp groups: - hal