• 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_device.h"
13 #include "hpm_misc.h"
14 #include "hpm_common.h"
15 
16 /* Initialize qtd */
usb_qtd_init(dcd_qtd_t * p_qtd,void * data_ptr,uint16_t total_bytes)17 static void usb_qtd_init(dcd_qtd_t *p_qtd, void *data_ptr, uint16_t total_bytes)
18 {
19     memset(p_qtd, 0, sizeof(dcd_qtd_t));
20 
21     p_qtd->next        = USB_SOC_DCD_QTD_NEXT_INVALID;
22     p_qtd->active      = 1;
23     p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes;
24 
25     if (data_ptr != NULL) {
26         p_qtd->buffer[0]   = (uint32_t)data_ptr;
27         for (uint8_t i = 1; i < USB_SOC_DCD_QHD_BUFFER_COUNT; i++) {
28             p_qtd->buffer[i] |= ((p_qtd->buffer[i-1]) & 0xFFFFF000UL) + 4096U;
29         }
30     }
31 }
32 
33 /*---------------------------------------------------------------------
34  * Device API
35  *---------------------------------------------------------------------
36  */
usb_device_qhd_get(usb_device_handle_t * handle,uint8_t ep_idx)37 dcd_qhd_t *usb_device_qhd_get(usb_device_handle_t *handle, uint8_t ep_idx)
38 {
39     return &handle->dcd_data->qhd[ep_idx];
40 }
41 
usb_device_qtd_get(usb_device_handle_t * handle,uint8_t ep_idx)42 dcd_qtd_t *usb_device_qtd_get(usb_device_handle_t *handle, uint8_t ep_idx)
43 {
44     return &handle->dcd_data->qtd[ep_idx * USB_SOC_DCD_QTD_COUNT_EACH_ENDPOINT];
45 }
46 
usb_device_bus_reset(usb_device_handle_t * handle,uint16_t ep0_max_packet_size)47 void usb_device_bus_reset(usb_device_handle_t *handle, uint16_t ep0_max_packet_size)
48 {
49     dcd_data_t *dcd_data = handle->dcd_data;
50 
51     usb_dcd_bus_reset(handle->regs, ep0_max_packet_size);
52 
53      /* Queue Head & Queue TD */
54     memset(dcd_data, 0, sizeof(dcd_data_t));
55 
56     /* Set up Control Endpoints (0 OUT, 1 IN) */
57     dcd_data->qhd[0].zero_length_termination = dcd_data->qhd[1].zero_length_termination = 1;
58     dcd_data->qhd[0].max_packet_size         = dcd_data->qhd[1].max_packet_size         = ep0_max_packet_size;
59     dcd_data->qhd[0].qtd_overlay.next        = dcd_data->qhd[1].qtd_overlay.next        = USB_SOC_DCD_QTD_NEXT_INVALID;
60 
61     /* OUT only */
62     dcd_data->qhd[0].int_on_setup = 1;
63 }
64 
usb_device_init(usb_device_handle_t * handle,uint32_t int_mask)65 bool usb_device_init(usb_device_handle_t *handle, uint32_t int_mask)
66 {
67     /* Clear memroy */
68     if (handle->dcd_data == NULL) {
69         return false;
70     }
71 
72     memset(handle->dcd_data, 0, sizeof(dcd_data_t));
73 
74     /* Initialize controller in device mode */
75     usb_dcd_init(handle->regs);
76 
77     /* Set endpoint list address */
78     usb_dcd_set_edpt_list_addr(handle->regs, core_local_mem_to_sys_address(0,  (uint32_t)handle->dcd_data->qhd));
79 
80     /* Clear status */
81     usb_clear_status_flags(handle->regs, usb_get_status_flags(handle->regs));
82 
83     /* Enable interrupt mask */
84     usb_enable_interrupts(handle->regs, int_mask);
85 
86     /* Connect */
87     usb_dcd_connect(handle->regs);
88 
89     return true;
90 }
91 
usb_device_deinit(usb_device_handle_t * handle)92 void usb_device_deinit(usb_device_handle_t *handle)
93 {
94     /* Clear memroy */
95     memset(handle->dcd_data, 0, sizeof(dcd_data_t));
96 
97     usb_dcd_deinit(handle->regs);
98 
99     for (uint32_t i = 0; i < USB_SOC_DCD_MAX_ENDPOINT_COUNT; i++) {
100         usb_dcd_edpt_close(handle->regs, (i | (usb_dir_in  << 0x07)));
101         usb_dcd_edpt_close(handle->regs, (i | (usb_dir_out << 0x07)));
102     }
103 }
104 
usb_device_status_flags(usb_device_handle_t * handle)105 uint32_t usb_device_status_flags(usb_device_handle_t *handle)
106 {
107     return usb_get_status_flags(handle->regs);
108 }
109 
usb_device_clear_status_flags(usb_device_handle_t * handle,uint32_t mask)110 void usb_device_clear_status_flags(usb_device_handle_t *handle, uint32_t mask)
111 {
112     usb_clear_status_flags(handle->regs, mask);
113 }
114 
usb_device_interrupts(usb_device_handle_t * handle)115 uint32_t usb_device_interrupts(usb_device_handle_t *handle)
116 {
117     return usb_get_interrupts(handle->regs);
118 }
119 
usb_device_get_port_speed(usb_device_handle_t * handle)120 uint8_t usb_device_get_port_speed(usb_device_handle_t *handle)
121 {
122     return usb_get_port_speed(handle->regs);
123 }
124 
usb_device_get_suspend_status(usb_device_handle_t * handle)125 uint8_t usb_device_get_suspend_status(usb_device_handle_t *handle)
126 {
127     return usb_get_suspend_status(handle->regs);
128 }
129 
usb_device_set_address(usb_device_handle_t * handle,uint8_t dev_addr)130 void usb_device_set_address(usb_device_handle_t *handle, uint8_t dev_addr)
131 {
132     /* Response with status first before changing device address */
133     usb_device_edpt_xfer(handle, 0 | usb_dir_in_mask, NULL, 0);
134 
135     usb_dcd_set_address(handle->regs, dev_addr);
136 }
137 
usb_device_get_address(usb_device_handle_t * handle)138 uint8_t usb_device_get_address(usb_device_handle_t *handle)
139 {
140     return usb_dcd_get_device_addr(handle->regs);
141 }
142 
usb_device_remote_wakeup(usb_device_handle_t * handle)143 void usb_device_remote_wakeup(usb_device_handle_t *handle)
144 {
145     usb_dcd_remote_wakeup(handle->regs);
146 }
147 
usb_device_connect(usb_device_handle_t * handle)148 void usb_device_connect(usb_device_handle_t *handle)
149 {
150     usb_dcd_connect(handle->regs);
151 }
152 
usb_device_disconnect(usb_device_handle_t * handle)153 void usb_device_disconnect(usb_device_handle_t *handle)
154 {
155     usb_dcd_disconnect(handle->regs);
156 }
157 
usb_device_get_port_ccs(usb_device_handle_t * handle)158 bool usb_device_get_port_ccs(usb_device_handle_t *handle)
159 {
160     return usb_get_port_ccs(handle->regs);
161 }
162 
usb_device_get_port_reset_status(usb_device_handle_t * handle)163 bool usb_device_get_port_reset_status(usb_device_handle_t *handle)
164 {
165     return usb_get_port_reset_status(handle->regs);
166 }
167 
usb_device_get_edpt_complete_status(usb_device_handle_t * handle)168 uint32_t usb_device_get_edpt_complete_status(usb_device_handle_t *handle)
169 {
170     return usb_dcd_get_edpt_complete_status(handle->regs);
171 }
172 
usb_device_clear_edpt_complete_status(usb_device_handle_t * handle,uint32_t mask)173 void usb_device_clear_edpt_complete_status(usb_device_handle_t *handle, uint32_t mask)
174 {
175     usb_dcd_clear_edpt_complete_status(handle->regs, mask);
176 }
177 
usb_device_get_setup_status(usb_device_handle_t * handle)178 uint32_t usb_device_get_setup_status(usb_device_handle_t *handle)
179 {
180     return usb_dcd_get_edpt_setup_status(handle->regs);
181 }
182 
usb_device_clear_setup_status(usb_device_handle_t * handle,uint32_t mask)183 void usb_device_clear_setup_status(usb_device_handle_t *handle, uint32_t mask)
184 {
185     usb_dcd_clear_edpt_setup_status(handle->regs, mask);
186 }
187 
188 /*---------------------------------------------------------------------
189  * Endpoint API
190  *---------------------------------------------------------------------
191  */
usb_device_edpt_open(usb_device_handle_t * handle,usb_endpoint_config_t * config)192 bool usb_device_edpt_open(usb_device_handle_t *handle, usb_endpoint_config_t *config)
193 {
194     uint8_t const epnum  = config->ep_addr & 0x0f;
195     uint8_t const dir = (config->ep_addr & 0x80) >> 7;
196     uint8_t const ep_idx = 2 * epnum + dir;
197 
198     dcd_qhd_t *p_qhd;
199 
200     /* Must not exceed max endpoint number */
201     if (epnum >= USB_SOC_DCD_MAX_ENDPOINT_COUNT) {
202         return false;
203     }
204 
205     /* Prepare Queue Head */
206     p_qhd = &handle->dcd_data->qhd[ep_idx];
207     memset(p_qhd, 0, sizeof(dcd_qhd_t));
208 
209     p_qhd->zero_length_termination = 1;
210     p_qhd->max_packet_size         = config->max_packet_size;
211     p_qhd->qtd_overlay.next        = USB_SOC_DCD_QTD_NEXT_INVALID;
212 
213     usb_dcd_edpt_open(handle->regs, config);
214 
215     return true;
216 }
217 
usb_device_edpt_xfer(usb_device_handle_t * handle,uint8_t ep_addr,uint8_t * buffer,uint32_t total_bytes)218 bool usb_device_edpt_xfer(usb_device_handle_t *handle, uint8_t ep_addr, uint8_t *buffer, uint32_t total_bytes)
219 {
220     uint8_t const epnum = ep_addr & 0x0f;
221     uint8_t const dir   = (ep_addr & 0x80) >> 7;
222     uint8_t const ep_idx = 2 * epnum + dir;
223     uint8_t qtd_num;
224     uint8_t i;
225     uint32_t xfer_len;
226     dcd_qhd_t *p_qhd;
227     dcd_qtd_t *p_qtd;
228     dcd_qtd_t *first_p_qtd = NULL;
229     dcd_qtd_t *prev_p_qtd = NULL;
230 
231     if (epnum == 0) {
232         /* follows UM Setup packet handling using setup lockout mechanism
233          * wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out
234          */
235         while (usb_dcd_get_edpt_setup_status(handle->regs) & HPM_BITSMASK(1, 0)) {
236         }
237     }
238 
239     qtd_num = (total_bytes + 0x3fff) / 0x4000;
240     if (qtd_num > USB_SOC_DCD_QTD_COUNT_EACH_ENDPOINT) {
241         return false;
242     }
243 
244     if (buffer != NULL) {
245         buffer = (uint8_t *)core_local_mem_to_sys_address(0, (uint32_t)buffer);
246     }
247     p_qhd = &handle->dcd_data->qhd[ep_idx];
248     i = 0;
249     do {
250         p_qtd = &handle->dcd_data->qtd[ep_idx * USB_SOC_DCD_QTD_COUNT_EACH_ENDPOINT + i];
251         i++;
252 
253         if (total_bytes > 0x4000) {
254             xfer_len = 0x4000;
255             total_bytes -= 0x4000;
256         } else {
257             xfer_len = total_bytes;
258             total_bytes = 0;
259         }
260 
261         usb_qtd_init(p_qtd, (void *)buffer, xfer_len);
262         if (total_bytes == 0) {
263             p_qtd->int_on_complete = true;
264         }
265         buffer += xfer_len;
266 
267         if (prev_p_qtd) {
268             prev_p_qtd->next = (uint32_t)p_qtd;
269         } else {
270             first_p_qtd = p_qtd;
271         }
272         prev_p_qtd = p_qtd;
273     } while (total_bytes > 0);
274 
275     p_qhd->qtd_overlay.next = core_local_mem_to_sys_address(0, (uint32_t) first_p_qtd); /* link qtd to qhd */
276 
277     if (usb_dcd_edpt_get_type(handle->regs, ep_addr) == usb_xfer_isochronous) {
278         p_qhd->iso_mult = 1;
279     }
280     usb_dcd_edpt_xfer(handle->regs, ep_idx);
281 
282     return true;
283 }
284 
usb_device_edpt_stall(usb_device_handle_t * handle,uint8_t ep_addr)285 void usb_device_edpt_stall(usb_device_handle_t *handle, uint8_t ep_addr)
286 {
287     usb_dcd_edpt_stall(handle->regs, ep_addr);
288 }
289 
usb_device_edpt_clear_stall(usb_device_handle_t * handle,uint8_t ep_addr)290 void usb_device_edpt_clear_stall(usb_device_handle_t *handle, uint8_t ep_addr)
291 {
292     usb_dcd_edpt_clear_stall(handle->regs, ep_addr);
293 }
294 
usb_device_edpt_check_stall(usb_device_handle_t * handle,uint8_t ep_addr)295 bool usb_device_edpt_check_stall(usb_device_handle_t *handle, uint8_t ep_addr)
296 {
297     return usb_dcd_edpt_check_stall(handle->regs, ep_addr);
298 }
299 
usb_device_edpt_close(usb_device_handle_t * handle,uint8_t ep_addr)300 void usb_device_edpt_close(usb_device_handle_t *handle, uint8_t ep_addr)
301 {
302     usb_dcd_edpt_close(handle->regs, ep_addr);
303 }
304 
usb_device_edpt_close_all(usb_device_handle_t * handle)305 void usb_device_edpt_close_all(usb_device_handle_t *handle)
306 {
307     for (uint32_t i = 1; i < USB_SOC_DCD_MAX_ENDPOINT_COUNT; i++) {
308         usb_device_edpt_close(handle, i);
309     }
310 }
311