1*9a138eb5SPatrick Delaunay /* 2*9a138eb5SPatrick Delaunay * Copyright (c) 2021, STMicroelectronics - All Rights Reserved 3*9a138eb5SPatrick Delaunay * 4*9a138eb5SPatrick Delaunay * SPDX-License-Identifier: BSD-3-Clause 5*9a138eb5SPatrick Delaunay */ 6*9a138eb5SPatrick Delaunay 7*9a138eb5SPatrick Delaunay #include <stdint.h> 8*9a138eb5SPatrick Delaunay 9*9a138eb5SPatrick Delaunay #include <arch_helpers.h> 10*9a138eb5SPatrick Delaunay #include <common/debug.h> 11*9a138eb5SPatrick Delaunay #include <drivers/delay_timer.h> 12*9a138eb5SPatrick Delaunay #include <drivers/st/stm32mp1_usb.h> 13*9a138eb5SPatrick Delaunay #include <lib/mmio.h> 14*9a138eb5SPatrick Delaunay 15*9a138eb5SPatrick Delaunay #include <platform_def.h> 16*9a138eb5SPatrick Delaunay 17*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_DEVICE 0U 18*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_HOST 1U 19*9a138eb5SPatrick Delaunay #define USB_OTG_MODE_DRD 2U 20*9a138eb5SPatrick Delaunay 21*9a138eb5SPatrick Delaunay #define EP_TYPE_CTRL 0U 22*9a138eb5SPatrick Delaunay #define EP_TYPE_ISOC 1U 23*9a138eb5SPatrick Delaunay #define EP_TYPE_BULK 2U 24*9a138eb5SPatrick Delaunay #define EP_TYPE_INTR 3U 25*9a138eb5SPatrick Delaunay 26*9a138eb5SPatrick Delaunay #define USBD_FIFO_FLUSH_TIMEOUT_US 1000U 27*9a138eb5SPatrick Delaunay #define EP0_FIFO_SIZE 64U 28*9a138eb5SPatrick Delaunay 29*9a138eb5SPatrick Delaunay /* OTG registers offsets */ 30*9a138eb5SPatrick Delaunay #define OTG_GOTGINT 0x004U 31*9a138eb5SPatrick Delaunay #define OTG_GAHBCFG 0x008U 32*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG 0x00CU 33*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL 0x010U 34*9a138eb5SPatrick Delaunay #define OTG_GINTSTS 0x014U 35*9a138eb5SPatrick Delaunay #define OTG_GINTMSK 0x018U 36*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP 0x020U 37*9a138eb5SPatrick Delaunay #define OTG_GLPMCFG 0x054U 38*9a138eb5SPatrick Delaunay #define OTG_DCFG 0x800U 39*9a138eb5SPatrick Delaunay #define OTG_DCTL 0x804U 40*9a138eb5SPatrick Delaunay #define OTG_DSTS 0x808U 41*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK 0x810U 42*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK 0x814U 43*9a138eb5SPatrick Delaunay #define OTG_DAINT 0x818U 44*9a138eb5SPatrick Delaunay #define OTG_DAINTMSK 0x81CU 45*9a138eb5SPatrick Delaunay #define OTG_DIEPEMPMSK 0x834U 46*9a138eb5SPatrick Delaunay 47*9a138eb5SPatrick Delaunay /* Definitions for OTG_DIEPx registers */ 48*9a138eb5SPatrick Delaunay #define OTG_DIEP_BASE 0x900U 49*9a138eb5SPatrick Delaunay #define OTG_DIEP_SIZE 0x20U 50*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL 0x00U 51*9a138eb5SPatrick Delaunay #define OTG_DIEPINT 0x08U 52*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ 0x10U 53*9a138eb5SPatrick Delaunay #define OTG_DIEPDMA 0x14U 54*9a138eb5SPatrick Delaunay #define OTG_DTXFSTS 0x18U 55*9a138eb5SPatrick Delaunay #define OTG_DIEP_MAX_NB 9U 56*9a138eb5SPatrick Delaunay 57*9a138eb5SPatrick Delaunay /* Definitions for OTG_DOEPx registers */ 58*9a138eb5SPatrick Delaunay #define OTG_DOEP_BASE 0xB00U 59*9a138eb5SPatrick Delaunay #define OTG_DOEP_SIZE 0x20U 60*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL 0x00U 61*9a138eb5SPatrick Delaunay #define OTG_DOEPINT 0x08U 62*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ 0x10U 63*9a138eb5SPatrick Delaunay #define OTG_DOEPDMA 0x14U 64*9a138eb5SPatrick Delaunay #define OTG_D0EP_MAX_NB 9U 65*9a138eb5SPatrick Delaunay 66*9a138eb5SPatrick Delaunay /* Definitions for OTG_DAINT registers */ 67*9a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_MASK GENMASK(31, 16) 68*9a138eb5SPatrick Delaunay #define OTG_DAINT_OUT_SHIFT 16U 69*9a138eb5SPatrick Delaunay #define OTG_DAINT_IN_MASK GENMASK(15, 0) 70*9a138eb5SPatrick Delaunay #define OTG_DAINT_IN_SHIFT 0U 71*9a138eb5SPatrick Delaunay 72*9a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_IN BIT(16) 73*9a138eb5SPatrick Delaunay #define OTG_DAINT_EP0_OUT BIT(0) 74*9a138eb5SPatrick Delaunay 75*9a138eb5SPatrick Delaunay /* Definitions for FIFOs */ 76*9a138eb5SPatrick Delaunay #define OTG_FIFO_BASE 0x1000U 77*9a138eb5SPatrick Delaunay #define OTG_FIFO_SIZE 0x1000U 78*9a138eb5SPatrick Delaunay 79*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GOTGINT register */ 80*9a138eb5SPatrick Delaunay #define OTG_GOTGINT_SEDET BIT(2) 81*9a138eb5SPatrick Delaunay 82*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GAHBCFG register */ 83*9a138eb5SPatrick Delaunay #define OTG_GAHBCFG_GINT BIT(0) 84*9a138eb5SPatrick Delaunay 85*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GUSBCFG register */ 86*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT GENMASK(13, 10) 87*9a138eb5SPatrick Delaunay #define OTG_GUSBCFG_TRDT_SHIFT 10U 88*9a138eb5SPatrick Delaunay 89*9a138eb5SPatrick Delaunay #define USBD_HS_TRDT_VALUE 9U 90*9a138eb5SPatrick Delaunay 91*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRSTCTL register */ 92*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_RXFFLSH BIT(4) 93*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFFLSH BIT(5) 94*9a138eb5SPatrick Delaunay #define OTG_GRSTCTL_TXFNUM_SHIFT 6U 95*9a138eb5SPatrick Delaunay 96*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GINTSTS register */ 97*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_CMOD BIT(0) 98*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_MMIS BIT(1) 99*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_OTGINT BIT(2) 100*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_SOF BIT(3) 101*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_RXFLVL BIT(4) 102*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBSUSP BIT(11) 103*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_USBRST BIT(12) 104*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_ENUMDNE BIT(13) 105*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IEPINT BIT(18) 106*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_OEPINT BIT(19) 107*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IISOIXFR BIT(20) 108*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_IPXFR_INCOMPISOOUT BIT(21) 109*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_LPMINT BIT(27) 110*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_SRQINT BIT(30) 111*9a138eb5SPatrick Delaunay #define OTG_GINTSTS_WKUPINT BIT(31) 112*9a138eb5SPatrick Delaunay 113*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GRXSTSP register */ 114*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_EPNUM GENMASK(3, 0) 115*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT GENMASK(14, 4) 116*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_BCNT_SHIFT 4U 117*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS GENMASK(20, 17) 118*9a138eb5SPatrick Delaunay #define OTG_GRXSTSP_PKTSTS_SHIFT 17U 119*9a138eb5SPatrick Delaunay 120*9a138eb5SPatrick Delaunay #define STS_GOUT_NAK 1U 121*9a138eb5SPatrick Delaunay #define STS_DATA_UPDT 2U 122*9a138eb5SPatrick Delaunay #define STS_XFER_COMP 3U 123*9a138eb5SPatrick Delaunay #define STS_SETUP_COMP 4U 124*9a138eb5SPatrick Delaunay #define STS_SETUP_UPDT 6U 125*9a138eb5SPatrick Delaunay 126*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_GLPMCFG register */ 127*9a138eb5SPatrick Delaunay #define OTG_GLPMCFG_BESL GENMASK(5, 2) 128*9a138eb5SPatrick Delaunay 129*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCFG register */ 130*9a138eb5SPatrick Delaunay #define OTG_DCFG_DAD GENMASK(10, 4) 131*9a138eb5SPatrick Delaunay #define OTG_DCFG_DAD_SHIFT 4U 132*9a138eb5SPatrick Delaunay 133*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DCTL register */ 134*9a138eb5SPatrick Delaunay #define OTG_DCTL_RWUSIG BIT(0) 135*9a138eb5SPatrick Delaunay #define OTG_DCTL_SDIS BIT(1) 136*9a138eb5SPatrick Delaunay #define OTG_DCTL_CGINAK BIT(8) 137*9a138eb5SPatrick Delaunay 138*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DSTS register */ 139*9a138eb5SPatrick Delaunay #define OTG_DSTS_SUSPSTS BIT(0) 140*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_MASK GENMASK(2, 1) 141*9a138eb5SPatrick Delaunay #define OTG_DSTS_FNSOF0 BIT(8) 142*9a138eb5SPatrick Delaunay 143*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD(val) ((val) << 1) 144*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(0U) 145*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ OTG_DSTS_ENUMSPD(1U) 146*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_LS_PHY_6MHZ OTG_DSTS_ENUMSPD(2U) 147*9a138eb5SPatrick Delaunay #define OTG_DSTS_ENUMSPD_FS_PHY_48MHZ OTG_DSTS_ENUMSPD(3U) 148*9a138eb5SPatrick Delaunay 149*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPMSK register */ 150*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_XFRCM BIT(0) 151*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_EPDM BIT(1) 152*9a138eb5SPatrick Delaunay #define OTG_DIEPMSK_TOM BIT(3) 153*9a138eb5SPatrick Delaunay 154*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPMSK register */ 155*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_XFRCM BIT(0) 156*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_EPDM BIT(1) 157*9a138eb5SPatrick Delaunay #define OTG_DOEPMSK_STUPM BIT(3) 158*9a138eb5SPatrick Delaunay 159*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPCTLx registers */ 160*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_MPSIZ GENMASK(10, 0) 161*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_STALL BIT(21) 162*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_CNAK BIT(26) 163*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SD0PID_SEVNFRM BIT(28) 164*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_SODDFRM BIT(29) 165*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPDIS BIT(30) 166*9a138eb5SPatrick Delaunay #define OTG_DIEPCTL_EPENA BIT(31) 167*9a138eb5SPatrick Delaunay 168*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPINTx registers */ 169*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_XFRC BIT(0) 170*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_EPDISD BIT(1) 171*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TOC BIT(3) 172*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_ITTXFE BIT(4) 173*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_INEPNE BIT(6) 174*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE BIT(7) 175*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_TXFE_SHIFT 7U 176*9a138eb5SPatrick Delaunay 177*9a138eb5SPatrick Delaunay #define OTG_DIEPINT_MASK (BIT(13) | BIT(11) | GENMASK(9, 0)) 178*9a138eb5SPatrick Delaunay 179*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DIEPTSIZx registers */ 180*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_XFRSIZ GENMASK(18, 0) 181*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT GENMASK(28, 19) 182*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_SHIFT 19U 183*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_MASK GENMASK(30, 29) 184*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_MCNT_DATA0 BIT(29) 185*9a138eb5SPatrick Delaunay 186*9a138eb5SPatrick Delaunay #define OTG_DIEPTSIZ_PKTCNT_1 BIT(19) 187*9a138eb5SPatrick Delaunay 188*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DTXFSTSx registers */ 189*9a138eb5SPatrick Delaunay #define OTG_DTXFSTS_INEPTFSAV GENMASK(15, 0) 190*9a138eb5SPatrick Delaunay 191*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPCTLx registers */ 192*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_STALL BIT(21) 193*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_CNAK BIT(26) 194*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD0PID_SEVNFRM BIT(28) /* other than endpoint 0 */ 195*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_SD1PID_SODDFRM BIT(29) /* other than endpoint 0 */ 196*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPDIS BIT(30) 197*9a138eb5SPatrick Delaunay #define OTG_DOEPCTL_EPENA BIT(31) 198*9a138eb5SPatrick Delaunay 199*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPTSIZx registers */ 200*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_XFRSIZ GENMASK(18, 0) 201*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_PKTCNT GENMASK(28, 19) 202*9a138eb5SPatrick Delaunay #define OTG_DOEPTSIZ_RXDPID_STUPCNT GENMASK(30, 29) 203*9a138eb5SPatrick Delaunay 204*9a138eb5SPatrick Delaunay /* Bit definitions for OTG_DOEPINTx registers */ 205*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_XFRC BIT(0) 206*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_STUP BIT(3) 207*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_OTEPDIS BIT(4) 208*9a138eb5SPatrick Delaunay 209*9a138eb5SPatrick Delaunay #define OTG_DOEPINT_MASK (GENMASK(15, 12) | GENMASK(9, 8) | GENMASK(6, 0)) 210*9a138eb5SPatrick Delaunay 211*9a138eb5SPatrick Delaunay #define EP_NB 15U 212*9a138eb5SPatrick Delaunay #define EP_ALL 0x10U 213*9a138eb5SPatrick Delaunay 214*9a138eb5SPatrick Delaunay /* 215*9a138eb5SPatrick Delaunay * Flush TX FIFO. 216*9a138eb5SPatrick Delaunay * handle: PCD handle. 217*9a138eb5SPatrick Delaunay * num: FIFO number. 218*9a138eb5SPatrick Delaunay * This parameter can be a value from 1 to 15 or EP_ALL. 219*9a138eb5SPatrick Delaunay * EP_ALL= 0x10 means Flush all TX FIFOs 220*9a138eb5SPatrick Delaunay * return: USB status. 221*9a138eb5SPatrick Delaunay */ 222*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_tx_fifo(void *handle, uint32_t num) 223*9a138eb5SPatrick Delaunay { 224*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 225*9a138eb5SPatrick Delaunay uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US); 226*9a138eb5SPatrick Delaunay 227*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GRSTCTL, 228*9a138eb5SPatrick Delaunay OTG_GRSTCTL_TXFFLSH | (uint32_t)(num << OTG_GRSTCTL_TXFNUM_SHIFT)); 229*9a138eb5SPatrick Delaunay 230*9a138eb5SPatrick Delaunay while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) & 231*9a138eb5SPatrick Delaunay OTG_GRSTCTL_TXFFLSH) == OTG_GRSTCTL_TXFFLSH) { 232*9a138eb5SPatrick Delaunay if (timeout_elapsed(timeout)) { 233*9a138eb5SPatrick Delaunay return USBD_TIMEOUT; 234*9a138eb5SPatrick Delaunay } 235*9a138eb5SPatrick Delaunay } 236*9a138eb5SPatrick Delaunay 237*9a138eb5SPatrick Delaunay return USBD_OK; 238*9a138eb5SPatrick Delaunay } 239*9a138eb5SPatrick Delaunay 240*9a138eb5SPatrick Delaunay /* 241*9a138eb5SPatrick Delaunay * Flush RX FIFO. 242*9a138eb5SPatrick Delaunay * handle: PCD handle. 243*9a138eb5SPatrick Delaunay * return: USB status. 244*9a138eb5SPatrick Delaunay */ 245*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_flush_rx_fifo(void *handle) 246*9a138eb5SPatrick Delaunay { 247*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 248*9a138eb5SPatrick Delaunay uint64_t timeout = timeout_init_us(USBD_FIFO_FLUSH_TIMEOUT_US); 249*9a138eb5SPatrick Delaunay 250*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GRSTCTL, OTG_GRSTCTL_RXFFLSH); 251*9a138eb5SPatrick Delaunay 252*9a138eb5SPatrick Delaunay while ((mmio_read_32(usb_base_addr + OTG_GRSTCTL) & 253*9a138eb5SPatrick Delaunay OTG_GRSTCTL_RXFFLSH) == OTG_GRSTCTL_RXFFLSH) { 254*9a138eb5SPatrick Delaunay if (timeout_elapsed(timeout)) { 255*9a138eb5SPatrick Delaunay return USBD_TIMEOUT; 256*9a138eb5SPatrick Delaunay } 257*9a138eb5SPatrick Delaunay } 258*9a138eb5SPatrick Delaunay 259*9a138eb5SPatrick Delaunay return USBD_OK; 260*9a138eb5SPatrick Delaunay } 261*9a138eb5SPatrick Delaunay 262*9a138eb5SPatrick Delaunay /* 263*9a138eb5SPatrick Delaunay * Return the global USB interrupt status. 264*9a138eb5SPatrick Delaunay * handle: PCD handle. 265*9a138eb5SPatrick Delaunay * return: Interrupt register value. 266*9a138eb5SPatrick Delaunay */ 267*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_read_int(void *handle) 268*9a138eb5SPatrick Delaunay { 269*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 270*9a138eb5SPatrick Delaunay 271*9a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_GINTSTS) & 272*9a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_GINTMSK); 273*9a138eb5SPatrick Delaunay } 274*9a138eb5SPatrick Delaunay 275*9a138eb5SPatrick Delaunay /* 276*9a138eb5SPatrick Delaunay * Return the USB device OUT endpoints interrupt. 277*9a138eb5SPatrick Delaunay * handle: PCD handle. 278*9a138eb5SPatrick Delaunay * return: Device OUT endpoint interrupts. 279*9a138eb5SPatrick Delaunay */ 280*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_out_ep_int(void *handle) 281*9a138eb5SPatrick Delaunay { 282*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 283*9a138eb5SPatrick Delaunay 284*9a138eb5SPatrick Delaunay return ((mmio_read_32(usb_base_addr + OTG_DAINT) & 285*9a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DAINTMSK)) & 286*9a138eb5SPatrick Delaunay OTG_DAINT_OUT_MASK) >> OTG_DAINT_OUT_SHIFT; 287*9a138eb5SPatrick Delaunay } 288*9a138eb5SPatrick Delaunay 289*9a138eb5SPatrick Delaunay /* 290*9a138eb5SPatrick Delaunay * Return the USB device IN endpoints interrupt. 291*9a138eb5SPatrick Delaunay * handle: PCD handle. 292*9a138eb5SPatrick Delaunay * return: Device IN endpoint interrupts. 293*9a138eb5SPatrick Delaunay */ 294*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_all_in_ep_int(void *handle) 295*9a138eb5SPatrick Delaunay { 296*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 297*9a138eb5SPatrick Delaunay 298*9a138eb5SPatrick Delaunay return ((mmio_read_32(usb_base_addr + OTG_DAINT) & 299*9a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DAINTMSK)) & 300*9a138eb5SPatrick Delaunay OTG_DAINT_IN_MASK) >> OTG_DAINT_IN_SHIFT; 301*9a138eb5SPatrick Delaunay } 302*9a138eb5SPatrick Delaunay 303*9a138eb5SPatrick Delaunay /* 304*9a138eb5SPatrick Delaunay * Return Device OUT EP interrupt register. 305*9a138eb5SPatrick Delaunay * handle: PCD handle. 306*9a138eb5SPatrick Delaunay * epnum: Endpoint number. 307*9a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 15. 308*9a138eb5SPatrick Delaunay * return: Device OUT EP Interrupt register. 309*9a138eb5SPatrick Delaunay */ 310*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_out_ep_int(void *handle, uint8_t epnum) 311*9a138eb5SPatrick Delaunay { 312*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 313*9a138eb5SPatrick Delaunay 314*9a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_DOEP_BASE + 315*9a138eb5SPatrick Delaunay (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT) & 316*9a138eb5SPatrick Delaunay mmio_read_32(usb_base_addr + OTG_DOEPMSK); 317*9a138eb5SPatrick Delaunay } 318*9a138eb5SPatrick Delaunay 319*9a138eb5SPatrick Delaunay /* 320*9a138eb5SPatrick Delaunay * Return Device IN EP interrupt register. 321*9a138eb5SPatrick Delaunay * handle: PCD handle. 322*9a138eb5SPatrick Delaunay * epnum: Endpoint number. 323*9a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 15. 324*9a138eb5SPatrick Delaunay * return: Device IN EP Interrupt register. 325*9a138eb5SPatrick Delaunay */ 326*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_in_ep_int(void *handle, uint8_t epnum) 327*9a138eb5SPatrick Delaunay { 328*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 329*9a138eb5SPatrick Delaunay uint32_t msk; 330*9a138eb5SPatrick Delaunay uint32_t emp; 331*9a138eb5SPatrick Delaunay 332*9a138eb5SPatrick Delaunay msk = mmio_read_32(usb_base_addr + OTG_DIEPMSK); 333*9a138eb5SPatrick Delaunay emp = mmio_read_32(usb_base_addr + OTG_DIEPEMPMSK); 334*9a138eb5SPatrick Delaunay msk |= ((emp >> epnum) << OTG_DIEPINT_TXFE_SHIFT) & OTG_DIEPINT_TXFE; 335*9a138eb5SPatrick Delaunay 336*9a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_DIEP_BASE + 337*9a138eb5SPatrick Delaunay (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT) & msk; 338*9a138eb5SPatrick Delaunay } 339*9a138eb5SPatrick Delaunay 340*9a138eb5SPatrick Delaunay /* 341*9a138eb5SPatrick Delaunay * Return USB core mode. 342*9a138eb5SPatrick Delaunay * handle: PCD handle. 343*9a138eb5SPatrick Delaunay * return: Core mode. 344*9a138eb5SPatrick Delaunay * This parameter can be 0 (host) or 1 (device). 345*9a138eb5SPatrick Delaunay */ 346*9a138eb5SPatrick Delaunay static uint32_t usb_dwc2_get_mode(void *handle) 347*9a138eb5SPatrick Delaunay { 348*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 349*9a138eb5SPatrick Delaunay 350*9a138eb5SPatrick Delaunay return mmio_read_32(usb_base_addr + OTG_GINTSTS) & OTG_GINTSTS_CMOD; 351*9a138eb5SPatrick Delaunay } 352*9a138eb5SPatrick Delaunay 353*9a138eb5SPatrick Delaunay /* 354*9a138eb5SPatrick Delaunay * Activate EP0 for detup transactions. 355*9a138eb5SPatrick Delaunay * handle: PCD handle. 356*9a138eb5SPatrick Delaunay * return: USB status. 357*9a138eb5SPatrick Delaunay */ 358*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_activate_setup(void *handle) 359*9a138eb5SPatrick Delaunay { 360*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 361*9a138eb5SPatrick Delaunay uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE; 362*9a138eb5SPatrick Delaunay 363*9a138eb5SPatrick Delaunay /* Set the MPS of the IN EP based on the enumeration speed */ 364*9a138eb5SPatrick Delaunay mmio_clrbits_32(reg_offset + OTG_DIEPCTL, OTG_DIEPCTL_MPSIZ); 365*9a138eb5SPatrick Delaunay 366*9a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_ENUMSPD_MASK) == 367*9a138eb5SPatrick Delaunay OTG_DSTS_ENUMSPD_LS_PHY_6MHZ) { 368*9a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, 3U); 369*9a138eb5SPatrick Delaunay } 370*9a138eb5SPatrick Delaunay 371*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_CGINAK); 372*9a138eb5SPatrick Delaunay 373*9a138eb5SPatrick Delaunay return USBD_OK; 374*9a138eb5SPatrick Delaunay } 375*9a138eb5SPatrick Delaunay 376*9a138eb5SPatrick Delaunay /* 377*9a138eb5SPatrick Delaunay * Prepare the EP0 to start the first control setup. 378*9a138eb5SPatrick Delaunay * handle: Selected device. 379*9a138eb5SPatrick Delaunay * return: USB status. 380*9a138eb5SPatrick Delaunay */ 381*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_out_start(void *handle) 382*9a138eb5SPatrick Delaunay { 383*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 384*9a138eb5SPatrick Delaunay uintptr_t reg_offset = usb_base_addr + OTG_DIEP_BASE + OTG_DIEPTSIZ; 385*9a138eb5SPatrick Delaunay uint32_t reg_value = 0U; 386*9a138eb5SPatrick Delaunay 387*9a138eb5SPatrick Delaunay /* PKTCNT = 1 and XFRSIZ = 24 bytes for endpoint 0 */ 388*9a138eb5SPatrick Delaunay reg_value |= OTG_DIEPTSIZ_PKTCNT_1; 389*9a138eb5SPatrick Delaunay reg_value |= (EP0_FIFO_SIZE & OTG_DIEPTSIZ_XFRSIZ); 390*9a138eb5SPatrick Delaunay reg_value |= OTG_DOEPTSIZ_RXDPID_STUPCNT; 391*9a138eb5SPatrick Delaunay 392*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, reg_value); 393*9a138eb5SPatrick Delaunay 394*9a138eb5SPatrick Delaunay return USBD_OK; 395*9a138eb5SPatrick Delaunay } 396*9a138eb5SPatrick Delaunay 397*9a138eb5SPatrick Delaunay /* 398*9a138eb5SPatrick Delaunay * Write a packet into the TX FIFO associated with the EP/channel. 399*9a138eb5SPatrick Delaunay * handle: Selected device. 400*9a138eb5SPatrick Delaunay * src: Pointer to source buffer. 401*9a138eb5SPatrick Delaunay * ch_ep_num: Endpoint or host channel number. 402*9a138eb5SPatrick Delaunay * len: Number of bytes to write. 403*9a138eb5SPatrick Delaunay * return: USB status. 404*9a138eb5SPatrick Delaunay */ 405*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_packet(void *handle, uint8_t *src, 406*9a138eb5SPatrick Delaunay uint8_t ch_ep_num, uint16_t len) 407*9a138eb5SPatrick Delaunay { 408*9a138eb5SPatrick Delaunay uint32_t reg_offset; 409*9a138eb5SPatrick Delaunay uint32_t count32b = (len + 3U) / 4U; 410*9a138eb5SPatrick Delaunay uint32_t i; 411*9a138eb5SPatrick Delaunay 412*9a138eb5SPatrick Delaunay reg_offset = (uintptr_t)handle + OTG_FIFO_BASE + 413*9a138eb5SPatrick Delaunay (ch_ep_num * OTG_FIFO_SIZE); 414*9a138eb5SPatrick Delaunay 415*9a138eb5SPatrick Delaunay for (i = 0U; i < count32b; i++) { 416*9a138eb5SPatrick Delaunay uint32_t src_copy = 0U; 417*9a138eb5SPatrick Delaunay uint32_t j; 418*9a138eb5SPatrick Delaunay 419*9a138eb5SPatrick Delaunay /* Data written to FIFO need to be 4 bytes aligned */ 420*9a138eb5SPatrick Delaunay for (j = 0U; j < 4U; j++) { 421*9a138eb5SPatrick Delaunay src_copy += (*(src + j)) << (8U * j); 422*9a138eb5SPatrick Delaunay } 423*9a138eb5SPatrick Delaunay 424*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, src_copy); 425*9a138eb5SPatrick Delaunay src += 4U; 426*9a138eb5SPatrick Delaunay } 427*9a138eb5SPatrick Delaunay 428*9a138eb5SPatrick Delaunay return USBD_OK; 429*9a138eb5SPatrick Delaunay } 430*9a138eb5SPatrick Delaunay 431*9a138eb5SPatrick Delaunay /* 432*9a138eb5SPatrick Delaunay * Read a packet from the RX FIFO associated with the EP/channel. 433*9a138eb5SPatrick Delaunay * handle: Selected device. 434*9a138eb5SPatrick Delaunay * dst: Destination pointer. 435*9a138eb5SPatrick Delaunay * len: Number of bytes to read. 436*9a138eb5SPatrick Delaunay * return: Pointer to destination buffer. 437*9a138eb5SPatrick Delaunay */ 438*9a138eb5SPatrick Delaunay static void *usb_dwc2_read_packet(void *handle, uint8_t *dest, uint16_t len) 439*9a138eb5SPatrick Delaunay { 440*9a138eb5SPatrick Delaunay uint32_t reg_offset; 441*9a138eb5SPatrick Delaunay uint32_t count32b = (len + 3U) / 4U; 442*9a138eb5SPatrick Delaunay uint32_t i; 443*9a138eb5SPatrick Delaunay 444*9a138eb5SPatrick Delaunay VERBOSE("read packet length %i to 0x%lx\n", len, (uintptr_t)dest); 445*9a138eb5SPatrick Delaunay 446*9a138eb5SPatrick Delaunay reg_offset = (uintptr_t)handle + OTG_FIFO_BASE; 447*9a138eb5SPatrick Delaunay 448*9a138eb5SPatrick Delaunay for (i = 0U; i < count32b; i++) { 449*9a138eb5SPatrick Delaunay *(uint32_t *)dest = mmio_read_32(reg_offset); 450*9a138eb5SPatrick Delaunay dest += 4U; 451*9a138eb5SPatrick Delaunay dsb(); 452*9a138eb5SPatrick Delaunay } 453*9a138eb5SPatrick Delaunay 454*9a138eb5SPatrick Delaunay return (void *)dest; 455*9a138eb5SPatrick Delaunay } 456*9a138eb5SPatrick Delaunay 457*9a138eb5SPatrick Delaunay /* 458*9a138eb5SPatrick Delaunay * Setup and start a transfer over an EP. 459*9a138eb5SPatrick Delaunay * handle: Selected device 460*9a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 461*9a138eb5SPatrick Delaunay * return: USB status. 462*9a138eb5SPatrick Delaunay */ 463*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_start_xfer(void *handle, struct usbd_ep *ep) 464*9a138eb5SPatrick Delaunay { 465*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 466*9a138eb5SPatrick Delaunay uint32_t reg_offset; 467*9a138eb5SPatrick Delaunay uint32_t reg_value; 468*9a138eb5SPatrick Delaunay uint32_t clear_value; 469*9a138eb5SPatrick Delaunay 470*9a138eb5SPatrick Delaunay if (ep->is_in) { 471*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (ep->num * OTG_DIEP_SIZE); 472*9a138eb5SPatrick Delaunay clear_value = OTG_DIEPTSIZ_PKTCNT | OTG_DIEPTSIZ_XFRSIZ; 473*9a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 474*9a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1; 475*9a138eb5SPatrick Delaunay } else { 476*9a138eb5SPatrick Delaunay /* 477*9a138eb5SPatrick Delaunay * Program the transfer size and packet count 478*9a138eb5SPatrick Delaunay * as follows: 479*9a138eb5SPatrick Delaunay * xfersize = N * maxpacket + short_packet 480*9a138eb5SPatrick Delaunay * pktcnt = N + (short_packet exist ? 1 : 0) 481*9a138eb5SPatrick Delaunay */ 482*9a138eb5SPatrick Delaunay reg_value = (OTG_DIEPTSIZ_PKTCNT & 483*9a138eb5SPatrick Delaunay (((ep->xfer_len + ep->maxpacket - 1U) / 484*9a138eb5SPatrick Delaunay ep->maxpacket) << OTG_DIEPTSIZ_PKTCNT_SHIFT)) 485*9a138eb5SPatrick Delaunay | ep->xfer_len; 486*9a138eb5SPatrick Delaunay 487*9a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 488*9a138eb5SPatrick Delaunay clear_value |= OTG_DIEPTSIZ_MCNT_MASK; 489*9a138eb5SPatrick Delaunay reg_value |= OTG_DIEPTSIZ_MCNT_DATA0; 490*9a138eb5SPatrick Delaunay } 491*9a138eb5SPatrick Delaunay } 492*9a138eb5SPatrick Delaunay 493*9a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, clear_value, reg_value); 494*9a138eb5SPatrick Delaunay 495*9a138eb5SPatrick Delaunay if ((ep->type != EP_TYPE_ISOC) && (ep->xfer_len > 0U)) { 496*9a138eb5SPatrick Delaunay /* Enable the TX FIFO empty interrupt for this EP */ 497*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(ep->num)); 498*9a138eb5SPatrick Delaunay } 499*9a138eb5SPatrick Delaunay 500*9a138eb5SPatrick Delaunay /* EP enable, IN data in FIFO */ 501*9a138eb5SPatrick Delaunay reg_value = OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA; 502*9a138eb5SPatrick Delaunay 503*9a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 504*9a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) { 505*9a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_SODDFRM; 506*9a138eb5SPatrick Delaunay } else { 507*9a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_SD0PID_SEVNFRM; 508*9a138eb5SPatrick Delaunay } 509*9a138eb5SPatrick Delaunay } 510*9a138eb5SPatrick Delaunay 511*9a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, reg_value); 512*9a138eb5SPatrick Delaunay 513*9a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 514*9a138eb5SPatrick Delaunay usb_dwc2_write_packet(handle, ep->xfer_buff, ep->num, ep->xfer_len); 515*9a138eb5SPatrick Delaunay } 516*9a138eb5SPatrick Delaunay } else { 517*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + (ep->num * OTG_DOEP_SIZE); 518*9a138eb5SPatrick Delaunay /* 519*9a138eb5SPatrick Delaunay * Program the transfer size and packet count as follows: 520*9a138eb5SPatrick Delaunay * pktcnt = N 521*9a138eb5SPatrick Delaunay * xfersize = N * maxpacket 522*9a138eb5SPatrick Delaunay */ 523*9a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 524*9a138eb5SPatrick Delaunay reg_value = ep->maxpacket | OTG_DIEPTSIZ_PKTCNT_1; 525*9a138eb5SPatrick Delaunay } else { 526*9a138eb5SPatrick Delaunay uint16_t pktcnt = (ep->xfer_len + ep->maxpacket - 1U) / ep->maxpacket; 527*9a138eb5SPatrick Delaunay 528*9a138eb5SPatrick Delaunay reg_value = (pktcnt << OTG_DIEPTSIZ_PKTCNT_SHIFT) | 529*9a138eb5SPatrick Delaunay (ep->maxpacket * pktcnt); 530*9a138eb5SPatrick Delaunay } 531*9a138eb5SPatrick Delaunay 532*9a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DOEPTSIZ, 533*9a138eb5SPatrick Delaunay OTG_DOEPTSIZ_XFRSIZ & OTG_DOEPTSIZ_PKTCNT, 534*9a138eb5SPatrick Delaunay reg_value); 535*9a138eb5SPatrick Delaunay 536*9a138eb5SPatrick Delaunay /* EP enable */ 537*9a138eb5SPatrick Delaunay reg_value = OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA; 538*9a138eb5SPatrick Delaunay 539*9a138eb5SPatrick Delaunay if (ep->type == EP_TYPE_ISOC) { 540*9a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & OTG_DSTS_FNSOF0) == 0U) { 541*9a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_SD1PID_SODDFRM; 542*9a138eb5SPatrick Delaunay } else { 543*9a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_SD0PID_SEVNFRM; 544*9a138eb5SPatrick Delaunay } 545*9a138eb5SPatrick Delaunay } 546*9a138eb5SPatrick Delaunay 547*9a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DOEPCTL, reg_value); 548*9a138eb5SPatrick Delaunay } 549*9a138eb5SPatrick Delaunay 550*9a138eb5SPatrick Delaunay return USBD_OK; 551*9a138eb5SPatrick Delaunay } 552*9a138eb5SPatrick Delaunay 553*9a138eb5SPatrick Delaunay /* 554*9a138eb5SPatrick Delaunay * Setup and start a transfer over the EP0. 555*9a138eb5SPatrick Delaunay * handle: Selected device. 556*9a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 557*9a138eb5SPatrick Delaunay * return: USB status. 558*9a138eb5SPatrick Delaunay */ 559*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep0_start_xfer(void *handle, struct usbd_ep *ep) 560*9a138eb5SPatrick Delaunay { 561*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 562*9a138eb5SPatrick Delaunay uint32_t reg_offset; 563*9a138eb5SPatrick Delaunay uint32_t reg_value; 564*9a138eb5SPatrick Delaunay 565*9a138eb5SPatrick Delaunay if (ep->is_in) { 566*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + 567*9a138eb5SPatrick Delaunay (ep->num * OTG_DIEP_SIZE); 568*9a138eb5SPatrick Delaunay 569*9a138eb5SPatrick Delaunay if (ep->xfer_len == 0U) { 570*9a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1; 571*9a138eb5SPatrick Delaunay } else { 572*9a138eb5SPatrick Delaunay /* 573*9a138eb5SPatrick Delaunay * Program the transfer size and packet count 574*9a138eb5SPatrick Delaunay * as follows: 575*9a138eb5SPatrick Delaunay * xfersize = N * maxpacket + short_packet 576*9a138eb5SPatrick Delaunay * pktcnt = N + (short_packet exist ? 1 : 0) 577*9a138eb5SPatrick Delaunay */ 578*9a138eb5SPatrick Delaunay 579*9a138eb5SPatrick Delaunay if (ep->xfer_len > ep->maxpacket) { 580*9a138eb5SPatrick Delaunay ep->xfer_len = ep->maxpacket; 581*9a138eb5SPatrick Delaunay } 582*9a138eb5SPatrick Delaunay 583*9a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->xfer_len; 584*9a138eb5SPatrick Delaunay } 585*9a138eb5SPatrick Delaunay 586*9a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, 587*9a138eb5SPatrick Delaunay OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT, 588*9a138eb5SPatrick Delaunay reg_value); 589*9a138eb5SPatrick Delaunay 590*9a138eb5SPatrick Delaunay /* Enable the TX FIFO empty interrupt for this EP */ 591*9a138eb5SPatrick Delaunay if (ep->xfer_len > 0U) { 592*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPEMPMSK, 593*9a138eb5SPatrick Delaunay BIT(ep->num)); 594*9a138eb5SPatrick Delaunay } 595*9a138eb5SPatrick Delaunay 596*9a138eb5SPatrick Delaunay /* EP enable, IN data in FIFO */ 597*9a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DIEPCTL, 598*9a138eb5SPatrick Delaunay OTG_DIEPCTL_CNAK | OTG_DIEPCTL_EPENA); 599*9a138eb5SPatrick Delaunay } else { 600*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + 601*9a138eb5SPatrick Delaunay (ep->num * OTG_DOEP_SIZE); 602*9a138eb5SPatrick Delaunay 603*9a138eb5SPatrick Delaunay /* 604*9a138eb5SPatrick Delaunay * Program the transfer size and packet count as follows: 605*9a138eb5SPatrick Delaunay * pktcnt = N 606*9a138eb5SPatrick Delaunay * xfersize = N * maxpacket 607*9a138eb5SPatrick Delaunay */ 608*9a138eb5SPatrick Delaunay if (ep->xfer_len > 0U) { 609*9a138eb5SPatrick Delaunay ep->xfer_len = ep->maxpacket; 610*9a138eb5SPatrick Delaunay } 611*9a138eb5SPatrick Delaunay 612*9a138eb5SPatrick Delaunay reg_value = OTG_DIEPTSIZ_PKTCNT_1 | ep->maxpacket; 613*9a138eb5SPatrick Delaunay 614*9a138eb5SPatrick Delaunay mmio_clrsetbits_32(reg_offset + OTG_DIEPTSIZ, 615*9a138eb5SPatrick Delaunay OTG_DIEPTSIZ_XFRSIZ | OTG_DIEPTSIZ_PKTCNT, 616*9a138eb5SPatrick Delaunay reg_value); 617*9a138eb5SPatrick Delaunay 618*9a138eb5SPatrick Delaunay /* EP enable */ 619*9a138eb5SPatrick Delaunay mmio_setbits_32(reg_offset + OTG_DOEPCTL, 620*9a138eb5SPatrick Delaunay OTG_DOEPCTL_CNAK | OTG_DOEPCTL_EPENA); 621*9a138eb5SPatrick Delaunay } 622*9a138eb5SPatrick Delaunay 623*9a138eb5SPatrick Delaunay return USBD_OK; 624*9a138eb5SPatrick Delaunay } 625*9a138eb5SPatrick Delaunay 626*9a138eb5SPatrick Delaunay /* 627*9a138eb5SPatrick Delaunay * Set a stall condition over an EP. 628*9a138eb5SPatrick Delaunay * handle: Selected device. 629*9a138eb5SPatrick Delaunay * ep: Pointer to endpoint structure. 630*9a138eb5SPatrick Delaunay * return: USB status. 631*9a138eb5SPatrick Delaunay */ 632*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_ep_set_stall(void *handle, struct usbd_ep *ep) 633*9a138eb5SPatrick Delaunay { 634*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 635*9a138eb5SPatrick Delaunay uint32_t reg_offset; 636*9a138eb5SPatrick Delaunay uint32_t reg_value; 637*9a138eb5SPatrick Delaunay 638*9a138eb5SPatrick Delaunay if (ep->is_in) { 639*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + 640*9a138eb5SPatrick Delaunay (ep->num * OTG_DIEP_SIZE); 641*9a138eb5SPatrick Delaunay reg_value = mmio_read_32(reg_offset + OTG_DIEPCTL); 642*9a138eb5SPatrick Delaunay 643*9a138eb5SPatrick Delaunay if ((reg_value & OTG_DIEPCTL_EPENA) == 0U) { 644*9a138eb5SPatrick Delaunay reg_value &= ~OTG_DIEPCTL_EPDIS; 645*9a138eb5SPatrick Delaunay } 646*9a138eb5SPatrick Delaunay 647*9a138eb5SPatrick Delaunay reg_value |= OTG_DIEPCTL_STALL; 648*9a138eb5SPatrick Delaunay 649*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset + OTG_DIEPCTL, reg_value); 650*9a138eb5SPatrick Delaunay } else { 651*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + 652*9a138eb5SPatrick Delaunay (ep->num * OTG_DOEP_SIZE); 653*9a138eb5SPatrick Delaunay reg_value = mmio_read_32(reg_offset + OTG_DOEPCTL); 654*9a138eb5SPatrick Delaunay 655*9a138eb5SPatrick Delaunay if ((reg_value & OTG_DOEPCTL_EPENA) == 0U) { 656*9a138eb5SPatrick Delaunay reg_value &= ~OTG_DOEPCTL_EPDIS; 657*9a138eb5SPatrick Delaunay } 658*9a138eb5SPatrick Delaunay 659*9a138eb5SPatrick Delaunay reg_value |= OTG_DOEPCTL_STALL; 660*9a138eb5SPatrick Delaunay 661*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset + OTG_DOEPCTL, reg_value); 662*9a138eb5SPatrick Delaunay } 663*9a138eb5SPatrick Delaunay 664*9a138eb5SPatrick Delaunay return USBD_OK; 665*9a138eb5SPatrick Delaunay } 666*9a138eb5SPatrick Delaunay 667*9a138eb5SPatrick Delaunay /* 668*9a138eb5SPatrick Delaunay * Stop the USB device mode. 669*9a138eb5SPatrick Delaunay * handle: Selected device. 670*9a138eb5SPatrick Delaunay * return: USB status. 671*9a138eb5SPatrick Delaunay */ 672*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_stop_device(void *handle) 673*9a138eb5SPatrick Delaunay { 674*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 675*9a138eb5SPatrick Delaunay uint32_t i; 676*9a138eb5SPatrick Delaunay 677*9a138eb5SPatrick Delaunay /* Disable Int */ 678*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT); 679*9a138eb5SPatrick Delaunay 680*9a138eb5SPatrick Delaunay /* Clear pending interrupts */ 681*9a138eb5SPatrick Delaunay for (i = 0U; i < EP_NB; i++) { 682*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DIEP_BASE + (i * OTG_DIEP_SIZE) + OTG_DIEPINT, 683*9a138eb5SPatrick Delaunay OTG_DIEPINT_MASK); 684*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DOEP_BASE + (i * OTG_DOEP_SIZE) + OTG_DOEPINT, 685*9a138eb5SPatrick Delaunay OTG_DOEPINT_MASK); 686*9a138eb5SPatrick Delaunay } 687*9a138eb5SPatrick Delaunay 688*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK); 689*9a138eb5SPatrick Delaunay 690*9a138eb5SPatrick Delaunay /* Clear interrupt masks */ 691*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DIEPMSK, 0U); 692*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DOEPMSK, 0U); 693*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINTMSK, 0U); 694*9a138eb5SPatrick Delaunay 695*9a138eb5SPatrick Delaunay /* Flush the FIFO */ 696*9a138eb5SPatrick Delaunay usb_dwc2_flush_rx_fifo(handle); 697*9a138eb5SPatrick Delaunay usb_dwc2_flush_tx_fifo(handle, EP_ALL); 698*9a138eb5SPatrick Delaunay 699*9a138eb5SPatrick Delaunay /* Disconnect the USB device by disabling the pull-up/pull-down */ 700*9a138eb5SPatrick Delaunay mmio_setbits_32((uintptr_t)handle + OTG_DCTL, OTG_DCTL_SDIS); 701*9a138eb5SPatrick Delaunay 702*9a138eb5SPatrick Delaunay return USBD_OK; 703*9a138eb5SPatrick Delaunay } 704*9a138eb5SPatrick Delaunay 705*9a138eb5SPatrick Delaunay /* 706*9a138eb5SPatrick Delaunay * Stop the USB device mode. 707*9a138eb5SPatrick Delaunay * handle: Selected device. 708*9a138eb5SPatrick Delaunay * address: New device address to be assigned. 709*9a138eb5SPatrick Delaunay * This parameter can be a value from 0 to 255. 710*9a138eb5SPatrick Delaunay * return: USB status. 711*9a138eb5SPatrick Delaunay */ 712*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_set_address(void *handle, uint8_t address) 713*9a138eb5SPatrick Delaunay { 714*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 715*9a138eb5SPatrick Delaunay 716*9a138eb5SPatrick Delaunay mmio_clrsetbits_32(usb_base_addr + OTG_DCFG, 717*9a138eb5SPatrick Delaunay OTG_DCFG_DAD, 718*9a138eb5SPatrick Delaunay address << OTG_DCFG_DAD_SHIFT); 719*9a138eb5SPatrick Delaunay 720*9a138eb5SPatrick Delaunay return USBD_OK; 721*9a138eb5SPatrick Delaunay } 722*9a138eb5SPatrick Delaunay 723*9a138eb5SPatrick Delaunay /* 724*9a138eb5SPatrick Delaunay * Check FIFO for the next packet to be loaded. 725*9a138eb5SPatrick Delaunay * handle: Selected device. 726*9a138eb5SPatrick Delaunay * epnum : Endpoint number. 727*9a138eb5SPatrick Delaunay * xfer_len: Block length. 728*9a138eb5SPatrick Delaunay * xfer_count: Number of blocks. 729*9a138eb5SPatrick Delaunay * maxpacket: Max packet length. 730*9a138eb5SPatrick Delaunay * xfer_buff: Buffer pointer. 731*9a138eb5SPatrick Delaunay * return: USB status. 732*9a138eb5SPatrick Delaunay */ 733*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_write_empty_tx_fifo(void *handle, 734*9a138eb5SPatrick Delaunay uint32_t epnum, 735*9a138eb5SPatrick Delaunay uint32_t xfer_len, 736*9a138eb5SPatrick Delaunay uint32_t *xfer_count, 737*9a138eb5SPatrick Delaunay uint32_t maxpacket, 738*9a138eb5SPatrick Delaunay uint8_t **xfer_buff) 739*9a138eb5SPatrick Delaunay { 740*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 741*9a138eb5SPatrick Delaunay uint32_t reg_offset; 742*9a138eb5SPatrick Delaunay int32_t len; 743*9a138eb5SPatrick Delaunay uint32_t len32b; 744*9a138eb5SPatrick Delaunay enum usb_status ret; 745*9a138eb5SPatrick Delaunay 746*9a138eb5SPatrick Delaunay len = xfer_len - *xfer_count; 747*9a138eb5SPatrick Delaunay 748*9a138eb5SPatrick Delaunay if ((len > 0) && ((uint32_t)len > maxpacket)) { 749*9a138eb5SPatrick Delaunay len = maxpacket; 750*9a138eb5SPatrick Delaunay } 751*9a138eb5SPatrick Delaunay 752*9a138eb5SPatrick Delaunay len32b = (len + 3U) / 4U; 753*9a138eb5SPatrick Delaunay 754*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE); 755*9a138eb5SPatrick Delaunay 756*9a138eb5SPatrick Delaunay while (((mmio_read_32(reg_offset + OTG_DTXFSTS) & 757*9a138eb5SPatrick Delaunay OTG_DTXFSTS_INEPTFSAV) > len32b) && 758*9a138eb5SPatrick Delaunay (*xfer_count < xfer_len) && (xfer_len != 0U)) { 759*9a138eb5SPatrick Delaunay /* Write the FIFO */ 760*9a138eb5SPatrick Delaunay len = xfer_len - *xfer_count; 761*9a138eb5SPatrick Delaunay 762*9a138eb5SPatrick Delaunay if ((len > 0) && ((uint32_t)len > maxpacket)) { 763*9a138eb5SPatrick Delaunay len = maxpacket; 764*9a138eb5SPatrick Delaunay } 765*9a138eb5SPatrick Delaunay 766*9a138eb5SPatrick Delaunay len32b = (len + 3U) / 4U; 767*9a138eb5SPatrick Delaunay 768*9a138eb5SPatrick Delaunay ret = usb_dwc2_write_packet(handle, *xfer_buff, epnum, len); 769*9a138eb5SPatrick Delaunay if (ret != USBD_OK) { 770*9a138eb5SPatrick Delaunay return ret; 771*9a138eb5SPatrick Delaunay } 772*9a138eb5SPatrick Delaunay 773*9a138eb5SPatrick Delaunay *xfer_buff += len; 774*9a138eb5SPatrick Delaunay *xfer_count += len; 775*9a138eb5SPatrick Delaunay } 776*9a138eb5SPatrick Delaunay 777*9a138eb5SPatrick Delaunay if (len <= 0) { 778*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum)); 779*9a138eb5SPatrick Delaunay } 780*9a138eb5SPatrick Delaunay 781*9a138eb5SPatrick Delaunay return USBD_OK; 782*9a138eb5SPatrick Delaunay } 783*9a138eb5SPatrick Delaunay 784*9a138eb5SPatrick Delaunay /* 785*9a138eb5SPatrick Delaunay * Handle PCD interrupt request. 786*9a138eb5SPatrick Delaunay * handle: PCD handle. 787*9a138eb5SPatrick Delaunay * param: Pointer to information updated by the IT handling. 788*9a138eb5SPatrick Delaunay * return: Action to do after IT handling. 789*9a138eb5SPatrick Delaunay */ 790*9a138eb5SPatrick Delaunay static enum usb_action usb_dwc2_it_handler(void *handle, uint32_t *param) 791*9a138eb5SPatrick Delaunay { 792*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 793*9a138eb5SPatrick Delaunay uint32_t ep_intr; 794*9a138eb5SPatrick Delaunay uint32_t epint; 795*9a138eb5SPatrick Delaunay uint32_t epnum; 796*9a138eb5SPatrick Delaunay uint32_t temp; 797*9a138eb5SPatrick Delaunay enum usb_status ret; 798*9a138eb5SPatrick Delaunay 799*9a138eb5SPatrick Delaunay if (usb_dwc2_get_mode(handle) != USB_OTG_MODE_DEVICE) { 800*9a138eb5SPatrick Delaunay return USB_NOTHING; 801*9a138eb5SPatrick Delaunay } 802*9a138eb5SPatrick Delaunay 803*9a138eb5SPatrick Delaunay /* Avoid spurious interrupt */ 804*9a138eb5SPatrick Delaunay if (usb_dwc2_read_int(handle) == 0U) { 805*9a138eb5SPatrick Delaunay return USB_NOTHING; 806*9a138eb5SPatrick Delaunay } 807*9a138eb5SPatrick Delaunay 808*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_MMIS) != 0U) { 809*9a138eb5SPatrick Delaunay /* Incorrect mode, acknowledge the interrupt */ 810*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_MMIS); 811*9a138eb5SPatrick Delaunay } 812*9a138eb5SPatrick Delaunay 813*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OEPINT) != 0U) { 814*9a138eb5SPatrick Delaunay uint32_t reg_offset; 815*9a138eb5SPatrick Delaunay 816*9a138eb5SPatrick Delaunay /* Read in the device interrupt bits */ 817*9a138eb5SPatrick Delaunay ep_intr = usb_dwc2_all_out_ep_int(handle); 818*9a138eb5SPatrick Delaunay epnum = 0U; 819*9a138eb5SPatrick Delaunay while ((ep_intr & BIT(0)) != BIT(0)) { 820*9a138eb5SPatrick Delaunay epnum++; 821*9a138eb5SPatrick Delaunay ep_intr >>= 1; 822*9a138eb5SPatrick Delaunay } 823*9a138eb5SPatrick Delaunay 824*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DOEP_BASE + (epnum * OTG_DOEP_SIZE) + OTG_DOEPINT; 825*9a138eb5SPatrick Delaunay 826*9a138eb5SPatrick Delaunay epint = usb_dwc2_out_ep_int(handle, epnum); 827*9a138eb5SPatrick Delaunay 828*9a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_XFRC) == OTG_DOEPINT_XFRC) { 829*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_XFRC); 830*9a138eb5SPatrick Delaunay *param = epnum; 831*9a138eb5SPatrick Delaunay 832*9a138eb5SPatrick Delaunay return USB_DATA_OUT; 833*9a138eb5SPatrick Delaunay } 834*9a138eb5SPatrick Delaunay 835*9a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_STUP) == OTG_DOEPINT_STUP) { 836*9a138eb5SPatrick Delaunay /* Inform that a setup packet is available */ 837*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_STUP); 838*9a138eb5SPatrick Delaunay 839*9a138eb5SPatrick Delaunay return USB_SETUP; 840*9a138eb5SPatrick Delaunay } 841*9a138eb5SPatrick Delaunay 842*9a138eb5SPatrick Delaunay if ((epint & OTG_DOEPINT_OTEPDIS) == OTG_DOEPINT_OTEPDIS) { 843*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DOEPINT_OTEPDIS); 844*9a138eb5SPatrick Delaunay } 845*9a138eb5SPatrick Delaunay } 846*9a138eb5SPatrick Delaunay 847*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IEPINT) != 0U) { 848*9a138eb5SPatrick Delaunay uint32_t reg_offset; 849*9a138eb5SPatrick Delaunay 850*9a138eb5SPatrick Delaunay /* Read in the device interrupt bits */ 851*9a138eb5SPatrick Delaunay ep_intr = usb_dwc2_all_in_ep_int(handle); 852*9a138eb5SPatrick Delaunay epnum = 0U; 853*9a138eb5SPatrick Delaunay while ((ep_intr & BIT(0)) != BIT(0)) { 854*9a138eb5SPatrick Delaunay epnum++; 855*9a138eb5SPatrick Delaunay ep_intr >>= 1; 856*9a138eb5SPatrick Delaunay } 857*9a138eb5SPatrick Delaunay 858*9a138eb5SPatrick Delaunay reg_offset = usb_base_addr + OTG_DIEP_BASE + (epnum * OTG_DIEP_SIZE) + OTG_DIEPINT; 859*9a138eb5SPatrick Delaunay 860*9a138eb5SPatrick Delaunay epint = usb_dwc2_in_ep_int(handle, epnum); 861*9a138eb5SPatrick Delaunay 862*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_XFRC) == OTG_DIEPINT_XFRC) { 863*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DIEPEMPMSK, BIT(epnum)); 864*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_XFRC); 865*9a138eb5SPatrick Delaunay *param = epnum; 866*9a138eb5SPatrick Delaunay 867*9a138eb5SPatrick Delaunay return USB_DATA_IN; 868*9a138eb5SPatrick Delaunay } 869*9a138eb5SPatrick Delaunay 870*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_TOC) == OTG_DIEPINT_TOC) { 871*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_TOC); 872*9a138eb5SPatrick Delaunay } 873*9a138eb5SPatrick Delaunay 874*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_ITTXFE) == OTG_DIEPINT_ITTXFE) { 875*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_ITTXFE); 876*9a138eb5SPatrick Delaunay } 877*9a138eb5SPatrick Delaunay 878*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_INEPNE) == OTG_DIEPINT_INEPNE) { 879*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_INEPNE); 880*9a138eb5SPatrick Delaunay } 881*9a138eb5SPatrick Delaunay 882*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_EPDISD) == OTG_DIEPINT_EPDISD) { 883*9a138eb5SPatrick Delaunay mmio_write_32(reg_offset, OTG_DIEPINT_EPDISD); 884*9a138eb5SPatrick Delaunay } 885*9a138eb5SPatrick Delaunay 886*9a138eb5SPatrick Delaunay if ((epint & OTG_DIEPINT_TXFE) == OTG_DIEPINT_TXFE) { 887*9a138eb5SPatrick Delaunay *param = epnum; 888*9a138eb5SPatrick Delaunay 889*9a138eb5SPatrick Delaunay return USB_WRITE_EMPTY; 890*9a138eb5SPatrick Delaunay } 891*9a138eb5SPatrick Delaunay } 892*9a138eb5SPatrick Delaunay 893*9a138eb5SPatrick Delaunay /* Handle resume interrupt */ 894*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_WKUPINT) != 0U) { 895*9a138eb5SPatrick Delaunay INFO("handle USB : Resume\n"); 896*9a138eb5SPatrick Delaunay 897*9a138eb5SPatrick Delaunay /* Clear the remote wake-up signaling */ 898*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG); 899*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_WKUPINT); 900*9a138eb5SPatrick Delaunay 901*9a138eb5SPatrick Delaunay return USB_RESUME; 902*9a138eb5SPatrick Delaunay } 903*9a138eb5SPatrick Delaunay 904*9a138eb5SPatrick Delaunay /* Handle suspend interrupt */ 905*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBSUSP) != 0U) { 906*9a138eb5SPatrick Delaunay INFO("handle USB : Suspend int\n"); 907*9a138eb5SPatrick Delaunay 908*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBSUSP); 909*9a138eb5SPatrick Delaunay 910*9a138eb5SPatrick Delaunay if ((mmio_read_32(usb_base_addr + OTG_DSTS) & 911*9a138eb5SPatrick Delaunay OTG_DSTS_SUSPSTS) == OTG_DSTS_SUSPSTS) { 912*9a138eb5SPatrick Delaunay return USB_SUSPEND; 913*9a138eb5SPatrick Delaunay } 914*9a138eb5SPatrick Delaunay } 915*9a138eb5SPatrick Delaunay 916*9a138eb5SPatrick Delaunay /* Handle LPM interrupt */ 917*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_LPMINT) != 0U) { 918*9a138eb5SPatrick Delaunay INFO("handle USB : LPM int enter in suspend\n"); 919*9a138eb5SPatrick Delaunay 920*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_LPMINT); 921*9a138eb5SPatrick Delaunay *param = (mmio_read_32(usb_base_addr + OTG_GLPMCFG) & 922*9a138eb5SPatrick Delaunay OTG_GLPMCFG_BESL) >> 2; 923*9a138eb5SPatrick Delaunay 924*9a138eb5SPatrick Delaunay return USB_LPM; 925*9a138eb5SPatrick Delaunay } 926*9a138eb5SPatrick Delaunay 927*9a138eb5SPatrick Delaunay /* Handle reset interrupt */ 928*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_USBRST) != 0U) { 929*9a138eb5SPatrick Delaunay INFO("handle USB : Reset\n"); 930*9a138eb5SPatrick Delaunay 931*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_RWUSIG); 932*9a138eb5SPatrick Delaunay 933*9a138eb5SPatrick Delaunay usb_dwc2_flush_tx_fifo(handle, 0U); 934*9a138eb5SPatrick Delaunay 935*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_DAINT, OTG_DAINT_IN_MASK | OTG_DAINT_OUT_MASK); 936*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DAINTMSK, OTG_DAINT_EP0_IN | OTG_DAINT_EP0_OUT); 937*9a138eb5SPatrick Delaunay 938*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DOEPMSK, OTG_DOEPMSK_STUPM | 939*9a138eb5SPatrick Delaunay OTG_DOEPMSK_XFRCM | 940*9a138eb5SPatrick Delaunay OTG_DOEPMSK_EPDM); 941*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_DIEPMSK, OTG_DIEPMSK_TOM | 942*9a138eb5SPatrick Delaunay OTG_DIEPMSK_XFRCM | 943*9a138eb5SPatrick Delaunay OTG_DIEPMSK_EPDM); 944*9a138eb5SPatrick Delaunay 945*9a138eb5SPatrick Delaunay /* Set default address to 0 */ 946*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCFG, OTG_DCFG_DAD); 947*9a138eb5SPatrick Delaunay 948*9a138eb5SPatrick Delaunay /* Setup EP0 to receive SETUP packets */ 949*9a138eb5SPatrick Delaunay ret = usb_dwc2_ep0_out_start(handle); 950*9a138eb5SPatrick Delaunay if (ret != USBD_OK) { 951*9a138eb5SPatrick Delaunay return ret; 952*9a138eb5SPatrick Delaunay } 953*9a138eb5SPatrick Delaunay 954*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_USBRST); 955*9a138eb5SPatrick Delaunay 956*9a138eb5SPatrick Delaunay return USB_RESET; 957*9a138eb5SPatrick Delaunay } 958*9a138eb5SPatrick Delaunay 959*9a138eb5SPatrick Delaunay /* Handle enumeration done interrupt */ 960*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_ENUMDNE) != 0U) { 961*9a138eb5SPatrick Delaunay ret = usb_dwc2_activate_setup(handle); 962*9a138eb5SPatrick Delaunay if (ret != USBD_OK) { 963*9a138eb5SPatrick Delaunay return ret; 964*9a138eb5SPatrick Delaunay } 965*9a138eb5SPatrick Delaunay 966*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GUSBCFG, OTG_GUSBCFG_TRDT); 967*9a138eb5SPatrick Delaunay 968*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GUSBCFG, 969*9a138eb5SPatrick Delaunay (USBD_HS_TRDT_VALUE << OTG_GUSBCFG_TRDT_SHIFT) & OTG_GUSBCFG_TRDT); 970*9a138eb5SPatrick Delaunay 971*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_ENUMDNE); 972*9a138eb5SPatrick Delaunay 973*9a138eb5SPatrick Delaunay return USB_ENUM_DONE; 974*9a138eb5SPatrick Delaunay } 975*9a138eb5SPatrick Delaunay 976*9a138eb5SPatrick Delaunay /* Handle RXQLevel interrupt */ 977*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_RXFLVL) != 0U) { 978*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_GINTMSK, 979*9a138eb5SPatrick Delaunay OTG_GINTSTS_RXFLVL); 980*9a138eb5SPatrick Delaunay 981*9a138eb5SPatrick Delaunay temp = mmio_read_32(usb_base_addr + OTG_GRXSTSP); 982*9a138eb5SPatrick Delaunay 983*9a138eb5SPatrick Delaunay *param = temp & OTG_GRXSTSP_EPNUM; 984*9a138eb5SPatrick Delaunay *param |= (temp & OTG_GRXSTSP_BCNT) << (USBD_OUT_COUNT_SHIFT - 985*9a138eb5SPatrick Delaunay OTG_GRXSTSP_BCNT_SHIFT); 986*9a138eb5SPatrick Delaunay 987*9a138eb5SPatrick Delaunay if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == STS_DATA_UPDT) { 988*9a138eb5SPatrick Delaunay if ((temp & OTG_GRXSTSP_BCNT) != 0U) { 989*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 990*9a138eb5SPatrick Delaunay 991*9a138eb5SPatrick Delaunay return USB_READ_DATA_PACKET; 992*9a138eb5SPatrick Delaunay } 993*9a138eb5SPatrick Delaunay } else if (((temp & OTG_GRXSTSP_PKTSTS) >> OTG_GRXSTSP_PKTSTS_SHIFT) == 994*9a138eb5SPatrick Delaunay STS_SETUP_UPDT) { 995*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 996*9a138eb5SPatrick Delaunay 997*9a138eb5SPatrick Delaunay return USB_READ_SETUP_PACKET; 998*9a138eb5SPatrick Delaunay } 999*9a138eb5SPatrick Delaunay 1000*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GINTMSK, OTG_GINTSTS_RXFLVL); 1001*9a138eb5SPatrick Delaunay } 1002*9a138eb5SPatrick Delaunay 1003*9a138eb5SPatrick Delaunay /* Handle SOF interrupt */ 1004*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SOF) != 0U) { 1005*9a138eb5SPatrick Delaunay INFO("handle USB : SOF\n"); 1006*9a138eb5SPatrick Delaunay 1007*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SOF); 1008*9a138eb5SPatrick Delaunay 1009*9a138eb5SPatrick Delaunay return USB_SOF; 1010*9a138eb5SPatrick Delaunay } 1011*9a138eb5SPatrick Delaunay 1012*9a138eb5SPatrick Delaunay /* Handle incomplete ISO IN interrupt */ 1013*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IISOIXFR) != 0U) { 1014*9a138eb5SPatrick Delaunay INFO("handle USB : ISO IN\n"); 1015*9a138eb5SPatrick Delaunay 1016*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, 1017*9a138eb5SPatrick Delaunay OTG_GINTSTS_IISOIXFR); 1018*9a138eb5SPatrick Delaunay } 1019*9a138eb5SPatrick Delaunay 1020*9a138eb5SPatrick Delaunay /* Handle incomplete ISO OUT interrupt */ 1021*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_IPXFR_INCOMPISOOUT) != 1022*9a138eb5SPatrick Delaunay 0U) { 1023*9a138eb5SPatrick Delaunay INFO("handle USB : ISO OUT\n"); 1024*9a138eb5SPatrick Delaunay 1025*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, 1026*9a138eb5SPatrick Delaunay OTG_GINTSTS_IPXFR_INCOMPISOOUT); 1027*9a138eb5SPatrick Delaunay } 1028*9a138eb5SPatrick Delaunay 1029*9a138eb5SPatrick Delaunay /* Handle connection event interrupt */ 1030*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_SRQINT) != 0U) { 1031*9a138eb5SPatrick Delaunay INFO("handle USB : Connect\n"); 1032*9a138eb5SPatrick Delaunay 1033*9a138eb5SPatrick Delaunay mmio_write_32(usb_base_addr + OTG_GINTSTS, OTG_GINTSTS_SRQINT); 1034*9a138eb5SPatrick Delaunay } 1035*9a138eb5SPatrick Delaunay 1036*9a138eb5SPatrick Delaunay /* Handle disconnection event interrupt */ 1037*9a138eb5SPatrick Delaunay if ((usb_dwc2_read_int(handle) & OTG_GINTSTS_OTGINT) != 0U) { 1038*9a138eb5SPatrick Delaunay INFO("handle USB : Disconnect\n"); 1039*9a138eb5SPatrick Delaunay 1040*9a138eb5SPatrick Delaunay temp = mmio_read_32(usb_base_addr + OTG_GOTGINT); 1041*9a138eb5SPatrick Delaunay 1042*9a138eb5SPatrick Delaunay if ((temp & OTG_GOTGINT_SEDET) == OTG_GOTGINT_SEDET) { 1043*9a138eb5SPatrick Delaunay return USB_DISCONNECT; 1044*9a138eb5SPatrick Delaunay } 1045*9a138eb5SPatrick Delaunay } 1046*9a138eb5SPatrick Delaunay 1047*9a138eb5SPatrick Delaunay return USB_NOTHING; 1048*9a138eb5SPatrick Delaunay } 1049*9a138eb5SPatrick Delaunay 1050*9a138eb5SPatrick Delaunay /* 1051*9a138eb5SPatrick Delaunay * Start the usb device mode 1052*9a138eb5SPatrick Delaunay * usb_core_handle: USB core driver handle. 1053*9a138eb5SPatrick Delaunay * return USB status. 1054*9a138eb5SPatrick Delaunay */ 1055*9a138eb5SPatrick Delaunay static enum usb_status usb_dwc2_start_device(void *handle) 1056*9a138eb5SPatrick Delaunay { 1057*9a138eb5SPatrick Delaunay uintptr_t usb_base_addr = (uintptr_t)handle; 1058*9a138eb5SPatrick Delaunay 1059*9a138eb5SPatrick Delaunay mmio_clrbits_32(usb_base_addr + OTG_DCTL, OTG_DCTL_SDIS); 1060*9a138eb5SPatrick Delaunay mmio_setbits_32(usb_base_addr + OTG_GAHBCFG, OTG_GAHBCFG_GINT); 1061*9a138eb5SPatrick Delaunay 1062*9a138eb5SPatrick Delaunay return USBD_OK; 1063*9a138eb5SPatrick Delaunay } 1064*9a138eb5SPatrick Delaunay 1065*9a138eb5SPatrick Delaunay static const struct usb_driver usb_dwc2driver = { 1066*9a138eb5SPatrick Delaunay .ep0_out_start = usb_dwc2_ep0_out_start, 1067*9a138eb5SPatrick Delaunay .ep_start_xfer = usb_dwc2_ep_start_xfer, 1068*9a138eb5SPatrick Delaunay .ep0_start_xfer = usb_dwc2_ep0_start_xfer, 1069*9a138eb5SPatrick Delaunay .write_packet = usb_dwc2_write_packet, 1070*9a138eb5SPatrick Delaunay .read_packet = usb_dwc2_read_packet, 1071*9a138eb5SPatrick Delaunay .ep_set_stall = usb_dwc2_ep_set_stall, 1072*9a138eb5SPatrick Delaunay .start_device = usb_dwc2_start_device, 1073*9a138eb5SPatrick Delaunay .stop_device = usb_dwc2_stop_device, 1074*9a138eb5SPatrick Delaunay .set_address = usb_dwc2_set_address, 1075*9a138eb5SPatrick Delaunay .write_empty_tx_fifo = usb_dwc2_write_empty_tx_fifo, 1076*9a138eb5SPatrick Delaunay .it_handler = usb_dwc2_it_handler 1077*9a138eb5SPatrick Delaunay }; 1078*9a138eb5SPatrick Delaunay 1079*9a138eb5SPatrick Delaunay /* 1080*9a138eb5SPatrick Delaunay * Initialize USB DWC2 driver. 1081*9a138eb5SPatrick Delaunay * usb_core_handle: USB core driver handle. 1082*9a138eb5SPatrick Delaunay * pcd_handle: PCD handle. 1083*9a138eb5SPatrick Delaunay * base_register: USB global register base address. 1084*9a138eb5SPatrick Delaunay */ 1085*9a138eb5SPatrick Delaunay void stm32mp1_usb_init_driver(struct usb_handle *usb_core_handle, 1086*9a138eb5SPatrick Delaunay struct pcd_handle *pcd_handle, 1087*9a138eb5SPatrick Delaunay void *base_register) 1088*9a138eb5SPatrick Delaunay { 1089*9a138eb5SPatrick Delaunay register_usb_driver(usb_core_handle, pcd_handle, &usb_dwc2driver, 1090*9a138eb5SPatrick Delaunay base_register); 1091*9a138eb5SPatrick Delaunay } 1092