Skip to content
Closed
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
4 changes: 4 additions & 0 deletions boards/nordic/nrf54l20pdk/nrf54l20pdk_nrf54l20_cpuapp.dts
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,7 @@
zephyr,sram = &cpuapp_sram;
};
};

zephyr_udc0: &usbhs {
status = "okay";
};
159 changes: 96 additions & 63 deletions drivers/usb/udc/udc_dwc2_vendor_quirks.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,11 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE)

#endif /*DT_HAS_COMPAT_STATUS_OKAY(st_stm32f4_fsotg) */

#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs)
#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) || \
DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l)

#define DT_DRV_COMPAT snps_dwc2

#include <nrfs_backend_ipc_service.h>
#include <nrfs_usb.h>

#define USBHS_DT_WRAPPER_REG_ADDR(n) UINT_TO_POINTER(DT_INST_REG_ADDR_BY_NAME(n, wrapper))

/*
Expand All @@ -125,7 +123,72 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_STM32F4_FSOTG_DEFINE)
* CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT timeout expires.
*/
static K_EVENT_DEFINE(usbhs_events);
#define USBHS_VBUS_READY BIT(0)
#define USBHS_VBUS_READY BIT(0)

static inline int usbhs_enable_core(const struct device *dev)
{
NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
k_timeout_t timeout = K_FOREVER;

#if CONFIG_NRFS_HAS_VBUS_DETECTOR_SERVICE
if (CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT) {
timeout = K_MSEC(CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT);
}
#endif

if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, K_NO_WAIT)) {
LOG_WRN("VBUS is not ready, block udc_enable()");
if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, timeout)) {
return -ETIMEDOUT;
}
}

wrapper->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk;
wrapper->TASKS_START = 1UL;

/* Wait for clock to start to avoid hang on too early register read */
k_busy_wait(1);

/* Enable interrupts */
wrapper->INTENSET = 1UL;

return 0;
}

static inline int usbhs_disable_core(const struct device *dev)
{
NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);

/* Disable interrupts */
wrapper->INTENCLR = 1UL;

wrapper->ENABLE = 0UL;
wrapper->TASKS_START = 1UL;

return 0;
}

static inline int usbhs_init_caps(const struct device *dev)
{
struct udc_data *data = dev->data;

data->caps.can_detect_vbus = true;
data->caps.hs = true;

return 0;
}

static inline int usbhs_is_phy_clk_off(const struct device *dev)
{
return !k_event_test(&usbhs_events, USBHS_VBUS_READY);
}

#endif /* nordic_nrf_usbhs || nordic_nrf_usbhs_nrf54l */

#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs)

#include <nrfs_backend_ipc_service.h>
#include <nrfs_usb.h>

static void usbhs_vbus_handler(nrfs_usb_evt_t const *p_evt, void *const context)
{
Expand Down Expand Up @@ -180,49 +243,6 @@ static inline int usbhs_enable_nrfs_service(const struct device *dev)
return 0;
}

static inline int usbhs_enable_core(const struct device *dev)
{
NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);
k_timeout_t timeout = K_FOREVER;

#if CONFIG_NRFS_HAS_VBUS_DETECTOR_SERVICE
if (CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT) {
timeout = K_MSEC(CONFIG_UDC_DWC2_USBHS_VBUS_READY_TIMEOUT);
}
#endif

if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, K_NO_WAIT)) {
LOG_WRN("VBUS is not ready, block udc_enable()");
if (!k_event_wait(&usbhs_events, USBHS_VBUS_READY, false, timeout)) {
return -ETIMEDOUT;
}
}

wrapper->ENABLE = USBHS_ENABLE_PHY_Msk | USBHS_ENABLE_CORE_Msk;
wrapper->TASKS_START = 1UL;

/* Wait for clock to start to avoid hang on too early register read */
k_busy_wait(1);

/* Enable interrupts */
wrapper->INTENSET = 1UL;

return 0;
}

static inline int usbhs_disable_core(const struct device *dev)
{
NRF_USBHS_Type *wrapper = USBHS_DT_WRAPPER_REG_ADDR(0);

/* Disable interrupts */
wrapper->INTENCLR = 1UL;

wrapper->ENABLE = 0UL;
wrapper->TASKS_START = 1UL;

return 0;
}

static inline int usbhs_disable_nrfs_service(const struct device *dev)
{
nrfs_err_t nrfs_err;
Expand All @@ -247,21 +267,6 @@ static inline int usbhs_irq_clear(const struct device *dev)
return 0;
}

static inline int usbhs_init_caps(const struct device *dev)
{
struct udc_data *data = dev->data;

data->caps.can_detect_vbus = true;
data->caps.hs = true;

return 0;
}

static inline int usbhs_is_phy_clk_off(const struct device *dev)
{
return !k_event_test(&usbhs_events, USBHS_VBUS_READY);
}

static inline int usbhs_post_hibernation_entry(const struct device *dev)
{
const struct udc_dwc2_config *const config = dev->config;
Expand Down Expand Up @@ -311,6 +316,34 @@ DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)

#endif /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs) */

#if DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l)

static inline int usbhs_enable_usbreg(const struct device *dev)
{
LOG_WRN("VBUS detection not implemented.");
k_event_post(&usbhs_events, USBHS_VBUS_READY);
udc_submit_event(dev, UDC_EVT_VBUS_READY, 0);

return 0;
}

#define QUIRK_NRF_USBHS_DEFINE(n) \
struct dwc2_vendor_quirks dwc2_vendor_quirks_##n = { \
.init = usbhs_enable_usbreg, \
.pre_enable = usbhs_enable_core, \
.disable = usbhs_disable_core, \
.shutdown = NULL, \
.irq_clear = NULL, \
.caps = usbhs_init_caps, \
.is_phy_clk_off = usbhs_is_phy_clk_off, \
.post_hibernation_entry = NULL, \
.pre_hibernation_exit = NULL, \
};

DT_INST_FOREACH_STATUS_OKAY(QUIRK_NRF_USBHS_DEFINE)

#endif /*DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_usbhs_nrf54l) */

/* Add next vendor quirks definition above this line */

#endif /* ZEPHYR_DRIVERS_USB_UDC_DWC2_VENDOR_QUIRKS_H */
13 changes: 13 additions & 0 deletions dts/common/nordic/nrf54l20.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,19 @@
prescaler = <0>;
};

usbhs: usbhs@5a000 {
compatible = "nordic,nrf-usbhs-nrf54l", "snps,dwc2";
reg = <0x5a000 0x1000>, <0x50020000 0x1a000>;
reg-names = "wrapper", "core";
interrupts = <90 NRF_DEFAULT_IRQ_PRIORITY>;
num-in-eps = <16>;
num-out-eps = <16>;
ghwcfg1 = <0x0>;
ghwcfg2 = <0x22affc52>;
ghwcfg4 = <0x3e10aa60>;
status = "disabled";
};

dppic10: dppic@82000 {
compatible = "nordic,nrf-dppic";
reg = <0x82000 0x808>;
Expand Down
Loading