Skip to content

Commit 7bd64c2

Browse files
committed
drivers: udc_ambiq: added support for apollo510
Added handling specific to apollo510 and new feature supported by the soc. Signed-off-by: Chew Zeh Yang <[email protected]>
1 parent 6ea3fd4 commit 7bd64c2

File tree

2 files changed

+182
-13
lines changed

2 files changed

+182
-13
lines changed

drivers/usb/udc/Kconfig.ambiq

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ config UDC_AMBIQ
88
select GPIO
99
select AMBIQ_HAL
1010
select AMBIQ_HAL_USE_USB
11+
select UDC_DRIVER_HAS_HIGH_SPEED_SUPPORT
1112
help
1213
Enable USB Device Controller Driver.
1314

@@ -25,12 +26,67 @@ config UDC_AMBIQ_THREAD_PRIORITY
2526
help
2627
AMBIQ driver thread priority.
2728

28-
2929
config UDC_AMBIQ_MAX_QMESSAGES
3030
int "UDC AMBIQ maximum number of ISR event messages"
3131
range 4 64
3232
default 8
3333
help
3434
AMBIQ maximum number of ISR event messages.
3535

36+
choice UDC_AMBIQ_DMA_MODE
37+
prompt "DMA mode for non-control USB endpoints"
38+
default UDC_AMBIQ_DMA0_MODE
39+
depends on SOC_SERIES_APOLLO5X
40+
41+
config UDC_AMBIQ_DMA0_MODE
42+
bool "DMA0 transfer mode"
43+
help
44+
Select this config when synchronous endpoint is used.
45+
46+
config UDC_AMBIQ_DMA1_MODE
47+
bool "DMA1 transfer mode"
48+
help
49+
This config gives best throughput when endpoint buffer is greater than Max
50+
Packet Size. However this option cannot be chosen when synchronous
51+
endpoint is used.
52+
53+
config UDC_AMBIQ_PIO_MODE
54+
bool "PIO transfer mode"
55+
help
56+
Select this config when cache coherency handling is to be
57+
avoided.
58+
endchoice
59+
60+
config UDC_AMBIQ_HANDLE_CACHE
61+
bool "Cache handling enable for USB non-control endpoint buffers"
62+
default y
63+
depends on CACHE_MANAGEMENT
64+
depends on DCACHE
65+
depends on !UDC_BUF_FORCE_NOCACHE
66+
depends on UDC_AMBIQ_DMA0_MODE || UDC_AMBIQ_DMA1_MODE
67+
help
68+
Disable this if non-cacheable memory is selected as default system memory
69+
70+
config UDC_AMBIQ_ISR_PARAM_COUNT
71+
int "Parameter count for ISR handler"
72+
default 5 if SOC_SERIES_APOLLO5X
73+
default 3
74+
75+
config UDC_AMBIQ_DEB_ENABLE
76+
hex "EP Double Buffer Enable"
77+
default 0x0000
78+
depends on SOC_SERIES_APOLLO5X
79+
help
80+
Double Endpoint Buffer acceleration (DEB) is doubles an EP's FIFO size
81+
so that USB transfer could continue to happen while waiting for DMA/CPU to
82+
load/unload data from the EP FIFO.
83+
This hex value is a bitmap of endpoints for DEB to be enabled. BIT0-4
84+
represents OUT_EP 1-5, while BIT16-20 represents IN_EP 1-8.
85+
Take note that this feature is limited by total EP FIFO size. Proper
86+
calculation should be done before enabling DEB such that the total usage
87+
of FIFO for all endpoint doesn't exceed the FIFO available on SoC.
88+
The list of Soc with its FIFO size is listed below. The FIFO size here
89+
includes 128 bytes required by control endpoints.
90+
- Apollo510: (4096 Bytes FIFO)
91+
3692
endif # UDC_AMBIQ

drivers/usb/udc/udc_ambiq.c

