summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYang Xijing <[email protected]>2023-11-04 23:31:14 +0800
committersakumisu <[email protected]>2023-11-05 14:38:26 +0800
commitae521bf95cd3949e9b7d7e83a1f4051c9c21a7c1 (patch)
treef9b03c4cdc3d09b40ca8347de21de416ddcbe505
parenta2f7b67dc40e61968ba7e08e22e2cec1611b4042 (diff)
add nuvoton port(not release)
-rw-r--r--port/nuvoton/README.md14
-rw-r--r--port/nuvoton/usb_dc_usbfs.c454
2 files changed, 468 insertions, 0 deletions
diff --git a/port/nuvoton/README.md b/port/nuvoton/README.md
new file mode 100644
index 00000000..1198c574
--- /dev/null
+++ b/port/nuvoton/README.md
@@ -0,0 +1,14 @@
+# Note
+
+## Support Chip List
+
+- M032 Series
+- M480 Series
+
+## Before Use
+
+Configure USBD_EPNUM.
+Your should implement `usb_dc_low_level_init` and `usb_dc_low_level_deinit`.
+- Enable or disable USB clock and set USB clock for 48M.
+- Enable or disable gpio and gpio clk for usb dp and dm.
+- Enable or disable usb irq
diff --git a/port/nuvoton/usb_dc_usbfs.c b/port/nuvoton/usb_dc_usbfs.c
new file mode 100644
index 00000000..cb2b5975
--- /dev/null
+++ b/port/nuvoton/usb_dc_usbfs.c
@@ -0,0 +1,454 @@
+#include <stdint.h>
+#include "NuMicro.h"
+#include "usbd_core.h"
+
+#ifndef USBD_IRQHandler
+#define USBD_IRQHandler USBD_IRQHandler
+#endif
+
+#ifndef USBD_EPNUM
+#define USBD_EPNUM 8
+#endif
+#define USB_NUM_BIDIR_ENDPOINTS (USBD_EPNUM >> 1)
+
+#define USBD_EP_GET_CONFIG(ep) (*((__IO uint32_t *)((uint32_t)&USBD->EP[0].CFG + (uint32_t)((ep) << 4))))
+
+/* Define EP maximum packet size */
+#define DEFAULT_EP_MAX_PKT_SIZE 64
+
+#define EP0_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP1_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP2_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP3_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP4_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP5_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP6_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP7_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP8_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP9_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP10_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+#define EP11_MAX_PKT_SIZE DEFAULT_EP_MAX_PKT_SIZE
+
+#define SETUP_BUF_BASE 0
+#define SETUP_BUF_LEN 8
+#define EP0_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
+#define EP0_BUF_LEN EP0_MAX_PKT_SIZE
+#define EP1_BUF_BASE (SETUP_BUF_BASE + SETUP_BUF_LEN)
+#define EP1_BUF_LEN EP1_MAX_PKT_SIZE
+#define EP2_BUF_BASE (EP1_BUF_BASE + EP1_BUF_LEN)
+#define EP2_BUF_LEN EP2_MAX_PKT_SIZE
+#define EP3_BUF_BASE (EP2_BUF_BASE + EP2_BUF_LEN)
+#define EP3_BUF_LEN EP3_MAX_PKT_SIZE
+#define EP4_BUF_BASE (EP3_BUF_BASE + EP3_BUF_LEN)
+#define EP4_BUF_LEN EP4_MAX_PKT_SIZE
+#define EP5_BUF_BASE (EP4_BUF_BASE + EP4_BUF_LEN)
+#define EP5_BUF_LEN EP5_MAX_PKT_SIZE
+#if USBD_EPNUM >= 8
+#define EP6_BUF_BASE (EP5_BUF_BASE + EP5_BUF_LEN)
+#define EP6_BUF_LEN EP6_MAX_PKT_SIZE
+#define EP7_BUF_BASE (EP6_BUF_BASE + EP6_BUF_LEN)
+#define EP7_BUF_LEN EP7_MAX_PKT_SIZE
+#if USBD_EPNUM >= 10
+#define EP8_BUF_BASE (EP7_BUF_BASE + EP7_BUF_LEN)
+#define EP8_BUF_LEN EP8_MAX_PKT_SIZE
+#define EP9_BUF_BASE (EP8_BUF_BASE + EP8_BUF_LEN)
+#define EP9_BUF_LEN EP9_MAX_PKT_SIZE
+#if USBD_EPNUM >= 12
+#define EP10_BUF_BASE (EP9_BUF_BASE + EP9_BUF_LEN)
+#define EP10_BUF_LEN EP10_MAX_PKT_SIZE
+#define EP11_BUF_BASE (EP10_BUF_BASE + EP10_BUF_LEN)
+#define EP11_BUF_LEN EP11_MAX_PKT_SIZE
+#endif
+#endif
+#endif
+
+#define USBD_EPNUM_FROM_IN_EPIDX(ep_idx) ((ep_idx) << 1)
+#define USBD_EPNUM_FROM_OUT_EPIDX(ep_idx) (((ep_idx) << 1) + 1)
+#define USBD_EPNUM_FROM_EPADDR(ep_addr) \
+ (USB_EP_DIR_IS_IN(ep_addr) ? USBD_EPNUM_FROM_IN_EPIDX(USB_EP_GET_IDX(ep_addr)) : USBD_EPNUM_FROM_OUT_EPIDX(USB_EP_GET_IDX(ep_addr)))
+
+/* Endpoint state */
+struct usb_dc_ep_state {
+ uint16_t ep_mps; /* Endpoint max packet size */
+ uint8_t ep_type; /* Endpoint type */
+ uint8_t ep_stalled; /* Endpoint stall flag */
+ uint8_t ep_enable; /* Endpoint enable */
+ uint8_t *xfer_buf;
+ uint32_t xfer_len;
+ uint32_t actual_xfer_len;
+ uint32_t mps_xfer_len;
+};
+
+/* Driver state */
+struct usb_dc_config_priv {
+ volatile uint8_t dev_addr;
+ struct usb_dc_ep_state in_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< IN endpoint parameters*/
+ struct usb_dc_ep_state out_ep[USB_NUM_BIDIR_ENDPOINTS]; /*!< OUT endpoint parameters */
+} g_nuvoton_udc;
+
+static uint8_t usdb_set_address_flag = 0;
+static uint8_t usbd_out_toggle[USB_NUM_BIDIR_ENDPOINTS] = { 0 };
+
+__WEAK void usb_dc_low_level_init(void)
+{
+}
+
+__WEAK void usb_dc_low_level_deinit(void)
+{
+}
+
+int usb_dc_init(void)
+{
+ memset(&g_nuvoton_udc, 0, sizeof(g_nuvoton_udc));
+
+ usb_dc_low_level_init();
+
+ /*****************************************************/
+ /* Initial USB engine */
+ USBD->ATTR = 0x6D0ul;
+ /* Force SE0 */
+ USBD_SET_SE0();
+
+ /*****************************************************/
+ /* Init setup packet buffer */
+ /* Buffer for setup packet -> [0 ~ 0x7] */
+ USBD->STBUFSEG = SETUP_BUF_BASE;
+
+ USBD_SET_EP_BUF_ADDR(EP0, EP0_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP1, EP1_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP2, EP2_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP3, EP3_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP4, EP4_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP5, EP5_BUF_BASE);
+#if USBD_EPNUM >= 8
+ USBD_SET_EP_BUF_ADDR(EP6, EP6_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP7, EP7_BUF_BASE);
+#if USBD_EPNUM >= 10
+ USBD_SET_EP_BUF_ADDR(EP8, EP8_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP9, EP9_BUF_BASE);
+ USBD_SET_EP_BUF_ADDR(EP10, EP10_BUF_BASE);
+#if USBD_EPNUM >= 12
+ USBD_SET_EP_BUF_ADDR(EP11, EP11_BUF_BASE);
+#endif
+#endif
+#endif
+
+ /*****************************************************/
+ /* USB start */
+ /* Disable software-disconnect function */
+ USBD_CLR_SE0();
+ USBD->ATTR = 0x7D0ul;
+
+ /* Clear USB-related interrupts before enable interrupt */
+ USBD_CLR_INT_FLAG(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
+
+ /* Enable USB-related interrupts. */
+ USBD_ENABLE_INT(USBD_INT_BUS | USBD_INT_USB | USBD_INT_FLDET | USBD_INT_WAKEUP);
+ /*****************************************************/
+
+ return 0;
+}
+
+int usb_dc_deinit(void)
+{
+ USBD->ATTR = 0x00000040;
+ /* Force SE0 */
+ USBD_SET_SE0();
+
+ return 0;
+}
+
+int usbd_set_address(const uint8_t addr)
+{
+ uint8_t usbd_addr = USBD_GET_ADDR();
+ if ((usbd_addr == 0) && (usbd_addr != addr)) {
+ g_nuvoton_udc.dev_addr = addr;
+ usdb_set_address_flag = 1;
+ }
+
+ return 0;
+}
+
+uint8_t usbd_get_port_speed(const uint8_t port)
+{
+ return USB_SPEED_FULL;
+}
+
+int usbd_ep_open(const struct usbd_endpoint_cfg *ep_cfg)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep_cfg->ep_addr);
+
+ if (USB_EP_DIR_IS_IN(ep_cfg->ep_addr)) {
+ uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep_idx);
+
+ g_nuvoton_udc.in_ep[ep_idx].ep_mps = ep_cfg->ep_mps;
+ g_nuvoton_udc.in_ep[ep_idx].ep_type = ep_cfg->ep_type;
+ g_nuvoton_udc.in_ep[ep_idx].ep_enable = true;
+ if (ep_idx == 0) {
+ /* EP0 ==> control IN endpoint, address 0 */
+ USBD_CONFIG_EP(EP0, USBD_CFG_CSTALL | USBD_CFG_EPMODE_IN | 0);
+ } else {
+ USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_IN | ep_idx);
+ USBD_STOP_TRANSACTION(epnum);
+ }
+ } else {
+ uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep_idx);
+
+ g_nuvoton_udc.out_ep[ep_idx].ep_mps = ep_cfg->ep_mps;
+ g_nuvoton_udc.out_ep[ep_idx].ep_type = ep_cfg->ep_type;
+ g_nuvoton_udc.out_ep[ep_idx].ep_enable = true;
+ if (ep_idx == 0) {
+ /* EP1 ==> control OUT endpoint, address 0 */
+ USBD_CONFIG_EP(EP1, USBD_CFG_CSTALL | USBD_CFG_EPMODE_OUT | 0);
+ } else {
+ USBD_CONFIG_EP(epnum, USBD_CFG_EPMODE_OUT | ep_idx);
+ USBD_STOP_TRANSACTION(epnum);
+ }
+ }
+
+ return 0;
+}
+
+int usbd_ep_close(const uint8_t ep)
+{
+ USBD->EP[USBD_EPNUM_FROM_EPADDR(ep)].CFG &= ~USBD_CFG_STATE_Msk; // disable endpoint
+ return 0;
+}
+
+int usbd_ep_set_stall(const uint8_t ep)
+{
+ USBD_SET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
+ return 0;
+}
+
+int usbd_ep_clear_stall(const uint8_t ep)
+{
+ USBD_CLR_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep));
+ return 0;
+}
+
+int usbd_ep_is_stalled(const uint8_t ep, uint8_t *stalled)
+{
+ *stalled = USBD_GET_EP_STALL(USBD_EPNUM_FROM_EPADDR(ep)) > 0 ? 1 : 0;
+ return 0;
+}
+
+int usbd_ep_start_write(const uint8_t ep, const uint8_t *data, uint32_t data_len)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+
+ if (!data && data_len) {
+ return -1;
+ }
+ if (!g_nuvoton_udc.in_ep[ep_idx].ep_enable) {
+ return -2;
+ }
+
+ uint8_t epnum = USBD_EPNUM_FROM_IN_EPIDX(ep);
+
+ g_nuvoton_udc.in_ep[ep_idx].xfer_buf = (uint8_t *)data;
+ g_nuvoton_udc.in_ep[ep_idx].xfer_len = data_len;
+ g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len = 0;
+
+ if (data_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
+ data_len = g_nuvoton_udc.in_ep[ep_idx].ep_mps;
+ }
+
+ if (epnum == 0) {
+ USBD_SET_DATA1(epnum);
+ }
+
+ USBD_MemCopy((uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), (uint8_t *)data, data_len);
+ USBD_SET_PAYLOAD_LEN(epnum, data_len);
+
+ return 0;
+}
+
+int usbd_ep_start_read(const uint8_t ep, uint8_t *data, uint32_t data_len)
+{
+ uint8_t ep_idx = USB_EP_GET_IDX(ep);
+
+ if (!data && data_len) {
+ return -1;
+ }
+ if (!g_nuvoton_udc.out_ep[ep_idx].ep_enable) {
+ return -2;
+ }
+
+ uint8_t epnum = USBD_EPNUM_FROM_OUT_EPIDX(ep);
+
+ g_nuvoton_udc.out_ep[ep_idx].xfer_buf = (uint8_t *)data;
+ g_nuvoton_udc.out_ep[ep_idx].xfer_len = data_len;
+ g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len = 0;
+
+ if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
+ g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
+ } else {
+ g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
+ }
+
+ USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
+
+ return 0;
+}
+
+void USBD_IRQHandler(void)
+{
+ uint32_t int_flag = USBD_GET_INT_FLAG();
+ uint32_t bus_state = USBD_GET_BUS_STATE();
+
+ if (int_flag & USBD_INTSTS_FLDET) {
+ // Floating detect
+ USBD_CLR_INT_FLAG(USBD_INTSTS_FLDET);
+
+ if (USBD_IS_ATTACHED()) {
+ /* USB Plug In */
+ USBD_ENABLE_USB();
+ usbd_event_connect_handler();
+ } else {
+ /* USB Un-plug */
+ USBD_DISABLE_USB();
+ usbd_event_disconnect_handler();
+ }
+ }
+
+ //------------------------------------------------------------------
+ if (int_flag & USBD_INTSTS_BUS) {
+ /* Clear event flag */
+ USBD_CLR_INT_FLAG(USBD_INTSTS_BUS);
+
+ if (bus_state & USBD_STATE_USBRST) {
+ /* Bus reset */
+ USBD_ENABLE_USB();
+
+ memset((usbd_out_toggle + 1), 0, (USB_NUM_BIDIR_ENDPOINTS - 1));
+
+ for (uint8_t i = 0; i < USBD_MAX_EP; i++) {
+ USBD->EP[i].CFG = 0; // default value
+ }
+
+ USBD_SET_ADDR(0ul);
+ g_nuvoton_udc.dev_addr = 0;
+
+ usbd_event_reset_handler();
+ }
+
+ if (bus_state & USBD_STATE_SUSPEND) {
+ /* Enable USB but disable PHY */
+ USBD_DISABLE_PHY();
+ usbd_event_suspend_handler();
+ }
+ if (bus_state & USBD_STATE_RESUME) {
+ /* Enable USB and enable PHY */
+ USBD_ENABLE_USB();
+ usbd_event_resume_handler();
+ }
+ }
+
+ //------------------------------------------------------------------
+ if (int_flag & USBD_INTSTS_WAKEUP) {
+ /* Clear event flag */
+ USBD_CLR_INT_FLAG(USBD_INTSTS_WAKEUP);
+ }
+
+ if (int_flag & USBD_INTSTS_USB) {
+ // USB event
+ if (int_flag & USBD_INTSTS_SETUP) {
+ // Setup packet
+ /* Clear event flag */
+ USBD_CLR_INT_FLAG(USBD_INTSTS_SETUP);
+
+ /* Clear the data IN/OUT ready flag of control end-points */
+ USBD_STOP_TRANSACTION(EP0);
+ USBD_STOP_TRANSACTION(EP1);
+
+ usbd_out_toggle[0] = 0;
+ usbd_event_ep0_setup_complete_handler((uint8_t *)(USBD_BUF_BASE));
+ }
+
+ if (int_flag & USBD_INTSTS_EP0) {
+ /* In ACK for Set address */
+ if (usdb_set_address_flag == 1) {
+ USBD_SET_ADDR(g_nuvoton_udc.dev_addr);
+ usdb_set_address_flag = 0;
+ }
+ }
+
+ // if (int_flag & USBD_INTSTS_EP1)
+ // {
+ // }
+
+ for (uint8_t epnum = 0; epnum < USBD_EPNUM; epnum++) {
+ if (int_flag & (USBD_INTSTS_EP0 << epnum)) {
+ USBD_CLR_INT_FLAG((USBD_INTSTS_EP0 << epnum));
+
+ uint8_t ep_cfg = USBD_EP_GET_CONFIG(epnum);
+
+ uint8_t ep_state = 0;
+#if USBD_EPNUM >= 10
+ if (epnum > 7) {
+ ep_state = (USBD->EPSTS1 >> ((epnum - 8) * 4)) & 0x0f;
+ } else
+#endif
+ {
+ ep_state = (USBD->EPSTS0 >> (epnum * 4)) & 0x0f;
+ }
+
+ uint8_t ep_cfg_state = (ep_cfg & USBD_CFG_STATE_Msk) >> USBD_CFG_STATE_Pos;
+
+ if (ep_cfg_state == 0x01) {
+ // OUT
+ uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
+
+ if (ep_state == usbd_out_toggle[ep_idx]) {
+ USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].ep_mps);
+ } else {
+ uint32_t recv_count = USBD_GET_PAYLOAD_LEN(epnum);
+
+ USBD_MemCopy((uint8_t *)g_nuvoton_udc.out_ep[ep_idx].xfer_buf,
+ (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum)), recv_count);
+
+ g_nuvoton_udc.out_ep[ep_idx].xfer_buf += recv_count;
+ g_nuvoton_udc.out_ep[ep_idx].xfer_len -= recv_count;
+ g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len += recv_count;
+
+ usbd_out_toggle[ep_idx] = ep_state;
+
+ if ((recv_count < g_nuvoton_udc.out_ep[ep_idx].ep_mps) ||
+ (g_nuvoton_udc.out_ep[ep_idx].xfer_len == 0)) {
+ usbd_event_ep_out_complete_handler(ep_idx, g_nuvoton_udc.out_ep[ep_idx].actual_xfer_len);
+ } else {
+ if (g_nuvoton_udc.out_ep[ep_idx].xfer_len < g_nuvoton_udc.out_ep[ep_idx].ep_mps) {
+ g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].xfer_len;
+ } else {
+ g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len = g_nuvoton_udc.out_ep[ep_idx].ep_mps;
+ }
+
+ USBD_SET_PAYLOAD_LEN(epnum, g_nuvoton_udc.out_ep[ep_idx].mps_xfer_len);
+ }
+ }
+ } else if (ep_cfg_state == 0x02) {
+ uint8_t ep_idx = ep_cfg & USBD_CFG_EPNUM_Msk;
+ // In Ack
+
+ if (g_nuvoton_udc.in_ep[ep_idx].xfer_len > g_nuvoton_udc.in_ep[ep_idx].ep_mps) {
+ g_nuvoton_udc.in_ep[ep_idx].xfer_buf += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
+ g_nuvoton_udc.in_ep[ep_idx].xfer_len -= g_nuvoton_udc.in_ep[ep_idx].ep_mps;
+ g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].ep_mps;
+
+ uint16_t min_len = MIN(g_nuvoton_udc.in_ep[ep_idx].xfer_len, g_nuvoton_udc.in_ep[ep_idx].ep_mps);
+
+ uint8_t *usbd_ep_buf_addr = (uint8_t *)(USBD_BUF_BASE + USBD_GET_EP_BUF_ADDR(epnum));
+ USBD_MemCopy(usbd_ep_buf_addr, g_nuvoton_udc.in_ep[ep_idx].xfer_buf, min_len);
+ USBD_SET_PAYLOAD_LEN(epnum, min_len);
+ } else {
+ g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len += g_nuvoton_udc.in_ep[ep_idx].xfer_len;
+ g_nuvoton_udc.in_ep[ep_idx].xfer_len = 0;
+
+ usbd_event_ep_in_complete_handler(ep_idx | 0x80, g_nuvoton_udc.in_ep[ep_idx].actual_xfer_len);
+ }
+ }
+ }
+ }
+ }
+}