1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 /*---------------------------------------------------------------------
9 * Include
10 *---------------------------------------------------------------------
11 */
12 #include "hpm_usb_drv.h"
13 #include "hpm_misc.h"
14 #include "hpm_soc_feature.h"
15 #include "hpm_common.h"
16 /*---------------------------------------------------------------------
17 * Macro Enum Declaration
18 *---------------------------------------------------------------------
19 */
20
21 /* ENDPTCTRL */
22 enum {
23 ENDPTCTRL_STALL = HPM_BITSMASK(1, 0),
24 ENDPTCTRL_TYPE = HPM_BITSMASK(3, 2),
25 ENDPTCTRL_TOGGLE_INHIBIT = HPM_BITSMASK(1, 5),
26 ENDPTCTRL_TOGGLE_RESET = HPM_BITSMASK(1, 6),
27 ENDPTCTRL_ENABLE = HPM_BITSMASK(1, 7),
28 };
29
30 /*---------------------------------------------------------------------
31 * Internal API
32 *---------------------------------------------------------------------
33 */
34
35 /* De-initialize USB phy */
usb_phy_deinit(USB_Type * ptr)36 static void usb_phy_deinit(USB_Type *ptr)
37 {
38 ptr->OTG_CTRL0 |= USB_OTG_CTRL0_OTG_UTMI_SUSPENDM_SW_MASK; /* set otg_utmi_suspend_m for naneng usbphy */
39
40 ptr->OTG_CTRL0 &= ~USB_OTG_CTRL0_OTG_UTMI_RESET_SW_MASK; /* clear otg_utmi_reset_sw for naneng usbphy */
41
42 ptr->PHY_CTRL1 &= ~USB_PHY_CTRL1_UTMI_CFG_RST_N_MASK; /* clear cfg_rst_n */
43
44 ptr->PHY_CTRL1 &= ~USB_PHY_CTRL1_UTMI_OTG_SUSPENDM_MASK; /* clear otg_suspendm */
45 }
46
usb_phy_get_line_state(USB_Type * ptr)47 static uint8_t usb_phy_get_line_state(USB_Type *ptr)
48 {
49 return USB_PHY_STATUS_LINE_STATE_GET(ptr->PHY_STATUS);
50 }
51
52 /*---------------------------------------------------------------------
53 * Driver API
54 *---------------------------------------------------------------------
55 */
56 /* Initialize USB phy */
usb_phy_init(USB_Type * ptr)57 void usb_phy_init(USB_Type *ptr)
58 {
59 uint32_t status;
60
61 usb_phy_enable_dp_dm_pulldown(ptr);
62 ptr->OTG_CTRL0 |= USB_OTG_CTRL0_OTG_UTMI_RESET_SW_MASK; /* set otg_utmi_reset_sw for naneng usbphy */
63 ptr->OTG_CTRL0 &= ~USB_OTG_CTRL0_OTG_UTMI_SUSPENDM_SW_MASK; /* clr otg_utmi_suspend_m for naneng usbphy */
64 ptr->PHY_CTRL1 &= ~USB_PHY_CTRL1_UTMI_CFG_RST_N_MASK; /* clr cfg_rst_n */
65
66 do {
67 status = USB_OTG_CTRL0_OTG_UTMI_RESET_SW_GET(ptr->OTG_CTRL0); /* wait for reset status */
68 } while (status == 0);
69
70 ptr->OTG_CTRL0 |= USB_OTG_CTRL0_OTG_UTMI_SUSPENDM_SW_MASK; /* set otg_utmi_suspend_m for naneng usbphy */
71
72 for (volatile uint32_t i = 0; i < USB_PHY_INIT_DELAY_COUNT; i++) {
73 (void)ptr->PHY_CTRL1; /* used for delay */
74 }
75
76 ptr->OTG_CTRL0 &= ~USB_OTG_CTRL0_OTG_UTMI_RESET_SW_MASK; /* clear otg_utmi_reset_sw for naneng usbphy */
77
78 /* otg utmi clock detection */
79 ptr->PHY_STATUS |= USB_PHY_STATUS_UTMI_CLK_VALID_MASK; /* write 1 to clear valid status */
80 do {
81 status = USB_PHY_STATUS_UTMI_CLK_VALID_GET(ptr->PHY_STATUS); /* get utmi clock status */
82 } while (status == 0);
83
84 ptr->PHY_CTRL1 |= USB_PHY_CTRL1_UTMI_CFG_RST_N_MASK; /* set cfg_rst_n */
85
86 ptr->PHY_CTRL1 |= USB_PHY_CTRL1_UTMI_OTG_SUSPENDM_MASK; /* set otg_suspendm */
87 }
88
usb_dcd_bus_reset(USB_Type * ptr,uint16_t ep0_max_packet_size)89 void usb_dcd_bus_reset(USB_Type *ptr, uint16_t ep0_max_packet_size)
90 {
91 (void) ep0_max_packet_size;
92 /* The reset value for all endpoint types is the control endpoint. If one endpoint
93 * direction is enabled and the paired endpoint of opposite direction is disabled, then the
94 * endpoint type of the unused direction must be changed from the control type to any other
95 * type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior
96 * for the data PID tracking on the active endpoint.
97 */
98
99 for (uint32_t i = 1; i < USB_SOC_DCD_MAX_ENDPOINT_COUNT; i++) {
100 ptr->ENDPTCTRL[i] = USB_ENDPTCTRL_TXT_SET(usb_xfer_bulk) | USB_ENDPTCTRL_RXT_SET(usb_xfer_bulk);
101 }
102
103 /* Clear All Registers */
104 ptr->ENDPTNAK = ptr->ENDPTNAK;
105 ptr->ENDPTNAKEN = 0;
106 ptr->USBSTS = ptr->USBSTS;
107 ptr->ENDPTSETUPSTAT = ptr->ENDPTSETUPSTAT;
108 ptr->ENDPTCOMPLETE = ptr->ENDPTCOMPLETE;
109
110 while (ptr->ENDPTPRIME) {
111 }
112 ptr->ENDPTFLUSH = 0xFFFFFFFF;
113 while (ptr->ENDPTFLUSH) {
114 }
115 }
116
usb_dcd_init(USB_Type * ptr)117 void usb_dcd_init(USB_Type *ptr)
118 {
119 /* Initialize USB phy */
120 usb_phy_init(ptr);
121
122 /* Reset controller */
123 ptr->USBCMD |= USB_USBCMD_RST_MASK;
124 while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
125 }
126
127 /* Set mode to device, must be set immediately after reset */
128 ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
129 ptr->USBMODE |= USB_USBMODE_CM_SET(2);
130
131 /* Disable setup lockout, please refer to "Control Endpoint Operation" section in RM. */
132 ptr->USBMODE &= ~USB_USBMODE_SLOM_MASK;
133
134 /* Set the endian */
135 ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
136
137 /* TODO Force fullspeed on non-highspeed port */
138 /* ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK; */
139
140 /* Set parallel interface signal */
141 ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
142
143 /* Set parallel transceiver width */
144 ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
145
146 #ifdef CONFIG_USB_DEVICE_FS
147 /* Set usb forced to full speed mode */
148 ptr->PORTSC1 |= USB_PORTSC1_PFSC_MASK;
149 #endif
150
151 /* Not use interrupt threshold. */
152 ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
153
154 /* Enable VBUS discharge */
155 ptr->OTGSC |= USB_OTGSC_VD_MASK;
156 }
157
usb_dcd_deinit(USB_Type * ptr)158 void usb_dcd_deinit(USB_Type *ptr)
159 {
160 /* Stop */
161 ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
162
163 /* Reset controller */
164 ptr->USBCMD |= USB_USBCMD_RST_MASK;
165 while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
166 }
167
168 /* De-initialize USB phy */
169 usb_phy_deinit(ptr);
170
171 /* Reset endpoint list address register */
172 ptr->ENDPTLISTADDR = 0;
173
174 /* Reset status register */
175 ptr->USBSTS = ptr->USBSTS;
176
177 /* Reset interrupt enable register */
178 ptr->USBINTR = 0;
179 }
180
181 /* Connect by enabling internal pull-up resistor on D+/D- */
usb_dcd_connect(USB_Type * ptr)182 void usb_dcd_connect(USB_Type *ptr)
183 {
184 ptr->USBCMD |= USB_USBCMD_RS_MASK;
185 }
186
187 /* Disconnect by disabling internal pull-up resistor on D+/D- */
usb_dcd_disconnect(USB_Type * ptr)188 void usb_dcd_disconnect(USB_Type *ptr)
189 {
190 /* Stop */
191 ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
192
193 /* Pullup DP to make the phy switch into full speed mode */
194 ptr->USBCMD |= USB_USBCMD_RS_MASK;
195
196 /* Clear the sof flag */
197 ptr->USBSTS |= USB_USBSTS_SRI_MASK;
198
199 /* Wait a SOF (It will not be a dead loop even usb cable is not connected.) */
200 while (USB_USBSTS_SRI_GET(ptr->USBSTS) == 0) {
201 }
202
203 /* Disconnect */
204 ptr->USBCMD &= ~USB_USBCMD_RS_MASK;
205 }
206
207 /*---------------------------------------------------------------------
208 * Endpoint API
209 *---------------------------------------------------------------------
210 */
usb_dcd_edpt_open(USB_Type * ptr,usb_endpoint_config_t * config)211 void usb_dcd_edpt_open(USB_Type *ptr, usb_endpoint_config_t *config)
212 {
213 uint8_t const epnum = config->ep_addr & 0x0f;
214 uint8_t const dir = (config->ep_addr & 0x80) >> 7;
215
216 /* Enable EP Control */
217 uint32_t temp = ptr->ENDPTCTRL[epnum];
218 temp &= ~((0x03 << 2) << (dir ? 16 : 0));
219 temp |= ((config->xfer << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0);
220 ptr->ENDPTCTRL[epnum] = temp;
221 }
222
usb_dcd_edpt_get_type(USB_Type * ptr,uint8_t ep_addr)223 uint8_t usb_dcd_edpt_get_type(USB_Type *ptr, uint8_t ep_addr)
224 {
225 uint8_t const epnum = ep_addr & 0x0f;
226 uint8_t const dir = (ep_addr & 0x80) >> 7;
227 uint32_t temp = ptr->ENDPTCTRL[epnum];
228
229 return dir ? USB_ENDPTCTRL_TXT_GET(temp) : USB_ENDPTCTRL_RXT_GET(temp);
230 }
231
usb_dcd_edpt_xfer(USB_Type * ptr,uint8_t ep_idx)232 void usb_dcd_edpt_xfer(USB_Type *ptr, uint8_t ep_idx)
233 {
234 uint32_t offset = ep_idx / 2 + ((ep_idx % 2) ? 16 : 0);
235
236 /* Start transfer */
237 ptr->ENDPTPRIME = 1 << offset;
238 }
239
usb_dcd_edpt_stall(USB_Type * ptr,uint8_t ep_addr)240 void usb_dcd_edpt_stall(USB_Type *ptr, uint8_t ep_addr)
241 {
242 uint8_t const epnum = ep_addr & 0x0f;
243 uint8_t const dir = (ep_addr & 0x80) >> 7;
244
245 ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0);
246 }
247
usb_dcd_edpt_clear_stall(USB_Type * ptr,uint8_t ep_addr)248 void usb_dcd_edpt_clear_stall(USB_Type *ptr, uint8_t ep_addr)
249 {
250 uint8_t const epnum = ep_addr & 0x0f;
251 uint8_t const dir = (ep_addr & 0x80) >> 7;
252
253 /* data toggle also need to be reset */
254 ptr->ENDPTCTRL[epnum] |= ENDPTCTRL_TOGGLE_RESET << (dir ? 16 : 0);
255 ptr->ENDPTCTRL[epnum] &= ~(ENDPTCTRL_STALL << (dir ? 16 : 0));
256 }
257
usb_dcd_edpt_check_stall(USB_Type * ptr,uint8_t ep_addr)258 bool usb_dcd_edpt_check_stall(USB_Type *ptr, uint8_t ep_addr)
259 {
260 uint8_t const epnum = ep_addr & 0x0f;
261 uint8_t const dir = (ep_addr & 0x80) >> 7;
262
263 return (ptr->ENDPTCTRL[epnum] & (ENDPTCTRL_STALL << (dir ? 16 : 0))) ? true : false;
264 }
265
usb_dcd_edpt_close(USB_Type * ptr,uint8_t ep_addr)266 void usb_dcd_edpt_close(USB_Type *ptr, uint8_t ep_addr)
267 {
268 uint8_t const epnum = ep_addr & 0x0f;
269 uint8_t const dir = (ep_addr & 0x80) >> 7;
270
271 uint32_t primebit = HPM_BITSMASK(1, epnum) << (dir ? 16 : 0);
272
273 /* Flush the endpoint to stop a transfer. */
274 do {
275 /* Set the corresponding bit(s) in the ENDPTFLUSH register */
276 ptr->ENDPTFLUSH |= primebit;
277
278 /* Wait until all bits in the ENDPTFLUSH register are cleared. */
279 while (0U != (ptr->ENDPTFLUSH & primebit)) {
280 }
281 /*
282 * Read the ENDPTSTAT register to ensure that for all endpoints
283 * commanded to be flushed, that the corresponding bits
284 * are now cleared.
285 */
286 } while (0U != (ptr->ENDPTSTAT & primebit));
287
288 /* Disable the endpoint */
289 ptr->ENDPTCTRL[epnum] &= ~((ENDPTCTRL_TYPE | ENDPTCTRL_ENABLE | ENDPTCTRL_STALL) << (dir ? 16 : 0));
290 ptr->ENDPTCTRL[epnum] |= (usb_xfer_bulk << 2) << (dir ? 16 : 0);
291 }
292
usb_dcd_remote_wakeup(USB_Type * ptr)293 void usb_dcd_remote_wakeup(USB_Type *ptr)
294 {
295 (void) ptr;
296 }
297
usb_hcd_init(USB_Type * ptr,uint32_t int_mask,uint16_t framelist_size)298 bool usb_hcd_init(USB_Type *ptr, uint32_t int_mask, uint16_t framelist_size)
299 {
300 uint8_t framelist_size_bf = 0;
301
302 if (framelist_size > USB_SOC_HCD_FRAMELIST_MAX_ELEMENTS || framelist_size == 0) {
303 return false;
304 }
305
306 framelist_size_bf = 10 - get_first_set_bit_from_lsb(framelist_size);
307
308 if (framelist_size != (1 << get_first_set_bit_from_lsb(framelist_size))) {
309 return false;
310 }
311
312 usb_phy_init(ptr);
313
314 /* Reset controller */
315 ptr->USBCMD |= USB_USBCMD_RST_MASK;
316 while (USB_USBCMD_RST_GET(ptr->USBCMD)) {
317 }
318
319 /* Set mode to host, must be set immediately after reset */
320 ptr->USBMODE &= ~USB_USBMODE_CM_MASK;
321 ptr->USBMODE |= USB_USBMODE_CM_SET(usb_ctrl_mode_host);
322
323 /* Set the endian */
324 ptr->USBMODE &= ~USB_USBMODE_ES_MASK;
325
326 /* Set parallel interface signal */
327 ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
328
329 /* Set parallel transceiver width */
330 ptr->PORTSC1 &= ~USB_PORTSC1_PTW_MASK;
331
332 /* Not use interrupt threshold. */
333 ptr->USBCMD &= ~USB_USBCMD_ITC_MASK;
334
335 /* USB INT Register */
336 ptr->USBSTS = ptr->USBSTS;
337 ptr->USBINTR |= int_mask;
338
339 /* USB CMD Register */
340 ptr->USBCMD = USB_USBCMD_ASE_MASK | USB_USBCMD_PSE_MASK
341 | USB_USBCMD_FS_2_SET(framelist_size_bf >> 2)
342 | USB_USBCMD_FS_1_SET(framelist_size_bf);
343
344 return true;
345 }
346
usb_hcd_port_reset(USB_Type * ptr)347 void usb_hcd_port_reset(USB_Type *ptr)
348 {
349 if (usb_phy_get_line_state(ptr) == usb_line_state2) {
350 ptr->PORTSC1 |= USB_PORTSC1_STS_MASK;
351 } else {
352 ptr->PORTSC1 &= ~USB_PORTSC1_STS_MASK;
353 }
354
355 ptr->PORTSC1 &= ~USB_PORTSC1_PE_MASK;
356 ptr->PORTSC1 |= USB_PORTSC1_PR_MASK;
357
358 /* wait until port reset sequence is completed */
359 while (USB_PORTSC1_PR_GET(ptr->PORTSC1)) {
360 }
361 }
362