19a138eb5SPatrick Delaunay /* 29a138eb5SPatrick Delaunay * Copyright (c) 2021, STMicroelectronics - All Rights Reserved 39a138eb5SPatrick Delaunay * 49a138eb5SPatrick Delaunay * SPDX-License-Identifier: BSD-3-Clause 59a138eb5SPatrick Delaunay */ 69a138eb5SPatrick Delaunay 7*02af589cSBoyan Karatotev #include <assert.h> 89a138eb5SPatrick Delaunay #include <stdint.h> 99a138eb5SPatrick Delaunay 109a138eb5SPatrick Delaunay #include <arch_helpers.h> 119a138eb5SPatrick Delaunay #include <common/debug.h> 129a138eb5SPatrick Delaunay #include <drivers/delay_timer.h> 139a138eb5SPatrick Delaunay #include <drivers/st/stm32mp1_usb.h> 149a138eb5SPatrick Delaunay #include <lib/mmio.h> 159a138eb5SPatrick Delaunay 169a138eb5SPatrick Delaunay #include <platform_def.h> 179a138eb5SPatrick Delaunay 189a138eb5SPatrick Delaunay #define USB_OTG_MODE_DEVICE 0U 199a138eb5SPatrick Delaunay #define USB_OTG_MODE_HOST 1U 209a138eb5SPatrick Delaunay #define USB_OTG_MODE_DRD 2U 219a138eb5SPatrick Delaunay 229a138eb5SPatrick Delaunay #define EP_TYPE_CTRL 0U 239a138eb5SPatrick Delaunay #define EP_TYPE_ISOC 1U 249a138eb5SPatrick Delaunay #define EP_TYPE_BULK 2U 259a138eb5SPatrick Delaunay #define EP_TYPE_INTR 3U 269a138eb5SPatrick Delaunay 279a138eb5SPatrick Delaunay #define USBD_FIFO_FLUSH_TIMEOUT_US 1000U 289a138eb5SPatrick Delaunay #define EP0_FIFO_SIZE 64U 299a138eb5SPatrick Delaunay 309a138eb5SPatrick Delaunay /* OTG registers offsets */ 319a138eb5SPatrick Delaunay #define OTG_GOTGINT 0x004U 329a138eb5SPatrick Delaunay #define OTG_GAHBCFG 0x008U 339a138eb5SPatrick Delaunay #define OTG_GUSBCFG 0x00CU 349a138eb5SPatrick Delaunay #define OTG_GRSTCTL 0x010U 359a138eb5SPatrick Delaunay #define OTG_GINTSTS 0x014U 369a138eb5SPatrick Delaunay #define OTG_GINTMSK 0x018U 379a138eb5SPatrick Delaunay #define OTG_GRXSTSP 0x020U 389a138eb5SPatrick Delaunay #define OTG_GLPMCFG 0x054U 399a138eb5SPatrick Delaunay #define OTG_DCFG 0x800U 409a138eb5SPatrick Delaunay #define OTG_DCTL 0x804U 419a138eb5SPatrick Delaunay #define OTG_DSTS 0x808U 429a138eb5SPatrick Delaunay #define OTG_DIEPMSK 0x810U 439a138eb5SPatrick Delaunay #define OTG_DOEPMSK 0x814U 449a138eb5SPatrick Delaunay #define OTG_DAINT 0x818U 459a138eb5SPatrick Delaunay #define OTG_DAINTMSK 0x81CU 469a138eb5SPatrick Delaunay #define OTG_DIEPEMPMSK 0x834U 479a138eb5SPatrick Delaunay 489a138eb5SPatrick Delaunay /* Definitions for OTG_DIEPx registers */ 499a138eb5SPatrick Delaunay #define OTG_DIEP_BASE 0x900U 509a138eb5SPatrick Delaunay #define OTG_DIEP_SIZE 0x20U 519a138eb5SPatrick Delaunay #define OTG_DIEPCTL 0x00U 529a138eb5SPatrick Delaunay #define OTG_DIEPINT 0x08U 539a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ 0x10U 549a138eb5SPatrick Delaunay #define OTG_DIEPDMA 0x14U 559a138eb5SPatrick Delaunay #define OTG_DTXFSTS 0x18U 569a138eb5SPatrick Delaunay #define OTG_DIEP_MAX_NB 9U 579a138eb5SPatrick Delaunay 589a138eb5SPatrick Delaunay /* Definitions for OTG_DOEPx registers */ 599a138eb5SPatrick Delaunay #define OTG_DOEP_BASE 0xB00U 609a138eb5SPatrick Delaunay #define OTG_DOEP_SIZE 0x20U 619a138eb5SPatrick Delaunay #define OTG_DOEPCTL 0x00U 629a138eb5SPatrick Delaunay #define OTG_DOEPINT 0x08U 639a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ 0x10U 649a138eb5SPatrick Delaunay #define OTG_DOEPDMA 0x14U 659a138eb5SPatrick Delaunay #define OTG_D0EP_MAX_NB 9U 669a138eb5SPatrick Delaunay 679a138eb5SPatrick Delaunay /* Definitions for OTG_DAINT registers */ 689a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_MASK GENMASK(31, 16) 699a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_SHIFT 16U 709a138eb5SPatrick Delaunay #define OTG_DAINT_IN_MASK GENMASK(15, 0) 719a138eb5SPatrick Delaunay #define OTG_DAINT_IN_SHIFT 0U 729a138eb5SPatrick Delaunay 739a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_IN BIT(16) 749a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_OUT BIT(0) 759a138eb5SPatrick Delaunay 769a138eb5SPatrick Delaunay /* Definitions for FIFOs */ 779a138eb5SPatrick Delaunay #define OTG_FIFO_BASE 0x1000U 789a138eb5SPatrick Delaunay #define OTG_FIFO_SIZE 0x1000U 799a138eb5SPatrick Delaunay 809a138eb5SPatrick Delaunay /* Bit definitions for OTG_GOTGINT register */ 819a138eb5SPatrick Delaunay #define OTG_GOTGINT_SEDET BIT(2) 829a138eb5SPatrick Delaunay 839a138eb5SPatrick Delaunay /* Bit definitions for OTG_GAHBCFG register */ 849a138eb5SPatrick Delaunay #define OTG_GAHBCFG_GINT BIT(0) 859a138eb5SPatrick Delaunay 869a138eb5SPatrick Delaunay /* Bit definitions for OTG_GUSBCFG register */ 879a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT GENMASK(13, 10) 889a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT_SHIFT 10U 899a138eb5SPatrick Delaunay 909a138eb5SPatrick Delaunay #define USBD_HS_TRDT_VALUE 9U 919a138eb5SPatrick Delaunay 929a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRSTCTL register */ 939a138eb5SPatrick Delaunay #define OTG_GRSTCTL_RXFFLSH BIT(4) 949a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFFLSH BIT(5) 959a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFNUM_SHIFT 6U 969a138eb5SPatrick Delaunay 979a138eb5SPatrick Delaunay /* Bit definitions for OTG_GINTSTS register */ 989a138eb5SPatrick Delaunay #define OTG_GINTSTS_CMOD BIT(0) 999a138eb5SPatrick Delaunay #define OTG_GINTSTS_MMIS BIT(1) 1009a138eb5SPatrick Delaunay #define OTG_GINTSTS_OTGINT BIT(2) 1019a138eb5SPatrick Delaunay #define OTG_GINTSTS_SOF BIT(3) 1029a138eb5SPatrick Delaunay #define OTG_GINTSTS_RXFLVL BIT(4) 1039a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBSUSP BIT(11) 1049a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBRST BIT(12) 1059a138eb5SPatrick Delaunay #define OTG_GINTSTS_ENUMDNE BIT(13) 1069a138eb5SPatrick Delaunay #define OTG_GINTSTS_IEPINT BIT(18) 1079a138eb5SPatrick Delaunay #define OTG_GINTSTS_OEPINT BIT(19) 1089a138eb5SPatrick Delaunay #define OTG_GINTSTS_IISOIXFR BIT(20) 1099a138eb5SPatrick Delaunay #define OTG_GINTSTS_IPXFR_INCOMPISOOUT BIT(21) 1109a138eb5SPatrick Delaunay #define OTG_GINTSTS_LPMINT BIT(27) 1119a138eb5SPatrick Delaunay #define OTG_GINTSTS_SRQINT BIT(30) 1129a138eb5SPatrick Delaunay #define OTG_GINTSTS_WKUPINT BIT(31) 1139a138eb5SPatrick Delaunay 1149a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRXSTSP register */ 1159a138eb5SPatrick Delaunay #define OTG_GRXSTSP_EPNUM GENMASK(3, 0) 1169a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT GENMASK(14, 4) 1179a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT_SHIFT 4U 1189a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS GENMASK(20, 17) 1199a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS_SHIFT 17U 1209a138eb5SPatrick Delaunay 1219a138eb5SPatrick Delaunay #define STS_GOUT_NAK 1U 1229a138eb5SPatrick Delaunay #define STS_DATA_UPDT 2U 1239a138eb5SPatrick Delaunay #define STS_XFER_COMP 3U 1249a138eb5SPatrick Delaunay #define STS_SETUP_COMP 4U 1259a138eb5SPatrick Delaunay #define STS_SETUP_UPDT 6U 1269a138eb5SPatrick Delaunay 1279a138eb5SPatrick Delaunay /* Bit definitions for OTG_GLPMCFG register */ 1289a138eb5SPatrick Delaunay #define OTG_GLPMCFG_BESL GENMASK(5, 2) 1299a138eb5SPatrick Delaunay 1309a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCFG register */ 1319a138eb5SPatrick Delaunay #define OTG_DCFG_DAD GENMASK(10, 4) 1329a138eb5SPatrick Delaunay #define OTG_DCFG_DAD_SHIFT 4U 1339a138eb5SPatrick Delaunay 1349a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCTL register */ 1359a138eb5SPatrick Delaunay #define OTG_DCTL_RWUSIG BIT(0) 1369a138eb5SPatrick Delaunay #define OTG_DCTL_SDIS BIT(1) 1379a138eb5SPatrick Delaunay #define OTG_DCTL_CGINAK BIT(8) 1389a138eb5SPatrick Delaunay 1399a138eb5SPatrick Delaunay /* Bit definitions for OTG_DSTS register */ 1409a138eb5SPatrick Delaunay #define OTG_DSTS_SUSPSTS BIT(0) 1419a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_MASK GENMASK(2, 1) 1429a138eb5SPatrick Delaunay #define OTG_DSTS_FNSOF0 BIT(8) 1439a138eb5SPatrick Delaunay 1449a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD(val) ((val) << 1) 1459a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(0U) 1469a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(1U) 1479a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_LS_PHY_6MHZ OTG_DSTS_ENUMSPD(2U) 1489a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_48MHZ OTG_DSTS_ENUMSPD(3U) 1499a138eb5SPatrick Delaunay 1509a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPMSK register */ 1519a138eb5SPatrick Delaunay #define OTG_DIEPMSK_XFRCM BIT(0) 1529a138eb5SPatrick Delaunay #define OTG_DIEPMSK_EPDM BIT(1) 1539a138eb5SPatrick Delaunay #define OTG_DIEPMSK_TOM BIT(3) 1549a138eb5SPatrick Delaunay 1559a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPMSK register */ 1569a138eb5SPatrick Delaunay #define OTG_DOEPMSK_XFRCM BIT(0) 1579a138eb5SPatrick Delaunay #define OTG_DOEPMSK_EPDM BIT(1) 1589a138eb5SPatrick Delaunay #define OTG_DOEPMSK_STUPM BIT(3) 1599a138eb5SPatrick Delaunay 1609a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPCTLx registers */ 1619a138eb5SPatrick Delaunay #define OTG_DIEPCTL_MPSIZ GENMASK(10, 0) 1629a138eb5SPatrick Delaunay #define OTG_DIEPCTL_STALL BIT(21) 1639a138eb5SPatrick Delaunay #define OTG_DIEPCTL_CNAK BIT(26) 1649a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SD0PID_SEVNFRM BIT(28) 1659a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SODDFRM BIT(29) 1669a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPDIS BIT(30) 1679a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPENA BIT(31) 1689a138eb5SPatrick Delaunay 1699a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPINTx registers */ 1709a138eb5SPatrick Delaunay #define OTG_DIEPINT_XFRC BIT(0) 1719a138eb5SPatrick Delaunay #define OTG_DIEPINT_EPDISD BIT(1) 1729a138eb5SPatrick Delaunay #define OTG_DIEPINT_TOC BIT(3) 1739a138eb5SPatrick Delaunay #define OTG_DIEPINT_ITTXFE BIT(4) 1749a138eb5SPatrick Delaunay #define OTG_DIEPINT_INEPNE BIT(6) 1759a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE BIT(7) 1769a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE_SHIFT 7U 1779a138eb5SPatrick Delaunay 1789a138eb5SPatrick Delaunay #define OTG_DIEPINT_MASK (BIT(13) | BIT(11) | GENMASK(9, 0)) 1799a138eb5SPatrick Delaunay 1809a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPTSIZx registers */ 1819a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_XFRSIZ GENMASK(18, 0) 1829a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT GENMASK(28, 19) 1839a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_SHIFT 19U 1849a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_MASK GENMASK(30, 29) 1859a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_DATA0 BIT(29) 1869a138eb5SPatrick Delaunay 1879a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_1 BIT(19) 1889a138eb5SPatrick Delaunay 1899a138eb5SPatrick Delaunay /* Bit definitions for OTG_DTXFSTSx registers */ 1909a138eb5SPatrick Delaunay #define OTG_DTXFSTS_INEPTFSAV GENMASK(15, 0) 1919a138eb5SPatrick Delaunay 1929a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPCTLx registers */ 1939a138eb5SPatrick Delaunay #define OTG_DOEPCTL_STALL BIT(21) 1949a138eb5SPatrick Delaunay #define OTG_DOEPCTL_CNAK BIT(26) 1959a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD0PID_SEVNFRM BIT(28) /* other than endpoint 0 */ 1969a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD1PID_SODDFRM BIT(29) /* other than endpoint 0 */ 1979a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPDIS BIT(30) 1989a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPENA BIT(31) 1999a138eb5SPatrick Delaunay 2009a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPTSIZx registers */ 2019a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_XFRSIZ GENMASK(18, 0) 2029a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_PKTCNT GENMASK(28, 19) 2039a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_RXDPID_STUPCNT GENMASK(30, 29) 2049a138eb5SPatrick Delaunay 2059a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPINTx registers */ 2069a138eb5SPatrick Delaunay #define OTG_DOEPINT_XFRC BIT(0) 2079a138eb5SPatrick Delaunay #define OTG_DOEPINT_STUP BIT(3) 2089a138eb5SPatrick Delaunay #define OTG_DOEPINT_OTEPDIS BIT(4) 2099a138eb5SPatrick Delaunay 2109a138eb5SPatrick Delaunay #define OTG_DOEPINT_MASK (GENMASK(15, 12) | GENMASK(9, 8) | GENMASK(6, 0)) 2119a138eb5SPatrick Delaunay 2129a138eb5SPatrick Delaunay #define EP_NB 15U 2139a138eb5SPatrick Delaunay #define EP_ALL 0x10U 2149a138eb5SPatrick Delaunay 2159a138eb5SPatrick Delaunay /* 2169a138eb5SPatrick Delaunay * Flush TX FIFO. 2179a138eb5SPatrick Delaunay * handle: PCD handle. 2189a138eb5SPatrick Delaunay * num: FIFO number. 2199a138eb5SPatrick Delaunay * This parameter can be a value from 1 to 15 or EP_ALL. 2209a138eb5SPatrick Delaunay * EP_ALL= 0x10 means Flush all TX FIFOs 2219a138eb5SPatrick Delaunay * return: USB status. 2229a138eb5SPatrick Delaunay */ 2239a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_tx_fifo(void *handle, uint32_t num) 2249a138eb5SPatrick Delaunay { 2259a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 2269a138eb5SPatrick Delaunay uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US); 2279a138eb5SPatrick Delaunay 2289a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GRSTCTL, 2299a138eb5SPatrick Delaunay OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << OTG_GRSTCTL_TXFNUM_SHIFT)); 2309a138eb5SPatrick Delaunay 2319a138eb5SPatrick Delaunay while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) & 2329a138eb5SPatrick Delaunay OTG_GRSTCTL_TXFFLSH) == OTG_GRSTCTL_TXFFLSH) { 2339a138eb5SPatrick Delaunay if (timeout_elapsed(timeout)) { 2349a138eb5SPatrick Delaunay return USBD_TIMEOUT; 2359a138eb5SPatrick Delaunay } 2369a138eb5SPatrick Delaunay } 2379a138eb5SPatrick Delaunay 2389a138eb5SPatrick Delaunay return USBD_OK; 2399a138eb5SPatrick Delaunay } 2409a138eb5SPatrick Delaunay 2419a138eb5SPatrick Delaunay /* 2429a138eb5SPatrick Delaunay * Flush RX FIFO. 2439a138eb5SPatrick Delaunay * handle: PCD handle. 2449a138eb5SPatrick Delaunay * return: USB status. 2459a138eb5SPatrick Delaunay */ 2469a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_rx_fifo(void *handle) 2479a138eb5SPatrick Delaunay { 2489a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 2499a138eb5SPatrick Delaunay uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US); 2509a138eb5SPatrick Delaunay 2519a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GRSTCTL, OTG_GRSTCTL_RXFFLSH); 2529a138eb5SPatrick Delaunay 2539a138eb5SPatrick Delaunay while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) & 2549a138eb5SPatrick Delaunay OTG_GRSTCTL_RXFFLSH) == OTG_GRSTCTL_RXFFLSH) { 2559a138eb5SPatrick Delaunay if (timeout_elapsed(timeout)) { 2569a138eb5SPatrick Delaunay return USBD_TIMEOUT; 2579a138eb5SPatrick Delaunay } 2589a138eb5SPatrick Delaunay } 2599a138eb5SPatrick Delaunay 2609a138eb5SPatrick Delaunay return USBD_OK; 2619a138eb5SPatrick Delaunay } 2629a138eb5SPatrick Delaunay 2639a138eb5SPatrick Delaunay /* 2649a138eb5SPatrick Delaunay * Return the global USB interrupt status. 2659a138eb5SPatrick Delaunay * handle: PCD handle. 2669a138eb5SPatrick Delaunay * return: Interrupt register value. 2679a138eb5SPatrick Delaunay */ 2689a138eb5SPatrick Delaunay static uint32_t usb_dwc2_read_int(void *handle) 2699a138eb5SPatrick Delaunay { 2709a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 2719a138eb5SPatrick Delaunay 2729a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_GINTSTS) & 2739a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_GINTMSK); 2749a138eb5SPatrick Delaunay } 2759a138eb5SPatrick Delaunay 2769a138eb5SPatrick Delaunay /* 2779a138eb5SPatrick Delaunay * Return the USB device OUT endpoints interrupt. 2789a138eb5SPatrick Delaunay * handle: PCD handle. 2799a138eb5SPatrick Delaunay * return: Device OUT endpoint interrupts. 2809a138eb5SPatrick Delaunay */ 2819a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_out_ep_int(void *handle) 2829a138eb5SPatrick Delaunay { 2839a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 2849a138eb5SPatrick Delaunay 2859a138eb5SPatrick Delaunay return ((mmio_read_32(usb_base_addr + OTG_DAINT) & 2869a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DAINTMSK)) & 2879a138eb5SPatrick Delaunay OTG_DAINT_OUT_MASK) >> OTG_DAINT_OUT_SHIFT; 2889a138eb5SPatrick Delaunay } 2899a138eb5SPatrick Delaunay 2909a138eb5SPatrick Delaunay /* 2919a138eb5SPatrick Delaunay * Return the USB device IN endpoints interrupt. 2929a138eb5SPatrick Delaunay * handle: PCD handle. 2939a138eb5SPatrick Delaunay * return: Device IN endpoint interrupts. 2949a138eb5SPatrick Delaunay */ 2959a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_in_ep_int(void *handle) 2969a138eb5SPatrick Delaunay { 2979a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 2989a138eb5SPatrick Delaunay 2999a138eb5SPatrick Delaunay return ((mmio_read_32(usb_base_addr + OTG_DAINT) & 3009a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DAINTMSK)) & 3019a138eb5SPatrick Delaunay OTG_DAINT_IN_MASK) >> OTG_DAINT_IN_SHIFT; 3029a138eb5SPatrick Delaunay } 3039a138eb5SPatrick Delaunay 3049a138eb5SPatrick Delaunay /* 3059a138eb5SPatrick Delaunay * Return Device OUT EP interrupt register. 3069a138eb5SPatrick Delaunay * handle: PCD handle. 3079a138eb5SPatrick Delaunay * epnum: Endpoint number. 3089a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 15. 3099a138eb5SPatrick Delaunay * return: Device OUT EP Interrupt register. 3109a138eb5SPatrick Delaunay */ 3119a138eb5SPatrick Delaunay static uint32_t usb_dwc2_out_ep_int(void *handle, uint8_t epnum) 3129a138eb5SPatrick Delaunay { 3139a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 3149a138eb5SPatrick Delaunay 3159a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_DOEP_BASE + 3169a138eb5SPatrick Delaunay (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT) & 3179a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DOEPMSK); 3189a138eb5SPatrick Delaunay } 3199a138eb5SPatrick Delaunay 3209a138eb5SPatrick Delaunay /* 3219a138eb5SPatrick Delaunay * Return Device IN EP interrupt register. 3229a138eb5SPatrick Delaunay * handle: PCD handle. 3239a138eb5SPatrick Delaunay * epnum: Endpoint number. 3249a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 15. 3259a138eb5SPatrick Delaunay * return: Device IN EP Interrupt register. 3269a138eb5SPatrick Delaunay */ 3279a138eb5SPatrick Delaunay static uint32_t usb_dwc2_in_ep_int(void *handle, uint8_t epnum) 3289a138eb5SPatrick Delaunay { 3299a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 3309a138eb5SPatrick Delaunay uint32_t msk; 3319a138eb5SPatrick Delaunay uint32_t emp; 3329a138eb5SPatrick Delaunay 3339a138eb5SPatrick Delaunay msk = mmio_read_32(usb_base_addr + OTG_DIEPMSK); 3349a138eb5SPatrick Delaunay emp = mmio_read_32(usb_base_addr + OTG_DIEPEMPMSK); 3359a138eb5SPatrick Delaunay msk |= ((emp >> epnum) << OTG_DIEPINT_TXFE_SHIFT) & OTG_DIEPINT_TXFE; 3369a138eb5SPatrick Delaunay 3379a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_DIEP_BASE + 3389a138eb5SPatrick Delaunay (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT) & msk; 3399a138eb5SPatrick Delaunay } 3409a138eb5SPatrick Delaunay 3419a138eb5SPatrick Delaunay /* 3429a138eb5SPatrick Delaunay * Return USB core mode. 3439a138eb5SPatrick Delaunay * handle: PCD handle. 3449a138eb5SPatrick Delaunay * return: Core mode. 3459a138eb5SPatrick Delaunay * This parameter can be 0 (host) or 1 (device). 3469a138eb5SPatrick Delaunay */ 3479a138eb5SPatrick Delaunay static uint32_t usb_dwc2_get_mode(void *handle) 3489a138eb5SPatrick Delaunay { 3499a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 3509a138eb5SPatrick Delaunay 3519a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_GINTSTS) & OTG_GINTSTS_CMOD; 3529a138eb5SPatrick Delaunay } 3539a138eb5SPatrick Delaunay 3549a138eb5SPatrick Delaunay /* 3559a138eb5SPatrick Delaunay * Activate EP0 for detup transactions. 3569a138eb5SPatrick Delaunay * handle: PCD handle. 3579a138eb5SPatrick Delaunay * return: USB status. 3589a138eb5SPatrick Delaunay */ 3599a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_activate_setup(void *handle) 3609a138eb5SPatrick Delaunay { 3619a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 3629a138eb5SPatrick Delaunay uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE; 3639a138eb5SPatrick Delaunay 3649a138eb5SPatrick Delaunay /* Set the MPS of the IN EP based on the enumeration speed */ 3659a138eb5SPatrick Delaunay mmio_clrbits_32(reg_offset + OTG_DIEPCTL, OTG_DIEPCTL_MPSIZ); 3669a138eb5SPatrick Delaunay 3679a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_ENUMSPD_MASK) == 3689a138eb5SPatrick Delaunay OTG_DSTS_ENUMSPD_LS_PHY_6MHZ) { 3699a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, 3U); 3709a138eb5SPatrick Delaunay } 3719a138eb5SPatrick Delaunay 3729a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_CGINAK); 3739a138eb5SPatrick Delaunay 3749a138eb5SPatrick Delaunay return USBD_OK; 3759a138eb5SPatrick Delaunay } 3769a138eb5SPatrick Delaunay 3779a138eb5SPatrick Delaunay /* 3789a138eb5SPatrick Delaunay * Prepare the EP0 to start the first control setup. 3799a138eb5SPatrick Delaunay * handle: Selected device. 3809a138eb5SPatrick Delaunay * return: USB status. 3819a138eb5SPatrick Delaunay */ 3829a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_out_start(void *handle) 3839a138eb5SPatrick Delaunay { 3849a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 3859a138eb5SPatrick Delaunay uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE + OTG_DIEPTSIZ; 3869a138eb5SPatrick Delaunay uint32_t reg_value = 0U; 3879a138eb5SPatrick Delaunay 3889a138eb5SPatrick Delaunay /* PKTCNT = 1 and XFRSIZ = 24 bytes for endpoint 0 */ 3899a138eb5SPatrick Delaunay reg_value |= OTG_DIEPTSIZ_PKTCNT_1; 3909a138eb5SPatrick Delaunay reg_value |= (EP0_FIFO_SIZE & OTG_DIEPTSIZ_XFRSIZ); 3919a138eb5SPatrick Delaunay reg_value |= OTG_DOEPTSIZ_RXDPID_STUPCNT; 3929a138eb5SPatrick Delaunay 3939a138eb5SPatrick Delaunay mmio_write_32(reg_offset, reg_value); 3949a138eb5SPatrick Delaunay 3959a138eb5SPatrick Delaunay return USBD_OK; 3969a138eb5SPatrick Delaunay } 3979a138eb5SPatrick Delaunay 3989a138eb5SPatrick Delaunay /* 3999a138eb5SPatrick Delaunay * Write a packet into the TX FIFO associated with the EP/channel. 4009a138eb5SPatrick Delaunay * handle: Selected device. 4019a138eb5SPatrick Delaunay * src: Pointer to source buffer. 4029a138eb5SPatrick Delaunay * ch_ep_num: Endpoint or host channel number. 4039a138eb5SPatrick Delaunay * len: Number of bytes to write. 4049a138eb5SPatrick Delaunay * return: USB status. 4059a138eb5SPatrick Delaunay */ 4069a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_packet(void *handle, uint8_t *src, 4079a138eb5SPatrick Delaunay uint8_t ch_ep_num, uint16_t len) 4089a138eb5SPatrick Delaunay { 4099a138eb5SPatrick Delaunay uint32_t reg_offset; 4109a138eb5SPatrick Delaunay uint32_t count32b = (len + 3U) / 4U; 4119a138eb5SPatrick Delaunay uint32_t i; 4129a138eb5SPatrick Delaunay 4139a138eb5SPatrick Delaunay reg_offset = (uintptr_t)handle + OTG_FIFO_BASE + 4149a138eb5SPatrick Delaunay (ch_ep_num * OTG_FIFO_SIZE); 4159a138eb5SPatrick Delaunay 4169a138eb5SPatrick Delaunay for (i = 0U; i < count32b; i++) { 4179a138eb5SPatrick Delaunay uint32_t src_copy = 0U; 4189a138eb5SPatrick Delaunay uint32_t j; 4199a138eb5SPatrick Delaunay 4209a138eb5SPatrick Delaunay /* Data written to FIFO need to be 4 bytes aligned */ 4219a138eb5SPatrick Delaunay for (j = 0U; j < 4U; j++) { 4229a138eb5SPatrick Delaunay src_copy += (*(src + j)) << (8U * j); 4239a138eb5SPatrick Delaunay } 4249a138eb5SPatrick Delaunay 4259a138eb5SPatrick Delaunay mmio_write_32(reg_offset, src_copy); 4269a138eb5SPatrick Delaunay src += 4U; 4279a138eb5SPatrick Delaunay } 4289a138eb5SPatrick Delaunay 4299a138eb5SPatrick Delaunay return USBD_OK; 4309a138eb5SPatrick Delaunay } 4319a138eb5SPatrick Delaunay 4329a138eb5SPatrick Delaunay /* 4339a138eb5SPatrick Delaunay * Read a packet from the RX FIFO associated with the EP/channel. 4349a138eb5SPatrick Delaunay * handle: Selected device. 4359a138eb5SPatrick Delaunay * dst: Destination pointer. 4369a138eb5SPatrick Delaunay * len: Number of bytes to read. 4379a138eb5SPatrick Delaunay * return: Pointer to destination buffer. 4389a138eb5SPatrick Delaunay */ 4399a138eb5SPatrick Delaunay static void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len) 4409a138eb5SPatrick Delaunay { 4419a138eb5SPatrick Delaunay uint32_t reg_offset; 4429a138eb5SPatrick Delaunay uint32_t count32b = (len + 3U) / 4U; 4439a138eb5SPatrick Delaunay uint32_t i; 4449a138eb5SPatrick Delaunay 4459a138eb5SPatrick Delaunay VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest); 4469a138eb5SPatrick Delaunay 4479a138eb5SPatrick Delaunay reg_offset = (uintptr_t)handle + OTG_FIFO_BASE; 4489a138eb5SPatrick Delaunay 4499a138eb5SPatrick Delaunay for (i = 0U; i < count32b; i++) { 4509a138eb5SPatrick Delaunay *(uint32_t *)dest = mmio_read_32(reg_offset); 4519a138eb5SPatrick Delaunay dest += 4U; 4529a138eb5SPatrick Delaunay dsb(); 4539a138eb5SPatrick Delaunay } 4549a138eb5SPatrick Delaunay 4559a138eb5SPatrick Delaunay return (void *)dest; 4569a138eb5SPatrick Delaunay } 4579a138eb5SPatrick Delaunay 4589a138eb5SPatrick Delaunay /* 4599a138eb5SPatrick Delaunay * Setup and start a transfer over an EP. 4609a138eb5SPatrick Delaunay * handle: Selected device 4619a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 4629a138eb5SPatrick Delaunay * return: USB status. 4639a138eb5SPatrick Delaunay */ 4649a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_start_xfer(void *handle, struct usbd_ep *ep) 4659a138eb5SPatrick Delaunay { 4669a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 4679a138eb5SPatrick Delaunay uint32_t reg_offset; 4689a138eb5SPatrick Delaunay uint32_t reg_value; 4699a138eb5SPatrick Delaunay uint32_t clear_value; 4709a138eb5SPatrick Delaunay 4719a138eb5SPatrick Delaunay if (ep->is_in) { 4729a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (ep->num * OTG_DIEP_SIZE); 4739a138eb5SPatrick Delaunay clear_value = OTG_DIEPTSIZ_PKTCNT | OTG_DIEPTSIZ_XFRSIZ; 4749a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 4759a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1; 4769a138eb5SPatrick Delaunay } else { 4779a138eb5SPatrick Delaunay /* 4789a138eb5SPatrick Delaunay * Program the transfer size and packet count 4799a138eb5SPatrick Delaunay * as follows: 4809a138eb5SPatrick Delaunay * xfersize = N * maxpacket + short_packet 4819a138eb5SPatrick Delaunay * pktcnt = N + (short_packet exist ? 1 : 0) 4829a138eb5SPatrick Delaunay */ 4839a138eb5SPatrick Delaunay reg_value = (OTG_DIEPTSIZ_PKTCNT & 4849a138eb5SPatrick Delaunay (((ep->xfer_len + ep->maxpacket - 1U) / 4859a138eb5SPatrick Delaunay ep->maxpacket) << OTG_DIEPTSIZ_PKTCNT_SHIFT)) 4869a138eb5SPatrick Delaunay | ep->xfer_len; 4879a138eb5SPatrick Delaunay 4889a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 4899a138eb5SPatrick Delaunay clear_value |= OTG_DIEPTSIZ_MCNT_MASK; 4909a138eb5SPatrick Delaunay reg_value |= OTG_DIEPTSIZ_MCNT_DATA0; 4919a138eb5SPatrick Delaunay } 4929a138eb5SPatrick Delaunay } 4939a138eb5SPatrick Delaunay 4949a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, clear_value, reg_value); 4959a138eb5SPatrick Delaunay 4969a138eb5SPatrick Delaunay if ((ep->type != EP_TYPE_ISOC) && (ep->xfer_len > 0U)) { 4979a138eb5SPatrick Delaunay /* Enable the TX FIFO empty interrupt for this EP */ 4989a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(ep->num)); 4999a138eb5SPatrick Delaunay } 5009a138eb5SPatrick Delaunay 5019a138eb5SPatrick Delaunay /* EP enable, IN data in FIFO */ 5029a138eb5SPatrick Delaunay reg_value = OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA; 5039a138eb5SPatrick Delaunay 5049a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 5059a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) { 5069a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_SODDFRM; 5079a138eb5SPatrick Delaunay } else { 5089a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_SD0PID_SEVNFRM; 5099a138eb5SPatrick Delaunay } 5109a138eb5SPatrick Delaunay } 5119a138eb5SPatrick Delaunay 5129a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, reg_value); 5139a138eb5SPatrick Delaunay 5149a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 5159a138eb5SPatrick Delaunay usb_dwc2_write_packet(handle, ep->xfer_buff, ep->num, ep->xfer_len); 5169a138eb5SPatrick Delaunay } 5179a138eb5SPatrick Delaunay } else { 5189a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + (ep->num * OTG_DOEP_SIZE); 5199a138eb5SPatrick Delaunay /* 5209a138eb5SPatrick Delaunay * Program the transfer size and packet count as follows: 5219a138eb5SPatrick Delaunay * pktcnt = N 5229a138eb5SPatrick Delaunay * xfersize = N * maxpacket 5239a138eb5SPatrick Delaunay */ 5249a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 5259a138eb5SPatrick Delaunay reg_value = ep->maxpacket | OTG_DIEPTSIZ_PKTCNT_1; 5269a138eb5SPatrick Delaunay } else { 5279a138eb5SPatrick Delaunay uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket; 5289a138eb5SPatrick Delaunay 5299a138eb5SPatrick Delaunay reg_value = (pktcnt << OTG_DIEPTSIZ_PKTCNT_SHIFT) | 5309a138eb5SPatrick Delaunay (ep->maxpacket * pktcnt); 5319a138eb5SPatrick Delaunay } 5329a138eb5SPatrick Delaunay 5339a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DOEPTSIZ, 5349a138eb5SPatrick Delaunay OTG_DOEPTSIZ_XFRSIZ & OTG_DOEPTSIZ_PKTCNT, 5359a138eb5SPatrick Delaunay reg_value); 5369a138eb5SPatrick Delaunay 5379a138eb5SPatrick Delaunay /* EP enable */ 5389a138eb5SPatrick Delaunay reg_value = OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA; 5399a138eb5SPatrick Delaunay 5409a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 5419a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) { 5429a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_SD1PID_SODDFRM; 5439a138eb5SPatrick Delaunay } else { 5449a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_SD0PID_SEVNFRM; 5459a138eb5SPatrick Delaunay } 5469a138eb5SPatrick Delaunay } 5479a138eb5SPatrick Delaunay 5489a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DOEPCTL, reg_value); 5499a138eb5SPatrick Delaunay } 5509a138eb5SPatrick Delaunay 5519a138eb5SPatrick Delaunay return USBD_OK; 5529a138eb5SPatrick Delaunay } 5539a138eb5SPatrick Delaunay 5549a138eb5SPatrick Delaunay /* 5559a138eb5SPatrick Delaunay * Setup and start a transfer over the EP0. 5569a138eb5SPatrick Delaunay * handle: Selected device. 5579a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 5589a138eb5SPatrick Delaunay * return: USB status. 5599a138eb5SPatrick Delaunay */ 5609a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_start_xfer(void *handle, struct usbd_ep *ep) 5619a138eb5SPatrick Delaunay { 5629a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 5639a138eb5SPatrick Delaunay uint32_t reg_offset; 5649a138eb5SPatrick Delaunay uint32_t reg_value; 5659a138eb5SPatrick Delaunay 5669a138eb5SPatrick Delaunay if (ep->is_in) { 5679a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + 5689a138eb5SPatrick Delaunay (ep->num * OTG_DIEP_SIZE); 5699a138eb5SPatrick Delaunay 5709a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 5719a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1; 5729a138eb5SPatrick Delaunay } else { 5739a138eb5SPatrick Delaunay /* 5749a138eb5SPatrick Delaunay * Program the transfer size and packet count 5759a138eb5SPatrick Delaunay * as follows: 5769a138eb5SPatrick Delaunay * xfersize = N * maxpacket + short_packet 5779a138eb5SPatrick Delaunay * pktcnt = N + (short_packet exist ? 1 : 0) 5789a138eb5SPatrick Delaunay */ 5799a138eb5SPatrick Delaunay 5809a138eb5SPatrick Delaunay if (ep->xfer_len > ep->maxpacket) { 5819a138eb5SPatrick Delaunay ep->xfer_len = ep->maxpacket; 5829a138eb5SPatrick Delaunay } 5839a138eb5SPatrick Delaunay 5849a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->xfer_len; 5859a138eb5SPatrick Delaunay } 5869a138eb5SPatrick Delaunay 5879a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, 5889a138eb5SPatrick Delaunay OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT, 5899a138eb5SPatrick Delaunay reg_value); 5909a138eb5SPatrick Delaunay 5919a138eb5SPatrick Delaunay /* Enable the TX FIFO empty interrupt for this EP */ 5929a138eb5SPatrick Delaunay if (ep->xfer_len > 0U) { 5939a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, 5949a138eb5SPatrick Delaunay BIT(ep->num)); 5959a138eb5SPatrick Delaunay } 5969a138eb5SPatrick Delaunay 5979a138eb5SPatrick Delaunay /* EP enable, IN data in FIFO */ 5989a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, 5999a138eb5SPatrick Delaunay OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA); 6009a138eb5SPatrick Delaunay } else { 6019a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + 6029a138eb5SPatrick Delaunay (ep->num * OTG_DOEP_SIZE); 6039a138eb5SPatrick Delaunay 6049a138eb5SPatrick Delaunay /* 6059a138eb5SPatrick Delaunay * Program the transfer size and packet count as follows: 6069a138eb5SPatrick Delaunay * pktcnt = N 6079a138eb5SPatrick Delaunay * xfersize = N * maxpacket 6089a138eb5SPatrick Delaunay */ 6099a138eb5SPatrick Delaunay if (ep->xfer_len > 0U) { 6109a138eb5SPatrick Delaunay ep->xfer_len = ep->maxpacket; 6119a138eb5SPatrick Delaunay } 6129a138eb5SPatrick Delaunay 6139a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->maxpacket; 6149a138eb5SPatrick Delaunay 6159a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, 6169a138eb5SPatrick Delaunay OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT, 6179a138eb5SPatrick Delaunay reg_value); 6189a138eb5SPatrick Delaunay 6199a138eb5SPatrick Delaunay /* EP enable */ 6209a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DOEPCTL, 6219a138eb5SPatrick Delaunay OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA); 6229a138eb5SPatrick Delaunay } 6239a138eb5SPatrick Delaunay 6249a138eb5SPatrick Delaunay return USBD_OK; 6259a138eb5SPatrick Delaunay } 6269a138eb5SPatrick Delaunay 6279a138eb5SPatrick Delaunay /* 6289a138eb5SPatrick Delaunay * Set a stall condition over an EP. 6299a138eb5SPatrick Delaunay * handle: Selected device. 6309a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 6319a138eb5SPatrick Delaunay * return: USB status. 6329a138eb5SPatrick Delaunay */ 6339a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_set_stall(void *handle, struct usbd_ep *ep) 6349a138eb5SPatrick Delaunay { 6359a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 6369a138eb5SPatrick Delaunay uint32_t reg_offset; 6379a138eb5SPatrick Delaunay uint32_t reg_value; 6389a138eb5SPatrick Delaunay 6399a138eb5SPatrick Delaunay if (ep->is_in) { 6409a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + 6419a138eb5SPatrick Delaunay (ep->num * OTG_DIEP_SIZE); 6429a138eb5SPatrick Delaunay reg_value = mmio_read_32(reg_offset + OTG_DIEPCTL); 6439a138eb5SPatrick Delaunay 6449a138eb5SPatrick Delaunay if ((reg_value & OTG_DIEPCTL_EPENA) == 0U) { 6459a138eb5SPatrick Delaunay reg_value &= ~OTG_DIEPCTL_EPDIS; 6469a138eb5SPatrick Delaunay } 6479a138eb5SPatrick Delaunay 6489a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_STALL; 6499a138eb5SPatrick Delaunay 6509a138eb5SPatrick Delaunay mmio_write_32(reg_offset + OTG_DIEPCTL, reg_value); 6519a138eb5SPatrick Delaunay } else { 6529a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + 6539a138eb5SPatrick Delaunay (ep->num * OTG_DOEP_SIZE); 6549a138eb5SPatrick Delaunay reg_value = mmio_read_32(reg_offset + OTG_DOEPCTL); 6559a138eb5SPatrick Delaunay 6569a138eb5SPatrick Delaunay if ((reg_value & OTG_DOEPCTL_EPENA) == 0U) { 6579a138eb5SPatrick Delaunay reg_value &= ~OTG_DOEPCTL_EPDIS; 6589a138eb5SPatrick Delaunay } 6599a138eb5SPatrick Delaunay 6609a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_STALL; 6619a138eb5SPatrick Delaunay 6629a138eb5SPatrick Delaunay mmio_write_32(reg_offset + OTG_DOEPCTL, reg_value); 6639a138eb5SPatrick Delaunay } 6649a138eb5SPatrick Delaunay 6659a138eb5SPatrick Delaunay return USBD_OK; 6669a138eb5SPatrick Delaunay } 6679a138eb5SPatrick Delaunay 6689a138eb5SPatrick Delaunay /* 6699a138eb5SPatrick Delaunay * Stop the USB device mode. 6709a138eb5SPatrick Delaunay * handle: Selected device. 6719a138eb5SPatrick Delaunay * return: USB status. 6729a138eb5SPatrick Delaunay */ 6739a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_stop_device(void *handle) 6749a138eb5SPatrick Delaunay { 6759a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 6769a138eb5SPatrick Delaunay uint32_t i; 6779a138eb5SPatrick Delaunay 6789a138eb5SPatrick Delaunay /* Disable Int */ 6799a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT); 6809a138eb5SPatrick Delaunay 6819a138eb5SPatrick Delaunay /* Clear pending interrupts */ 6829a138eb5SPatrick Delaunay for (i = 0U; i < EP_NB; i++) { 6839a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DIEP_BASE + (i * OTG_DIEP_SIZE) + OTG_DIEPINT, 6849a138eb5SPatrick Delaunay OTG_DIEPINT_MASK); 6859a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DOEP_BASE + (i * OTG_DOEP_SIZE) + OTG_DOEPINT, 6869a138eb5SPatrick Delaunay OTG_DOEPINT_MASK); 6879a138eb5SPatrick Delaunay } 6889a138eb5SPatrick Delaunay 6899a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK); 6909a138eb5SPatrick Delaunay 6919a138eb5SPatrick Delaunay /* Clear interrupt masks */ 6929a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DIEPMSK, 0U); 6939a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DOEPMSK, 0U); 6949a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINTMSK, 0U); 6959a138eb5SPatrick Delaunay 6969a138eb5SPatrick Delaunay /* Flush the FIFO */ 6979a138eb5SPatrick Delaunay usb_dwc2_flush_rx_fifo(handle); 6989a138eb5SPatrick Delaunay usb_dwc2_flush_tx_fifo(handle, EP_ALL); 6999a138eb5SPatrick Delaunay 7009a138eb5SPatrick Delaunay /* Disconnect the USB device by disabling the pull-up/pull-down */ 7019a138eb5SPatrick Delaunay mmio_setbits_32((uintptr_t)handle + OTG_DCTL, OTG_DCTL_SDIS); 7029a138eb5SPatrick Delaunay 7039a138eb5SPatrick Delaunay return USBD_OK; 7049a138eb5SPatrick Delaunay } 7059a138eb5SPatrick Delaunay 7069a138eb5SPatrick Delaunay /* 7079a138eb5SPatrick Delaunay * Stop the USB device mode. 7089a138eb5SPatrick Delaunay * handle: Selected device. 7099a138eb5SPatrick Delaunay * address: New device address to be assigned. 7109a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 255. 7119a138eb5SPatrick Delaunay * return: USB status. 7129a138eb5SPatrick Delaunay */ 7139a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_set_address(void *handle, uint8_t address) 7149a138eb5SPatrick Delaunay { 7159a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 7169a138eb5SPatrick Delaunay 7179a138eb5SPatrick Delaunay mmio_clrsetbits_32(usb_base_addr + OTG_DCFG, 7189a138eb5SPatrick Delaunay OTG_DCFG_DAD, 7199a138eb5SPatrick Delaunay address << OTG_DCFG_DAD_SHIFT); 7209a138eb5SPatrick Delaunay 7219a138eb5SPatrick Delaunay return USBD_OK; 7229a138eb5SPatrick Delaunay } 7239a138eb5SPatrick Delaunay 7249a138eb5SPatrick Delaunay /* 7259a138eb5SPatrick Delaunay * Check FIFO for the next packet to be loaded. 7269a138eb5SPatrick Delaunay * handle: Selected device. 7279a138eb5SPatrick Delaunay * epnum : Endpoint number. 7289a138eb5SPatrick Delaunay * xfer_len: Block length. 7299a138eb5SPatrick Delaunay * xfer_count: Number of blocks. 7309a138eb5SPatrick Delaunay * maxpacket: Max packet length. 7319a138eb5SPatrick Delaunay * xfer_buff: Buffer pointer. 7329a138eb5SPatrick Delaunay * return: USB status. 7339a138eb5SPatrick Delaunay */ 7349a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_empty_tx_fifo(void *handle, 7359a138eb5SPatrick Delaunay uint32_t epnum, 7369a138eb5SPatrick Delaunay uint32_t xfer_len, 7379a138eb5SPatrick Delaunay uint32_t *xfer_count, 7389a138eb5SPatrick Delaunay uint32_t maxpacket, 7399a138eb5SPatrick Delaunay uint8_t **xfer_buff) 7409a138eb5SPatrick Delaunay { 7419a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 7429a138eb5SPatrick Delaunay uint32_t reg_offset; 7439a138eb5SPatrick Delaunay int32_t len; 7449a138eb5SPatrick Delaunay uint32_t len32b; 7459a138eb5SPatrick Delaunay enum usb_status ret; 7469a138eb5SPatrick Delaunay 7479a138eb5SPatrick Delaunay len = xfer_len - *xfer_count; 7489a138eb5SPatrick Delaunay 7499a138eb5SPatrick Delaunay if ((len > 0) && ((uint32_t)len > maxpacket)) { 7509a138eb5SPatrick Delaunay len = maxpacket; 7519a138eb5SPatrick Delaunay } 7529a138eb5SPatrick Delaunay 7539a138eb5SPatrick Delaunay len32b = (len + 3U) / 4U; 7549a138eb5SPatrick Delaunay 7559a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE); 7569a138eb5SPatrick Delaunay 7579a138eb5SPatrick Delaunay while (((mmio_read_32(reg_offset + OTG_DTXFSTS) & 7589a138eb5SPatrick Delaunay OTG_DTXFSTS_INEPTFSAV) > len32b) && 7599a138eb5SPatrick Delaunay (*xfer_count < xfer_len) && (xfer_len != 0U)) { 7609a138eb5SPatrick Delaunay /* Write the FIFO */ 7619a138eb5SPatrick Delaunay len = xfer_len - *xfer_count; 7629a138eb5SPatrick Delaunay 7639a138eb5SPatrick Delaunay if ((len > 0) && ((uint32_t)len > maxpacket)) { 7649a138eb5SPatrick Delaunay len = maxpacket; 7659a138eb5SPatrick Delaunay } 7669a138eb5SPatrick Delaunay 7679a138eb5SPatrick Delaunay len32b = (len + 3U) / 4U; 7689a138eb5SPatrick Delaunay 7699a138eb5SPatrick Delaunay ret = usb_dwc2_write_packet(handle, *xfer_buff, epnum, len); 7709a138eb5SPatrick Delaunay if (ret != USBD_OK) { 7719a138eb5SPatrick Delaunay return ret; 7729a138eb5SPatrick Delaunay } 7739a138eb5SPatrick Delaunay 7749a138eb5SPatrick Delaunay *xfer_buff += len; 7759a138eb5SPatrick Delaunay *xfer_count += len; 7769a138eb5SPatrick Delaunay } 7779a138eb5SPatrick Delaunay 7789a138eb5SPatrick Delaunay if (len <= 0) { 7799a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum)); 7809a138eb5SPatrick Delaunay } 7819a138eb5SPatrick Delaunay 7829a138eb5SPatrick Delaunay return USBD_OK; 7839a138eb5SPatrick Delaunay } 7849a138eb5SPatrick Delaunay 7859a138eb5SPatrick Delaunay /* 7869a138eb5SPatrick Delaunay * Handle PCD interrupt request. 7879a138eb5SPatrick Delaunay * handle: PCD handle. 7889a138eb5SPatrick Delaunay * param: Pointer to information updated by the IT handling. 7899a138eb5SPatrick Delaunay * return: Action to do after IT handling. 7909a138eb5SPatrick Delaunay */ 7919a138eb5SPatrick Delaunay static enum usb_action usb_dwc2_it_handler(void *handle, uint32_t *param) 7929a138eb5SPatrick Delaunay { 7939a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 7949a138eb5SPatrick Delaunay uint32_t ep_intr; 7959a138eb5SPatrick Delaunay uint32_t epint; 7969a138eb5SPatrick Delaunay uint32_t epnum; 7979a138eb5SPatrick Delaunay uint32_t temp; 798*02af589cSBoyan Karatotev enum usb_status __unused ret; 7999a138eb5SPatrick Delaunay 8009a138eb5SPatrick Delaunay if (usb_dwc2_get_mode(handle) != USB_OTG_MODE_DEVICE) { 8019a138eb5SPatrick Delaunay return USB_NOTHING; 8029a138eb5SPatrick Delaunay } 8039a138eb5SPatrick Delaunay 8049a138eb5SPatrick Delaunay /* Avoid spurious interrupt */ 8059a138eb5SPatrick Delaunay if (usb_dwc2_read_int(handle) == 0U) { 8069a138eb5SPatrick Delaunay return USB_NOTHING; 8079a138eb5SPatrick Delaunay } 8089a138eb5SPatrick Delaunay 8099a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_MMIS) != 0U) { 8109a138eb5SPatrick Delaunay /* Incorrect mode, acknowledge the interrupt */ 8119a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_MMIS); 8129a138eb5SPatrick Delaunay } 8139a138eb5SPatrick Delaunay 8149a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OEPINT) != 0U) { 8159a138eb5SPatrick Delaunay uint32_t reg_offset; 8169a138eb5SPatrick Delaunay 8179a138eb5SPatrick Delaunay /* Read in the device interrupt bits */ 8189a138eb5SPatrick Delaunay ep_intr = usb_dwc2_all_out_ep_int(handle); 8199a138eb5SPatrick Delaunay epnum = 0U; 8209a138eb5SPatrick Delaunay while ((ep_intr & BIT(0)) != BIT(0)) { 8219a138eb5SPatrick Delaunay epnum++; 8229a138eb5SPatrick Delaunay ep_intr >>= 1; 8239a138eb5SPatrick Delaunay } 8249a138eb5SPatrick Delaunay 8259a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT; 8269a138eb5SPatrick Delaunay 8279a138eb5SPatrick Delaunay epint = usb_dwc2_out_ep_int(handle, epnum); 8289a138eb5SPatrick Delaunay 8299a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_XFRC) == OTG_DOEPINT_XFRC) { 8309a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_XFRC); 8319a138eb5SPatrick Delaunay *param = epnum; 8329a138eb5SPatrick Delaunay 8339a138eb5SPatrick Delaunay return USB_DATA_OUT; 8349a138eb5SPatrick Delaunay } 8359a138eb5SPatrick Delaunay 8369a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_STUP) == OTG_DOEPINT_STUP) { 8379a138eb5SPatrick Delaunay /* Inform that a setup packet is available */ 8389a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_STUP); 8399a138eb5SPatrick Delaunay 8409a138eb5SPatrick Delaunay return USB_SETUP; 8419a138eb5SPatrick Delaunay } 8429a138eb5SPatrick Delaunay 8439a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_OTEPDIS) == OTG_DOEPINT_OTEPDIS) { 8449a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_OTEPDIS); 8459a138eb5SPatrick Delaunay } 8469a138eb5SPatrick Delaunay } 8479a138eb5SPatrick Delaunay 8489a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IEPINT) != 0U) { 8499a138eb5SPatrick Delaunay uint32_t reg_offset; 8509a138eb5SPatrick Delaunay 8519a138eb5SPatrick Delaunay /* Read in the device interrupt bits */ 8529a138eb5SPatrick Delaunay ep_intr = usb_dwc2_all_in_ep_int(handle); 8539a138eb5SPatrick Delaunay epnum = 0U; 8549a138eb5SPatrick Delaunay while ((ep_intr & BIT(0)) != BIT(0)) { 8559a138eb5SPatrick Delaunay epnum++; 8569a138eb5SPatrick Delaunay ep_intr >>= 1; 8579a138eb5SPatrick Delaunay } 8589a138eb5SPatrick Delaunay 8599a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT; 8609a138eb5SPatrick Delaunay 8619a138eb5SPatrick Delaunay epint = usb_dwc2_in_ep_int(handle, epnum); 8629a138eb5SPatrick Delaunay 8639a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_XFRC) == OTG_DIEPINT_XFRC) { 8649a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum)); 8659a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_XFRC); 8669a138eb5SPatrick Delaunay *param = epnum; 8679a138eb5SPatrick Delaunay 8689a138eb5SPatrick Delaunay return USB_DATA_IN; 8699a138eb5SPatrick Delaunay } 8709a138eb5SPatrick Delaunay 8719a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_TOC) == OTG_DIEPINT_TOC) { 8729a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_TOC); 8739a138eb5SPatrick Delaunay } 8749a138eb5SPatrick Delaunay 8759a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_ITTXFE) == OTG_DIEPINT_ITTXFE) { 8769a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_ITTXFE); 8779a138eb5SPatrick Delaunay } 8789a138eb5SPatrick Delaunay 8799a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_INEPNE) == OTG_DIEPINT_INEPNE) { 8809a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_INEPNE); 8819a138eb5SPatrick Delaunay } 8829a138eb5SPatrick Delaunay 8839a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_EPDISD) == OTG_DIEPINT_EPDISD) { 8849a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_EPDISD); 8859a138eb5SPatrick Delaunay } 8869a138eb5SPatrick Delaunay 8879a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_TXFE) == OTG_DIEPINT_TXFE) { 8889a138eb5SPatrick Delaunay *param = epnum; 8899a138eb5SPatrick Delaunay 8909a138eb5SPatrick Delaunay return USB_WRITE_EMPTY; 8919a138eb5SPatrick Delaunay } 8929a138eb5SPatrick Delaunay } 8939a138eb5SPatrick Delaunay 8949a138eb5SPatrick Delaunay /* Handle resume interrupt */ 8959a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_WKUPINT) != 0U) { 8969a138eb5SPatrick Delaunay INFO("handle USB : Resume\n"); 8979a138eb5SPatrick Delaunay 8989a138eb5SPatrick Delaunay /* Clear the remote wake-up signaling */ 8999a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG); 9009a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_WKUPINT); 9019a138eb5SPatrick Delaunay 9029a138eb5SPatrick Delaunay return USB_RESUME; 9039a138eb5SPatrick Delaunay } 9049a138eb5SPatrick Delaunay 9059a138eb5SPatrick Delaunay /* Handle suspend interrupt */ 9069a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBSUSP) != 0U) { 9079a138eb5SPatrick Delaunay INFO("handle USB : Suspend int\n"); 9089a138eb5SPatrick Delaunay 9099a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBSUSP); 9109a138eb5SPatrick Delaunay 9119a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & 9129a138eb5SPatrick Delaunay OTG_DSTS_SUSPSTS) == OTG_DSTS_SUSPSTS) { 9139a138eb5SPatrick Delaunay return USB_SUSPEND; 9149a138eb5SPatrick Delaunay } 9159a138eb5SPatrick Delaunay } 9169a138eb5SPatrick Delaunay 9179a138eb5SPatrick Delaunay /* Handle LPM interrupt */ 9189a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_LPMINT) != 0U) { 9199a138eb5SPatrick Delaunay INFO("handle USB : LPM int enter in suspend\n"); 9209a138eb5SPatrick Delaunay 9219a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_LPMINT); 9229a138eb5SPatrick Delaunay *param = (mmio_read_32(usb_base_addr + OTG_GLPMCFG) & 9239a138eb5SPatrick Delaunay OTG_GLPMCFG_BESL) >> 2; 9249a138eb5SPatrick Delaunay 9259a138eb5SPatrick Delaunay return USB_LPM; 9269a138eb5SPatrick Delaunay } 9279a138eb5SPatrick Delaunay 9289a138eb5SPatrick Delaunay /* Handle reset interrupt */ 9299a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBRST) != 0U) { 9309a138eb5SPatrick Delaunay INFO("handle USB : Reset\n"); 9319a138eb5SPatrick Delaunay 9329a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG); 9339a138eb5SPatrick Delaunay 9349a138eb5SPatrick Delaunay usb_dwc2_flush_tx_fifo(handle, 0U); 9359a138eb5SPatrick Delaunay 9369a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK); 9379a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DAINTMSK, OTG_DAINT_EP0_IN | OTG_DAINT_EP0_OUT); 9389a138eb5SPatrick Delaunay 9399a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DOEPMSK, OTG_DOEPMSK_STUPM | 9409a138eb5SPatrick Delaunay OTG_DOEPMSK_XFRCM | 9419a138eb5SPatrick Delaunay OTG_DOEPMSK_EPDM); 9429a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPMSK, OTG_DIEPMSK_TOM | 9439a138eb5SPatrick Delaunay OTG_DIEPMSK_XFRCM | 9449a138eb5SPatrick Delaunay OTG_DIEPMSK_EPDM); 9459a138eb5SPatrick Delaunay 9469a138eb5SPatrick Delaunay /* Set default address to 0 */ 9479a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCFG, OTG_DCFG_DAD); 9489a138eb5SPatrick Delaunay 9499a138eb5SPatrick Delaunay /* Setup EP0 to receive SETUP packets */ 9509a138eb5SPatrick Delaunay ret = usb_dwc2_ep0_out_start(handle); 951*02af589cSBoyan Karatotev assert(ret == USBD_OK); 9529a138eb5SPatrick Delaunay 9539a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBRST); 9549a138eb5SPatrick Delaunay 9559a138eb5SPatrick Delaunay return USB_RESET; 9569a138eb5SPatrick Delaunay } 9579a138eb5SPatrick Delaunay 9589a138eb5SPatrick Delaunay /* Handle enumeration done interrupt */ 9599a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_ENUMDNE) != 0U) { 9609a138eb5SPatrick Delaunay ret = usb_dwc2_activate_setup(handle); 961*02af589cSBoyan Karatotev assert(ret == USBD_OK); 9629a138eb5SPatrick Delaunay 9639a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GUSBCFG, OTG_GUSBCFG_TRDT); 9649a138eb5SPatrick Delaunay 9659a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GUSBCFG, 9669a138eb5SPatrick Delaunay (USBD_HS_TRDT_VALUE << OTG_GUSBCFG_TRDT_SHIFT) & OTG_GUSBCFG_TRDT); 9679a138eb5SPatrick Delaunay 9689a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_ENUMDNE); 9699a138eb5SPatrick Delaunay 9709a138eb5SPatrick Delaunay return USB_ENUM_DONE; 9719a138eb5SPatrick Delaunay } 9729a138eb5SPatrick Delaunay 9739a138eb5SPatrick Delaunay /* Handle RXQLevel interrupt */ 9749a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_RXFLVL) != 0U) { 9759a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GINTMSK, 9769a138eb5SPatrick Delaunay OTG_GINTSTS_RXFLVL); 9779a138eb5SPatrick Delaunay 9789a138eb5SPatrick Delaunay temp = mmio_read_32(usb_base_addr + OTG_GRXSTSP); 9799a138eb5SPatrick Delaunay 9809a138eb5SPatrick Delaunay *param = temp & OTG_GRXSTSP_EPNUM; 9819a138eb5SPatrick Delaunay *param |= (temp & OTG_GRXSTSP_BCNT) << (USBD_OUT_COUNT_SHIFT - 9829a138eb5SPatrick Delaunay OTG_GRXSTSP_BCNT_SHIFT); 9839a138eb5SPatrick Delaunay 9849a138eb5SPatrick Delaunay if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == STS_DATA_UPDT) { 9859a138eb5SPatrick Delaunay if ((temp & OTG_GRXSTSP_BCNT) != 0U) { 9869a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 9879a138eb5SPatrick Delaunay 9889a138eb5SPatrick Delaunay return USB_READ_DATA_PACKET; 9899a138eb5SPatrick Delaunay } 9909a138eb5SPatrick Delaunay } else if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == 9919a138eb5SPatrick Delaunay STS_SETUP_UPDT) { 9929a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 9939a138eb5SPatrick Delaunay 9949a138eb5SPatrick Delaunay return USB_READ_SETUP_PACKET; 9959a138eb5SPatrick Delaunay } 9969a138eb5SPatrick Delaunay 9979a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 9989a138eb5SPatrick Delaunay } 9999a138eb5SPatrick Delaunay 10009a138eb5SPatrick Delaunay /* Handle SOF interrupt */ 10019a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SOF) != 0U) { 10029a138eb5SPatrick Delaunay INFO("handle USB : SOF\n"); 10039a138eb5SPatrick Delaunay 10049a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SOF); 10059a138eb5SPatrick Delaunay 10069a138eb5SPatrick Delaunay return USB_SOF; 10079a138eb5SPatrick Delaunay } 10089a138eb5SPatrick Delaunay 10099a138eb5SPatrick Delaunay /* Handle incomplete ISO IN interrupt */ 10109a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IISOIXFR) != 0U) { 10119a138eb5SPatrick Delaunay INFO("handle USB : ISO IN\n"); 10129a138eb5SPatrick Delaunay 10139a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, 10149a138eb5SPatrick Delaunay OTG_GINTSTS_IISOIXFR); 10159a138eb5SPatrick Delaunay } 10169a138eb5SPatrick Delaunay 10179a138eb5SPatrick Delaunay /* Handle incomplete ISO OUT interrupt */ 10189a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IPXFR_INCOMPISOOUT) != 10199a138eb5SPatrick Delaunay 0U) { 10209a138eb5SPatrick Delaunay INFO("handle USB : ISO OUT\n"); 10219a138eb5SPatrick Delaunay 10229a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, 10239a138eb5SPatrick Delaunay OTG_GINTSTS_IPXFR_INCOMPISOOUT); 10249a138eb5SPatrick Delaunay } 10259a138eb5SPatrick Delaunay 10269a138eb5SPatrick Delaunay /* Handle connection event interrupt */ 10279a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SRQINT) != 0U) { 10289a138eb5SPatrick Delaunay INFO("handle USB : Connect\n"); 10299a138eb5SPatrick Delaunay 10309a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SRQINT); 10319a138eb5SPatrick Delaunay } 10329a138eb5SPatrick Delaunay 10339a138eb5SPatrick Delaunay /* Handle disconnection event interrupt */ 10349a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OTGINT) != 0U) { 10359a138eb5SPatrick Delaunay INFO("handle USB : Disconnect\n"); 10369a138eb5SPatrick Delaunay 10379a138eb5SPatrick Delaunay temp = mmio_read_32(usb_base_addr + OTG_GOTGINT); 10389a138eb5SPatrick Delaunay 10399a138eb5SPatrick Delaunay if ((temp & OTG_GOTGINT_SEDET) == OTG_GOTGINT_SEDET) { 10409a138eb5SPatrick Delaunay return USB_DISCONNECT; 10419a138eb5SPatrick Delaunay } 10429a138eb5SPatrick Delaunay } 10439a138eb5SPatrick Delaunay 10449a138eb5SPatrick Delaunay return USB_NOTHING; 10459a138eb5SPatrick Delaunay } 10469a138eb5SPatrick Delaunay 10479a138eb5SPatrick Delaunay /* 10489a138eb5SPatrick Delaunay * Start the usb device mode 10499a138eb5SPatrick Delaunay * usb_core_handle: USB core driver handle. 10509a138eb5SPatrick Delaunay * return USB status. 10519a138eb5SPatrick Delaunay */ 10529a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_start_device(void *handle) 10539a138eb5SPatrick Delaunay { 10549a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 10559a138eb5SPatrick Delaunay 10569a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_SDIS); 10579a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT); 10589a138eb5SPatrick Delaunay 10599a138eb5SPatrick Delaunay return USBD_OK; 10609a138eb5SPatrick Delaunay } 10619a138eb5SPatrick Delaunay 10629a138eb5SPatrick Delaunay static const struct usb_driver usb_dwc2driver = { 10639a138eb5SPatrick Delaunay .ep0_out_start = usb_dwc2_ep0_out_start, 10649a138eb5SPatrick Delaunay .ep_start_xfer = usb_dwc2_ep_start_xfer, 10659a138eb5SPatrick Delaunay .ep0_start_xfer = usb_dwc2_ep0_start_xfer, 10669a138eb5SPatrick Delaunay .write_packet = usb_dwc2_write_packet, 10679a138eb5SPatrick Delaunay .read_packet = usb_dwc2_read_packet, 10689a138eb5SPatrick Delaunay .ep_set_stall = usb_dwc2_ep_set_stall, 10699a138eb5SPatrick Delaunay .start_device = usb_dwc2_start_device, 10709a138eb5SPatrick Delaunay .stop_device = usb_dwc2_stop_device, 10719a138eb5SPatrick Delaunay .set_address = usb_dwc2_set_address, 10729a138eb5SPatrick Delaunay .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo, 10739a138eb5SPatrick Delaunay .it_handler = usb_dwc2_it_handler 10749a138eb5SPatrick Delaunay }; 10759a138eb5SPatrick Delaunay 10769a138eb5SPatrick Delaunay /* 10779a138eb5SPatrick Delaunay * Initialize USB DWC2 driver. 10789a138eb5SPatrick Delaunay * usb_core_handle: USB core driver handle. 10799a138eb5SPatrick Delaunay * pcd_handle: PCD handle. 10809a138eb5SPatrick Delaunay * base_register: USB global register base address. 10819a138eb5SPatrick Delaunay */ 10829a138eb5SPatrick Delaunay void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle, 10839a138eb5SPatrick Delaunay struct pcd_handle *pcd_handle, 10849a138eb5SPatrick Delaunay void *base_register) 10859a138eb5SPatrick Delaunay { 10869a138eb5SPatrick Delaunay register_usb_driver(usb_core_handle, pcd_handle, &usb_dwc2driver, 10879a138eb5SPatrick Delaunay base_register); 10889a138eb5SPatrick Delaunay } 1089