• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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