Lines changed: 125 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ static int udc_ambiq_tx(const struct device *dev, uint8_t ep, struct net_buf *bu
107107
if (buf == NULL) {
108108
status = am_hal_usb_ep_xfer(priv->usb_handle, ep, NULL, 0);
109109
} else {
110+
#if defined(CONFIG_UDC_AMBIQ_HANDLE_CACHE)
111+
/* Cache management if cache and DMA is enabled */
112+
if ((ep != USB_CONTROL_EP_OUT) &&
113+
!buf_in_nocache((uintptr_t)buf->data, buf->size)) {
114+
sys_cache_data_flush_range(buf->data, buf->size);
115+
}
116+
#endif
110117
status = am_hal_usb_ep_xfer(priv->usb_handle, ep, buf->data, buf->len);
111118
}
112119

@@ -123,7 +130,6 @@ static int udc_ambiq_rx(const struct device *dev, uint8_t ep, struct net_buf *bu
123130
{
124131
struct udc_ambiq_data *priv = udc_get_private(dev);
125132
struct udc_ep_config *ep_cfg = udc_get_ep_cfg(dev, ep);
126-
struct udc_ep_config *cfg = udc_get_ep_cfg(dev, USB_CONTROL_EP_OUT);
127133
uint32_t status;
128134
uint16_t rx_size = buf->size;
129135

@@ -133,10 +139,24 @@ static int udc_ambiq_rx(const struct device *dev, uint8_t ep, struct net_buf *bu
133139
}
134140
udc_ep_set_busy(ep_cfg, true);
135141

136-
/* Make sure that OUT transaction size triggered doesn't exceed EP's MPS */
137-
if ((ep != USB_CONTROL_EP_OUT) && (cfg->mps < rx_size)) {
138-
rx_size = cfg->mps;
142+
#ifndef CONFIG_UDC_AMBIQ_DMA1_MODE
143+
/*
144+
* Make sure that OUT transaction size triggered doesn't exceed EP's MPS,
145+
* as the USB IP has no way to detect end on transaction when last packet
146+
* is not a short packet. Except for UDC_AMBIQ_DMA1_MODE, where such
147+
* detection is available.
148+
*/
149+
if ((ep != USB_CONTROL_EP_OUT) && (ep_cfg->mps < rx_size)) {
150+
rx_size = ep_cfg->mps;
151+
}
152+
#endif
153+
154+
#if CONFIG_UDC_AMBIQ_HANDLE_CACHE
155+
/* Cache management if cache and DMA is enabled */
156+
if ((ep != USB_CONTROL_EP_OUT) && !buf_in_nocache((uintptr_t)buf->data, buf->size)) {
157+
sys_cache_data_invd_range(buf->data, buf->size);
139158
}
159+
#endif
140160

141161
status = am_hal_usb_ep_xfer(priv->usb_handle, ep, buf->data, rx_size);
142162
if (status != AM_HAL_STATUS_SUCCESS) {
@@ -212,7 +232,7 @@ static void udc_ambiq_ep0_setup_callback(const struct device *dev, uint8_t *usb_
212232
}
213233

214234
static void udc_ambiq_ep_xfer_complete_callback(const struct device *dev, uint8_t ep_addr,
215-
uint16_t xfer_len, am_hal_usb_xfer_code_e code,
235+
uint32_t xfer_len, am_hal_usb_xfer_code_e code,
216236
void *param)
217237
{
218238
struct net_buf *buf;
@@ -470,14 +490,18 @@ static int udc_ambiq_disable(const struct device *dev)
470490
return 0;
471491
}
472492

493+
#define DEFINE_ISR_PARAM_DEF(x, _) CONCAT(uint32_t int_status, x)
494+
#define DEFINE_ISR_PARAM_PTR(x, _) CONCAT(&int_status, x)
495+
#define DEFINE_ISR_PARAM(x, _) CONCAT(int_status, x)
496+
473497
static void udc_ambiq_usb_isr(const struct device *dev)
474498
{
475499
struct udc_ambiq_data *priv = udc_get_private(dev);
476-
uint32_t int_status[3];
477-
478-
am_hal_usb_intr_status_get(priv->usb_handle, &int_status[0], &int_status[1],
479-
&int_status[2]);
480-
am_hal_usb_interrupt_service(priv->usb_handle, int_status[0], int_status[1], int_status[2]);
500+
LISTIFY(CONFIG_UDC_AMBIQ_ISR_PARAM_COUNT, DEFINE_ISR_PARAM_DEF, (;));
501+
am_hal_usb_intr_status_get(priv->usb_handle, LISTIFY(CONFIG_UDC_AMBIQ_ISR_PARAM_COUNT,
502+
DEFINE_ISR_PARAM_PTR, (,)));
503+
am_hal_usb_interrupt_service(
504+
priv->usb_handle, LISTIFY(CONFIG_UDC_AMBIQ_ISR_PARAM_COUNT, DEFINE_ISR_PARAM, (,)));
481505
}
482506

483507
static int usb_power_rails_set(const struct device *dev, bool on)
@@ -516,11 +540,54 @@ static int usb_power_rails_set(const struct device *dev, bool on)
516540
return 0;
517541
}
518542

543+
#if CONFIG_SOC_SERIES_APOLLO5X
544+
static int init_apollo5x(const struct udc_ambiq_data *priv)
545+
{
546+
uint32_t am_ret = AM_HAL_STATUS_SUCCESS;
547+
am_hal_clkmgr_board_info_t board;
548+
am_hal_usb_phyclksrc_e phyclksrc;
549+
550+
/* Decide PHY clock source according to USB speed and board configuration*/
551+
am_hal_clkmgr_board_info_get(&board);
552+
if (priv->usb_speed == AM_HAL_USB_SPEED_FULL) {
553+
phyclksrc = AM_HAL_USB_PHYCLKSRC_HFRC_24M;
554+
} else if (board.sXtalHs.ui32XtalHsFreq == 48000000) {
555+
phyclksrc = AM_HAL_USB_PHYCLKSRC_XTAL_HS_DIV2;
556+
} else if (board.sXtalHs.ui32XtalHsFreq == 24000000) {
557+
phyclksrc = AM_HAL_USB_PHYCLKSRC_XTAL_HS;
558+
} else if (board.ui32ExtRefClkFreq == 48000000) {
559+
phyclksrc = AM_HAL_USB_PHYCLKSRC_EXTREFCLK;
560+
} else if (board.ui32ExtRefClkFreq == 24000000) {
561+
phyclksrc = AM_HAL_USB_PHYCLKSRC_EXTREFCLK_DIV2;
562+
} else {
563+
phyclksrc = AM_HAL_USB_PHYCLKSRC_PLL;
564+
}
565+
566+
if (phyclksrc == AM_HAL_USB_PHYCLKSRC_PLL) {
567+
am_ret = am_hal_clkmgr_clock_config(AM_HAL_CLKMGR_CLK_ID_SYSPLL, 24000000, NULL);
568+
if (am_ret != AM_HAL_STATUS_SUCCESS) {
569+
LOG_WRN("Unable to configure SYSPLL for USB. Fallback to HFRC clock "
570+
"source");
571+
phyclksrc = AM_HAL_USB_PHYCLKSRC_HFRC_24M;
572+
}
573+
}
574+
575+
am_hal_usb_set_phy_clk_source(priv->usb_handle, phyclksrc);
576+
am_hal_usb_phy_clock_enable(priv->usb_handle, true, priv->usb_speed);
577+
578+
return 0;
579+
}
580+
#endif
581+
519582
static int udc_ambiq_init(const struct device *dev)
520583
{
521584
struct udc_ambiq_data *priv = udc_get_private(dev);
522585
const struct udc_ambiq_config *cfg = dev->config;
523586
uint32_t ret = 0;
587+
#if CONFIG_UDC_AMBIQ_DEB_ENABLE
588+
uint8_t idx;
589+
uint32_t mask;
590+
#endif
524591

525592
/* Create USB */
526593
if (am_hal_usb_initialize(0, (void *)&priv->usb_handle) != AM_HAL_STATUS_SUCCESS) {
@@ -542,10 +609,51 @@ static int udc_ambiq_init(const struct device *dev)
542609
am_hal_usb_hardware_unreset();
543610
/* Release USB PHY reset */
544611
am_hal_usb_disable_phy_reset_override();
612+
613+
#if CONFIG_SOC_SERIES_APOLLO5X
614+
ret = init_apollo5x(priv);
615+
if (ret) {
616+
return ret;
617+
}
618+
#endif
619+
620+
#if CONFIG_UDC_AMBIQ_DEB_ENABLE
621+
idx = 1;
622+
mask = CONFIG_UDC_AMBIQ_DEB_ENABLE & 0xFFFF;
623+
while (mask) {
624+
if (mask & 0x1) {
625+
am_hal_usb_enable_ep_double_buffer(priv->usb_handle, idx,
626+
AM_HAL_USB_OUT_DIR, true);
627+
}
628+
idx++;
629+
mask >>= 1;
630+
}
631+
632+
idx = 1;
633+
mask = (CONFIG_UDC_AMBIQ_DEB_ENABLE >> 16) & 0xFFFF;
634+
while (mask) {
635+
if (mask & 0x1) {
636+
am_hal_usb_enable_ep_double_buffer(priv->usb_handle, idx, AM_HAL_USB_IN_DIR,
637+
true);
638+
}
639+
idx++;
640+
mask >>= 1;
641+
}
642+
#endif
643+
545644
/* Set USB Speed */
546645
am_hal_usb_set_dev_speed(priv->usb_handle, priv->usb_speed);
547646
/* Enable USB interrupt */
548647
am_hal_usb_intr_usb_enable(priv->usb_handle, USB_INTRUSB_Reset_Msk);
648+
/* Configure DMA Modes */
649+
#if CONFIG_UDC_AMBIQ_DMA1_MODE
650+
am_hal_usb_set_xfer_mode(priv->usb_handle, AM_HAL_USB_OUT_DMA_MODE_1);
651+
am_hal_usb_set_xfer_mode(priv->usb_handle, AM_HAL_USB_IN_DMA_MODE_1);
652+
#elif CONFIG_UDC_AMBIQ_DMA0_MODE
653+
am_hal_usb_set_xfer_mode(priv->usb_handle, AM_HAL_USB_OUT_DMA_MODE_0);
654+
am_hal_usb_set_xfer_mode(priv->usb_handle, AM_HAL_USB_IN_DMA_MODE_0);
655+
#endif
656+
549657
/* Enable Control Endpoints */
550658
if (udc_ep_enable_internal(dev, USB_CONTROL_EP_OUT, USB_EP_TYPE_CONTROL, EP0_MPS, 0)) {
551659
LOG_ERR("Failed to enable control endpoint");
@@ -582,6 +690,10 @@ static int udc_ambiq_shutdown(const struct device *dev)
582690
cfg->irq_disable_func(dev);
583691
/* Assert USB PHY reset */
584692
am_hal_usb_enable_phy_reset_override();
693+
#if CONFIG_SOC_SERIES_APOLLO5X
694+
/* Release USB PHY Clock*/
695+
am_hal_usb_phy_clock_enable(priv->usb_handle, false, priv->usb_speed);
696+
#endif
585697
/* Disable the USB power rails */
586698
ret = usb_power_rails_set(dev, false);
587699
if (ret) {
@@ -911,7 +1023,7 @@ static const struct udc_api udc_ambiq_api = {
9111023
} \
9121024
\
9131025
static void udc_ambiq_ep_xfer_complete_callback_##n( \
914-
uint8_t ep_addr, uint16_t xfer_len, am_hal_usb_xfer_code_e code, void *param) \
1026+
uint8_t ep_addr, uint32_t xfer_len, am_hal_usb_xfer_code_e code, void *param) \
9151027
{ \
9161028
udc_ambiq_ep_xfer_complete_callback(DEVICE_DT_INST_GET(n), ep_addr, xfer_len, \
9171029
code, param); \
@@ -926,7 +1038,8 @@ static const struct udc_api udc_ambiq_api = {
9261038
am_hal_usb_register_ep0_setup_received_callback(priv->usb_handle, \
9271039
udc_ambiq_ep0_setup_callback_##n); \
9281040
am_hal_usb_register_ep_xfer_complete_callback( \
929-
priv->usb_handle, udc_ambiq_ep_xfer_complete_callback_##n); \
1041+
priv->usb_handle, (am_hal_usb_ep_xfer_complete_callback) \
1042+
udc_ambiq_ep_xfer_complete_callback_##n); \
9301043
} \
9311044
static void udc_ambiq_thread_##n(void *dev, void *arg1, void *arg2) \
9321045
{ \

0 commit comments

Comments
 (0)