Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions boards/nxp/frdm_imx93/frdm_imx93_mimx9352_a55.dts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
zephyr,shell-uart = &lpuart2;
zephyr,sram = &dram;
zephyr,canbus = &flexcan2;
zephyr,usb-device = &usb1;
};

cpus {
Expand Down Expand Up @@ -149,3 +150,7 @@
&wdog4 {
status = "okay";
};

zephyr_udc0: &usb1 {
status = "okay";
};
1 change: 1 addition & 0 deletions boards/nxp/frdm_imx93/frdm_imx93_mimx9352_a55.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ supported:
- can
- net
- watchdog
- usb_device
testing:
ignore_tags:
- bluetooth
Expand Down
3 changes: 3 additions & 0 deletions boards/nxp/frdm_imx93/frdm_imx93_mimx9352_a55_defconfig
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,6 @@ CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

CONFIG_CLOCK_CONTROL=y

# USB Except
CONFIG_UDC_WORKQUEUE=n
40 changes: 40 additions & 0 deletions drivers/clock_control/clock_control_mcux_ccm_rev2.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
#include <zephyr/drivers/clock_control.h>
#include <zephyr/dt-bindings/clock/imx_ccm_rev2.h>
#include <fsl_clock.h>
#if defined(CONFIG_SOC_MIMX9352_A55)
#include <soc.h>
#endif

#define LOG_LEVEL CONFIG_CLOCK_CONTROL_LOG_LEVEL
#include <zephyr/logging/log.h>
Expand Down Expand Up @@ -182,6 +185,27 @@ static int mcux_ccm_get_subsys_rate(const struct device *dev,
break;
#endif

#if defined(CONFIG_SOC_MIMX9352_A55)
case IMX_CCM_MEDIA_AXI_CLK:
clock_root = kCLOCK_Root_MediaAxi;
break;
case IMX_CCM_MEDIA_APB_CLK:
clock_root = kCLOCK_Root_MediaApb;
break;
case IMX_CCM_MEDIA_DISP_PIX_CLK:
clock_root = kCLOCK_Root_MediaDispPix;
break;
case IMX_CCM_MEDIA_LDB_CLK:
clock_root = kCLOCK_Root_MediaLdb;
break;
case IMX_CCM_MIPI_PHY_CFG_CLK:
clock_root = kCLOCK_Root_MipiPhyCfg;
break;
case IMX_CCM_CAM_PIX_CLK:
clock_root = kCLOCK_Root_CamPix;
break;
#endif

#if defined(CONFIG_SOC_MIMX9352) && defined(CONFIG_DAI_NXP_SAI)
case IMX_CCM_SAI1_CLK:
case IMX_CCM_SAI2_CLK:
Expand Down Expand Up @@ -372,6 +396,22 @@ static int CCM_SET_FUNC_ATTR mcux_ccm_set_subsys_rate(const struct device *dev,
return mipi_csi2rx_clock_set_freq(kCLOCK_Root_Csi2_Esc, clock_rate);
#endif

#if defined(CONFIG_SOC_MIMX9352_A55)
case IMX_CCM_MEDIA_AXI_CLK:
case IMX_CCM_MEDIA_APB_CLK:
case IMX_CCM_MEDIA_DISP_PIX_CLK:
case IMX_CCM_MEDIA_LDB_CLK:
case IMX_CCM_MIPI_PHY_CFG_CLK:
case IMX_CCM_CAM_PIX_CLK:
return common_clock_set_freq(clock_name, (uint32_t)clock_rate);
#endif

#if defined(CONFIG_UDC_NXP_EHCI) && defined(CONFIG_SOC_MIMX9352_A55)
case IMX_CCM_USB_CLK:
case IMX_CCM_USB_PHY_CLK:
return common_clock_set_freq(clock_name, (uint32_t)clock_rate);
#endif

default:
/* Silence unused variable warning */
ARG_UNUSED(clock_rate);
Expand Down
94 changes: 85 additions & 9 deletions drivers/usb/udc/udc_mcux_ehci.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
/*
* Copyright 2024 NXP
* Copyright 2024-2025 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_ehci

#include <soc.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <soc.h>

#include <zephyr/device.h>
#include <zephyr/kernel.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/drivers/usb/udc.h>
#include <zephyr/drivers/pinctrl.h>
#include <zephyr/drivers/clock_control.h>

#include "udc_common.h"
#include "usb.h"
Expand All @@ -34,19 +36,30 @@ LOG_MODULE_REGISTER(udc_mcux, CONFIG_UDC_DRIVER_LOG_LEVEL);

#define PRV_DATA_HANDLE(_handle) CONTAINER_OF(_handle, struct udc_mcux_data, mcux_device)

/* Required by DEVICE_MMIO_NAMED_* macros */
#define DEV_CFG(_dev) ((const struct udc_mcux_config *)(_dev)->config)
#define DEV_DATA(_dev) ((struct udc_mcux_data *)(udc_get_private(_dev)))

struct udc_mcux_config {
const usb_device_controller_interface_struct_t *mcux_if;
void (*irq_enable_func)(const struct device *dev);
void (*irq_disable_func)(const struct device *dev);
size_t num_of_eps;
struct udc_ep_config *ep_cfg_in;
struct udc_ep_config *ep_cfg_out;
uintptr_t base;
DEVICE_MMIO_NAMED_ROM(reg_base);
const struct pinctrl_dev_config *pincfg;
usb_phy_config_struct_t *phy_config;
const struct device *usb_clock_dev;
clock_control_subsys_t usb_clock_subsys;
clock_control_subsys_rate_t usb_clock_rate;
const struct device *usbphy_clock_dev;
clock_control_subsys_t usbphy_clock_subsys;
clock_control_subsys_rate_t usbphy_clock_rate;
};

struct udc_mcux_data {
DEVICE_MMIO_NAMED_RAM(reg_base);
const struct device *dev;
usb_device_struct_t mcux_device;
struct k_work work;
Expand Down Expand Up @@ -690,11 +703,14 @@ static int udc_mcux_init(const struct device *dev)
const usb_device_controller_interface_struct_t *mcux_if = config->mcux_if;
struct udc_mcux_data *priv = udc_get_private(dev);
usb_status_t status;
uintptr_t base;

if (priv->controller_id == 0xFFu) {
return -ENOMEM;
}

base = (uintptr_t)DEVICE_MMIO_NAMED_GET(dev, reg_base);

#ifdef CONFIG_DT_HAS_NXP_USBPHY_ENABLED
if (config->phy_config != NULL) {
USB_EhciPhyInit(priv->controller_id, 0u, config->phy_config);
Expand All @@ -711,7 +727,7 @@ static int udc_mcux_init(const struct device *dev)
/* enable USB interrupt */
config->irq_enable_func(dev);

LOG_DBG("Initialized USB controller %x", (uint32_t)config->base);
LOG_DBG("Initialized USB controller %x", (uint32_t)base);

return 0;
}
Expand All @@ -735,9 +751,14 @@ static int udc_mcux_shutdown(const struct device *dev)
return 0;
}

static inline void udc_mcux_get_hal_driver_id(struct udc_mcux_data *priv,
const struct udc_mcux_config *config)
static inline void udc_mcux_get_hal_driver_id(const struct device *dev)
{
struct udc_data *data = dev->data;
struct udc_mcux_data *priv = data->priv;
uintptr_t base;

base = (uintptr_t)DEVICE_MMIO_NAMED_GET(dev, reg_base);

/*
* MCUX USB controller drivers use an ID to tell the HAL drivers
* which controller is being used. This part of the code converts
Expand All @@ -752,7 +773,7 @@ static inline void udc_mcux_get_hal_driver_id(struct udc_mcux_data *priv,
/* 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) {
if (usb_base_addrs[i] == base) {
priv->controller_id = kUSB_ControllerEhci0 + i;
break;
}
Expand All @@ -766,11 +787,28 @@ static int udc_mcux_driver_preinit(const struct device *dev)
struct udc_mcux_data *priv = data->priv;
int err;

udc_mcux_get_hal_driver_id(priv, config);
DEVICE_MMIO_NAMED_MAP(dev, reg_base, K_MEM_CACHE_NONE | K_MEM_DIRECT_MAP);

udc_mcux_get_hal_driver_id(dev);
if (priv->controller_id == 0xFFu) {
return -ENOMEM;
}

if (config->usb_clock_dev && config->usb_clock_rate) {
clock_control_set_rate(
config->usb_clock_dev,
config->usb_clock_subsys,
config->usb_clock_rate
);
}
if (config->usbphy_clock_dev && config->usbphy_clock_rate) {
clock_control_set_rate(
config->usbphy_clock_dev,
config->usbphy_clock_subsys,
config->usbphy_clock_rate
);
}

k_mutex_init(&data->mutex);
k_fifo_init(&priv->fifo);
k_work_init(&priv->work, udc_mcux_work_handler);
Expand Down Expand Up @@ -853,6 +891,42 @@ static const usb_device_controller_interface_struct_t udc_mcux_if = {
USB_DeviceEhciRecv, USB_DeviceEhciCancel, USB_DeviceEhciControl
};

#define UDC_MCUX_CLK0_DEFINE(n) \
.usb_clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_IDX(n, 0)), \
.usb_clock_subsys = (clock_control_subsys_t) \
DT_INST_CLOCKS_CELL_BY_IDX(n, 0, name), \
.usb_clock_rate = (void *)(uintptr_t)DT_INST_PROP_BY_IDX(n, clock_rates, 0),

#define UDC_MCUX_CLK0_DEFINE_NULL \
.usb_clock_dev = NULL, \
.usb_clock_subsys = NULL, \
.usb_clock_rate = NULL,

#define UDC_MCUX_CLK0_DEFINE_OR(n) \
COND_CODE_1(DT_INST_CLOCKS_HAS_IDX(n, 0), \
(COND_CODE_1(DT_INST_PROP_HAS_IDX(n, clock_rates, 0), \
(UDC_MCUX_CLK0_DEFINE(n)), \
(UDC_MCUX_CLK0_DEFINE_NULL))), \
(UDC_MCUX_CLK0_DEFINE_NULL))

#define UDC_MCUX_CLK1_DEFINE(n) \
.usbphy_clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR_BY_IDX(n, 1)), \
.usbphy_clock_subsys = (clock_control_subsys_t) \
DT_INST_CLOCKS_CELL_BY_IDX(n, 1, name), \
.usbphy_clock_rate = (void *)(uintptr_t)DT_INST_PROP_BY_IDX(n, clock_rates, 1),

#define UDC_MCUX_CLK1_DEFINE_NULL \
.usbphy_clock_dev = NULL, \
.usbphy_clock_subsys = NULL, \
.usbphy_clock_rate = NULL,

#define UDC_MCUX_CLK1_DEFINE_OR(n) \
COND_CODE_1(DT_INST_CLOCKS_HAS_IDX(n, 1), \
(COND_CODE_1(DT_INST_PROP_HAS_IDX(n, clock_rates, 1), \
(UDC_MCUX_CLK1_DEFINE(n)), \
(UDC_MCUX_CLK1_DEFINE_NULL))), \
(UDC_MCUX_CLK1_DEFINE_NULL))

#define UDC_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), \
Expand Down Expand Up @@ -898,7 +972,7 @@ static usb_phy_config_struct_t phy_config_##n = { \
PINCTRL_DT_INST_DEFINE(n); \
\
static struct udc_mcux_config priv_config_##n = { \
.base = DT_INST_REG_ADDR(n), \
DEVICE_MMIO_NAMED_ROM_INIT(reg_base, DT_DRV_INST(n)), \
.irq_enable_func = udc_irq_enable_func##n, \
.irq_disable_func = udc_irq_disable_func##n, \
.num_of_eps = DT_INST_PROP(n, num_bidir_endpoints), \
Expand All @@ -907,6 +981,8 @@ static usb_phy_config_struct_t phy_config_##n = { \
.mcux_if = &udc_mcux_if, \
.pincfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
.phy_config = UDC_MCUX_PHY_CFG_PTR_OR_NULL(n), \
UDC_MCUX_CLK0_DEFINE_OR(n) \
UDC_MCUX_CLK1_DEFINE_OR(n) \
}; \
\
static struct udc_mcux_data priv_data_##n = { \
Expand Down
26 changes: 26 additions & 0 deletions dts/arm64/nxp/nxp_mimx93_a55.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,32 @@
prescaler = <1>;
status = "disabled";
};

usb1: usbd@4c100000 {
compatible = "nxp,ehci";
reg = <0x4c100000 DT_SIZE_K(4)>;
interrupts = <GIC_SPI 187 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
interrupt-names = "usb_0";
interrupt-parent= <&gic>;
clocks = <&ccm IMX_CCM_USB_CLK 2 3>,
<&ccm IMX_CCM_USB_PHY_CLK 2 8>;
clock-rates = <134000000 50000000>;
num-bidir-endpoints = <8>;
status = "disabled";
};

usb2: usbd@4c200000 {
compatible = "nxp,ehci";
reg = <0x4c200000 DT_SIZE_K(4)>;
interrupts = <GIC_SPI 188 IRQ_TYPE_LEVEL IRQ_DEFAULT_PRIORITY>;
interrupt-names = "usb_1";
interrupt-parent= <&gic>;
clocks = <&ccm IMX_CCM_USB_CLK 2 3>,
<&ccm IMX_CCM_USB_PHY_CLK 2 8>;
clock-rates = <134000000 50000000>;
num-bidir-endpoints = <8>;
status = "disabled";
};
};

&gpio1 {
Expand Down
7 changes: 6 additions & 1 deletion dts/bindings/usb/nxp,ehci.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023 NXP
# Copyright 2023,2025 NXP
# SPDX-License-Identifier: Apache-2.0

description: NXP EHCI USB device mode
Expand All @@ -10,3 +10,8 @@ include: "nxp,mcux-usbd.yaml"
properties:
phy-handle:
type: phandle

clock-rates:
type: array
description: |
Optional rate given to each clock provider in the "clocks" property.
12 changes: 12 additions & 0 deletions include/zephyr/dt-bindings/clock/imx_ccm_rev2.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,23 @@
/* KPP */
#define IMX_CCM_KPP_CLK 0x2400UL

/* USB */
#define IMX_CCM_USB_CLK 0x2500UL
#define IMX_CCM_USB_PHY_CLK 0x2600UL

/* QTMR */
#define IMX_CCM_QTMR_CLK 0x6000UL
#define IMX_CCM_QTMR1_CLK 0x6000UL
#define IMX_CCM_QTMR2_CLK 0x6001UL
#define IMX_CCM_QTMR3_CLK 0x6002UL
#define IMX_CCM_QTMR4_CLK 0x6003UL

/* MEDIA */
#define IMX_CCM_MEDIA_AXI_CLK 0x3000UL
#define IMX_CCM_MEDIA_APB_CLK 0x3100UL
#define IMX_CCM_MEDIA_DISP_PIX_CLK 0x3200UL
#define IMX_CCM_MEDIA_LDB_CLK 0x3300UL
#define IMX_CCM_MIPI_PHY_CFG_CLK 0x3400UL
#define IMX_CCM_CAM_PIX_CLK 0x3500UL

#endif /* ZEPHYR_INCLUDE_DT_BINDINGS_CLOCK_IMX_CCM_REV2_H_ */
8 changes: 4 additions & 4 deletions modules/hal_nxp/mcux/mcux-sdk-ng/middleware/middleware.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ if(CONFIG_USB_DEVICE_DRIVER)
set_variable_ifdef(CONFIG_USB_DC_NXP_LPCIP3511 CONFIG_MCUX_COMPONENT_middleware.usb.device.ip3511fs)

# For soc.c build pass
zephyr_include_directories(.)
zephyr_include_directories(${CMAKE_CURRENT_LIST_DIR})
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/device)
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/phy)
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/include)
Expand All @@ -30,13 +30,13 @@ if(CONFIG_UDC_DRIVER)
set_variable_ifdef(CONFIG_UDC_NXP_IP3511 CONFIG_MCUX_COMPONENT_middleware.usb.device.ip3511fs)

# For soc.c build pass
zephyr_include_directories(.)
zephyr_include_directories(${CMAKE_CURRENT_LIST_DIR})
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/device)
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/phy)
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/include)
endif()

if (CONFIG_UHC_DRIVER)
if(CONFIG_UHC_DRIVER)
zephyr_include_directories(middleware)

set(CONFIG_MCUX_COMPONENT_middleware.usb.common_header ON)
Expand All @@ -47,7 +47,7 @@ if (CONFIG_UHC_DRIVER)
set_variable_ifdef(CONFIG_UHC_NXP_OHCI CONFIG_MCUX_COMPONENT_middleware.usb.host.ohci)
set_variable_ifdef(CONFIG_UHC_NXP_IP3516HS CONFIG_MCUX_COMPONENT_middleware.usb.host.ip3516hs)
# For soc.c build pass
zephyr_include_directories(.)
zephyr_include_directories(${CMAKE_CURRENT_LIST_DIR})
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/phy)
zephyr_include_directories(${MCUX_SDK_NG_DIR}/middleware/usb/include)
endif()
Expand Down
Loading