Open FFBoard
Open source force feedback firmware
dwc2_stm32.h
Go to the documentation of this file.
1/*
2 * The MIT License (MIT)
3 *
4 * Copyright (c) 2021, Ha Thach (tinyusb.org)
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 *
24 * This file is part of the TinyUSB stack.
25 */
26
27#ifndef DWC2_STM32_H_
28#define DWC2_STM32_H_
29
30#ifdef __cplusplus
31extern "C" {
32#endif
33
34// EP_MAX : Max number of bi-directional endpoints including EP0
35// EP_FIFO_SIZE : Size of dedicated USB SRAM
36#if CFG_TUSB_MCU == OPT_MCU_STM32F1
37 #include "stm32f1xx.h"
38 #define EP_MAX_FS 4
39 #define EP_FIFO_SIZE_FS 1280
40
41#elif CFG_TUSB_MCU == OPT_MCU_STM32F2
42 #include "stm32f2xx.h"
43 #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
44 #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
45
46 #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
47 #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
48
49#elif CFG_TUSB_MCU == OPT_MCU_STM32F4
50 #include "stm32f4xx.h"
51 #define EP_MAX_FS USB_OTG_FS_MAX_IN_ENDPOINTS
52 #define EP_FIFO_SIZE_FS USB_OTG_FS_TOTAL_FIFO_SIZE
53
54 #define EP_MAX_HS USB_OTG_HS_MAX_IN_ENDPOINTS
55 #define EP_FIFO_SIZE_HS USB_OTG_HS_TOTAL_FIFO_SIZE
56
57#elif CFG_TUSB_MCU == OPT_MCU_STM32H7
58 #include "stm32h7xx.h"
59 #define EP_MAX_FS 9
60 #define EP_FIFO_SIZE_FS 4096
61
62 #define EP_MAX_HS 9
63 #define EP_FIFO_SIZE_HS 4096
64
65 // NOTE: H7 with only 1 USB port: H72x / H73x / H7Ax / H7Bx
66 // USB_OTG_FS_PERIPH_BASE and OTG_FS_IRQn not defined
67 #if (! defined USB2_OTG_FS)
68 #define USB_OTG_FS_PERIPH_BASE USB1_OTG_HS_PERIPH_BASE
69 #define OTG_FS_IRQn OTG_HS_IRQn
70 #endif
71
72#elif CFG_TUSB_MCU == OPT_MCU_STM32H7RS
73 #include "stm32h7rsxx.h"
74 #define EP_MAX_FS 6
75 #define EP_FIFO_SIZE_FS 1280
76
77 #define EP_MAX_HS 9
78 #define EP_FIFO_SIZE_HS 4096
79
80#elif CFG_TUSB_MCU == OPT_MCU_STM32F7
81 #include "stm32f7xx.h"
82 #define EP_MAX_FS 6
83 #define EP_FIFO_SIZE_FS 1280
84
85 #define EP_MAX_HS 9
86 #define EP_FIFO_SIZE_HS 4096
87
88#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
89 #include "stm32l4xx.h"
90 #define EP_MAX_FS 6
91 #define EP_FIFO_SIZE_FS 1280
92
93#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
94 #include "stm32u5xx.h"
95 // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
96 #ifdef USB_OTG_FS
97 #define USB_OTG_FS_PERIPH_BASE USB_OTG_FS_BASE
98 #define EP_MAX_FS 6
99 #define EP_FIFO_SIZE_FS 1280
100 #else
101 #define USB_OTG_HS_PERIPH_BASE USB_OTG_HS_BASE
102 #define EP_MAX_HS 9
103 #define EP_FIFO_SIZE_HS 4096
104 #endif
105#else
106 #error "Unsupported MCUs"
107#endif
108
109// OTG HS always has higher number of endpoints than FS
110#ifdef USB_OTG_HS_PERIPH_BASE
111 #define DWC2_EP_MAX EP_MAX_HS
112#else
113 #define DWC2_EP_MAX EP_MAX_FS
114#endif
115
116// On STM32 for consistency we associate
117// - Port0 to OTG_FS, and Port1 to OTG_HS
118static const dwc2_controller_t _dwc2_controller[] = {
119 #ifdef USB_OTG_FS_PERIPH_BASE
120 { .reg_base = USB_OTG_FS_PERIPH_BASE, .irqnum = OTG_FS_IRQn, .ep_count = EP_MAX_FS, .ep_fifo_size = EP_FIFO_SIZE_FS },
121 #endif
122
123 #ifdef USB_OTG_HS_PERIPH_BASE
124 { .reg_base = USB_OTG_HS_PERIPH_BASE, .irqnum = OTG_HS_IRQn, .ep_count = EP_MAX_HS, .ep_fifo_size = EP_FIFO_SIZE_HS },
125 #endif
126};
127
128//--------------------------------------------------------------------+
129//
130//--------------------------------------------------------------------+
131
132// SystemCoreClock is already included by family header
133// extern uint32_t SystemCoreClock;
134
135TU_ATTR_ALWAYS_INLINE static inline void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled) {
136 (void) role;
137 const IRQn_Type irqn = (IRQn_Type) _dwc2_controller[rhport].irqnum;
138 if (enabled) {
139 NVIC_EnableIRQ(irqn);
140 } else {
141 NVIC_DisableIRQ(irqn);
142 }
143}
144
145#define dwc2_dcd_int_enable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, true)
146#define dwc2_dcd_int_disable(_rhport) dwc2_int_set(_rhport, TUSB_ROLE_DEVICE, false)
147
148
149TU_ATTR_ALWAYS_INLINE static inline void dwc2_remote_wakeup_delay(void) {
150 // try to delay for 1 ms
151 uint32_t count = SystemCoreClock / 1000;
152 while (count--) __NOP();
153}
154
155// MCU specific PHY init, called BEFORE core reset
156// - dwc2 3.30a (H5) use USB_HS_PHYC
157// - dwc2 4.11a (U5) use femtoPHY
158static inline void dwc2_phy_init(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
159 if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
160 // Enable on-chip FS PHY
161 dwc2->stm32_gccfg |= STM32_GCCFG_PWRDWN;
162
163 // https://community.st.com/t5/stm32cubemx-mcus/why-stm32h743-usb-fs-doesn-t-work-if-freertos-tickless-idle/m-p/349480#M18867
164 // H7 running on full-speed phy need to disable ULPI clock in sleep mode.
165 // Otherwise, USB won't work when mcu executing WFI/WFE instruction i.e tick-less RTOS.
166 // Note: there may be other family that is affected by this, but only H7 and F7 is tested so far
167 #if defined(USB_OTG_FS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB2OTGFSULPILPEN)
168 if ( USB_OTG_FS_PERIPH_BASE == (uint32_t) dwc2 ) {
169 RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB2OTGFSULPILPEN;
170 }
171 #endif
172
173 #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_USB1OTGHSULPILPEN)
174 if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) {
175 RCC->AHB1LPENR &= ~RCC_AHB1LPENR_USB1OTGHSULPILPEN;
176 }
177 #endif
178
179 #if defined(USB_OTG_HS_PERIPH_BASE) && defined(RCC_AHB1LPENR_OTGHSULPILPEN)
180 if ( USB_OTG_HS_PERIPH_BASE == (uint32_t) dwc2 ) {
181 RCC->AHB1LPENR &= ~RCC_AHB1LPENR_OTGHSULPILPEN;
182 }
183 #endif
184
185 } else {
186#if CFG_TUSB_MCU != OPT_MCU_STM32U5
187 // Disable FS PHY, TODO on U5A5 (dwc2 4.11a) 16th bit is 'Host CDP behavior enable'
188 dwc2->stm32_gccfg &= ~STM32_GCCFG_PWRDWN;
189#endif
190
191 // Enable on-chip HS PHY
192 if (hs_phy_type == GHWCFG2_HSPHY_UTMI || hs_phy_type == GHWCFG2_HSPHY_UTMI_ULPI) {
193 #ifdef USB_HS_PHYC
194 // Enable UTMI HS PHY
195 dwc2->stm32_gccfg |= STM32_GCCFG_PHYHSEN;
196
197 // Enable LDO
198 USB_HS_PHYC->USB_HS_PHYC_LDO |= USB_HS_PHYC_LDO_ENABLE;
199
200 // Wait until LDO ready
201 while ( 0 == (USB_HS_PHYC->USB_HS_PHYC_LDO & USB_HS_PHYC_LDO_STATUS) ) {}
202
203 uint32_t phyc_pll = 0;
204
205 // TODO Try to get HSE_VALUE from registers instead of depending CFLAGS
206 switch ( HSE_VALUE )
207 {
208 case 12000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12MHZ ; break;
209 case 12500000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_12_5MHZ ; break;
210 case 16000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_16MHZ ; break;
211 case 24000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_24MHZ ; break;
212 case 25000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_25MHZ ; break;
213 case 32000000: phyc_pll = USB_HS_PHYC_PLL1_PLLSEL_Msk ; break; // Value not defined in header
214 default:
215 TU_ASSERT(false, );
216 }
217 USB_HS_PHYC->USB_HS_PHYC_PLL = phyc_pll;
218
219 // Control the tuning interface of the High Speed PHY
220 // Use magic value (USB_HS_PHYC_TUNE_VALUE) from ST driver for F7
221 USB_HS_PHYC->USB_HS_PHYC_TUNE |= 0x00000F13U;
222
223 // Enable PLL internal PHY
224 USB_HS_PHYC->USB_HS_PHYC_PLL |= USB_HS_PHYC_PLL_PLLEN;
225 #else
226
227 #endif
228 }
229 }
230}
231
232// MCU specific PHY update, it is called AFTER init() and core reset
233static inline void dwc2_phy_update(dwc2_regs_t* dwc2, uint8_t hs_phy_type) {
234 // used to set turnaround time for fullspeed, nothing to do in highspeed mode
235 if (hs_phy_type == GHWCFG2_HSPHY_NOT_SUPPORTED) {
236 // Turnaround timeout depends on the AHB clock dictated by STM32 Reference Manual
237 uint32_t turnaround;
238
239 if (SystemCoreClock >= 32000000u) {
240 turnaround = 0x6u;
241 } else if (SystemCoreClock >= 27500000u) {
242 turnaround = 0x7u;
243 } else if (SystemCoreClock >= 24000000u) {
244 turnaround = 0x8u;
245 } else if (SystemCoreClock >= 21800000u) {
246 turnaround = 0x9u;
247 }
248 else if (SystemCoreClock >= 20000000u) {
249 turnaround = 0xAu;
250 }
251 else if (SystemCoreClock >= 18500000u) {
252 turnaround = 0xBu;
253 }
254 else if (SystemCoreClock >= 17200000u) {
255 turnaround = 0xCu;
256 }
257 else if (SystemCoreClock >= 16000000u) {
258 turnaround = 0xDu;
259 }
260 else if (SystemCoreClock >= 15000000u) {
261 turnaround = 0xEu;
262 }
263 else {
264 turnaround = 0xFu;
265 }
266
267 dwc2->gusbcfg = (dwc2->gusbcfg & ~GUSBCFG_TRDT_Msk) | (turnaround << GUSBCFG_TRDT_Pos);
268 }
269}
270
271#ifdef __cplusplus
272}
273#endif
274
275#endif
u32 SystemCoreClock
static TU_ATTR_ALWAYS_INLINE void dwc2_int_set(uint8_t rhport, tusb_role_t role, bool enabled)
Definition: dwc2_stm32.h:135
static const dwc2_controller_t _dwc2_controller[]
Definition: dwc2_stm32.h:118
static TU_ATTR_ALWAYS_INLINE void dwc2_remote_wakeup_delay(void)
Definition: dwc2_stm32.h:149
static void dwc2_phy_init(dwc2_regs_t *dwc2, uint8_t hs_phy_type)
Definition: dwc2_stm32.h:158
static void dwc2_phy_update(dwc2_regs_t *dwc2, uint8_t hs_phy_type)
Definition: dwc2_stm32.h:233
@ GHWCFG2_HSPHY_UTMI
Definition: dwc2_type.h:111
@ GHWCFG2_HSPHY_NOT_SUPPORTED
Definition: dwc2_type.h:110
@ GHWCFG2_HSPHY_UTMI_ULPI
Definition: dwc2_type.h:113
volatile uint32_t stm32_gccfg
Definition: dwc2_type.h:581
volatile uint32_t gusbcfg
Definition: dwc2_type.h:553