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