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