1 /*******************************************************************************
2 * Copyright 2019-2020 Microchip FPGA Embedded Systems Solutions.
3 *
4 * SPDX-License-Identifier: MIT
5 *
6 * PolarFire SoC MSS USB Driver Stack
7 * USB Core Interface Layer (USB-CIFL)
8 * USBH-CIF driver
9 *
10 * USBH-CIF driver implementation:
11 * This file implements MSS USB core initialization in host mode and
12 * implements core interface function for the logical layer to control the
13 * MSS USB core in USB Host mode.
14 *
15 */
16
17 #include "mpfs_hal/mss_hal.h"
18 #include "mss_usb_host_cif.h"
19 #include "mss_usb_common_cif.h"
20 #include "mss_usb_common_reg_io.h"
21 #include "mss_usb_core_regs.h"
22 #include "mss_usb_host_reg_io.h"
23 #include "mss_usb_std_def.h"
24
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28
29 #ifdef MSS_USB_HOST_ENABLED
30
31 extern mss_usbh_cb_t g_mss_usbh_cb;
32
33 /***************************************************************************//**
34 *
35 */
36 void
MSS_USBH_CIF_init(void)37 MSS_USBH_CIF_init
38 (
39 void
40 )
41 {
42 MSS_USB_CIF_enable_hs_mode();
43 MSS_USB_CIF_clr_usb_irq_reg();
44
45 PLIC_EnableIRQ(USB_DMA_PLIC);
46 MSS_USB_CIF_rx_ep_disable_irq_all();
47 MSS_USB_CIF_tx_ep_disable_irq_all();
48
49 PLIC_EnableIRQ(USB_MC_PLIC);
50
51 /* This was added during Compliance testing */
52 USB->C_T_HSBT = 0x01u;
53
54 MSS_USB_CIF_enable_usbirq(CONNECT_IRQ_MASK | DISCONNECT_IRQ_MASK);
55 MSS_USB_CIF_start_session();
56 }
57
58 /***************************************************************************//**
59 *
60 */
61 void
MSS_USBH_CIF_cep_configure(mss_usb_ep_t * cep)62 MSS_USBH_CIF_cep_configure
63 (
64 mss_usb_ep_t* cep
65 )
66 {
67 /* Control transfers will be handled without DMA */
68 MSS_USBH_CIF_cep_clr_csr_reg();
69
70 /* TODO:Ping should be decided based on TDev Speed. */
71 if (cep->disable_ping)
72 {
73 MSS_USBH_CIF_cep_disable_ping();
74 }
75 else
76 {
77 MSS_USBH_CIF_cep_enable_ping();
78 }
79
80 ASSERT(cep->interval <= 32768u);
81
82 /* Value 0 or 1 disables the NAKTIMEOUT functionality.*/
83 if (cep->interval <= 32768u)
84 {
85 /*Value must be true and power of 2*/
86 ASSERT(((cep->interval != 0U) &&
87 (!(cep->interval & (cep->interval- 1)))));
88
89 /*2 pow (m-1)*/
90 MSS_USBH_CIF_cep_set_naklimit((MSS_USBH_CIF_ctz(cep->interval) + 1u));
91 }
92
93 /* Not flushing FIFO..since Tx/Rxpktrdy bit is not set. */
94 MSS_USB_CIF_cep_enable_irq();
95 }
96
97 /*******************************************************************************
98 * Configures the registers related to TX EP for data transfer operations as
99 * per the parameters provided by the upper layer.
100 */
101 void
MSS_USBH_CIF_tx_ep_configure(mss_usb_ep_t * host_ep)102 MSS_USBH_CIF_tx_ep_configure
103 (
104 mss_usb_ep_t* host_ep
105 )
106 {
107 MSS_USB_CIF_tx_ep_clr_csrreg(host_ep->num);
108
109 /* Perform host mode configurations here */
110 /* TODO: Add AutoSet DMA etc */
111 MSS_USBH_CIF_tx_ep_clr_retry_err(host_ep->num);
112 MSS_USBH_CIF_tx_ep_clr_naktimeout_err(host_ep->num);
113 MSS_USBH_CIF_tx_ep_clr_rxstall_err(host_ep->num);
114 MSS_USBH_CIF_tx_ep_clr_data_tog_we(host_ep->num);
115 MSS_USBH_CIF_tx_ep_clr_force_data_tog(host_ep->num);
116 if (DMA_ENABLE == host_ep->dma_enable)
117 {
118 MSS_USB_CIF_tx_ep_set_autoset(host_ep->num);
119 }
120 else
121 {
122 MSS_USB_CIF_tx_ep_clr_autoset(host_ep->num);
123 }
124
125 /* Do the common configuration for TX EP */
126 MSS_USB_CIF_tx_ep_configure(host_ep);
127 }
128
129 /*******************************************************************************
130 * Configures the registers related to RX EP for data transfer operations as
131 * per the parameters provided by the upper layer.
132 */
133 void
MSS_USBH_CIF_rx_ep_configure(mss_usb_ep_t * host_ep)134 MSS_USBH_CIF_rx_ep_configure
135 (
136 mss_usb_ep_t* host_ep
137 )
138 {
139 MSS_USB_CIF_rx_ep_clr_csrreg(host_ep->num);
140
141 /* Perform host mode configurations here */
142 /* TODO: Add AutoSet DMA etc */
143 MSS_USBH_CIF_rx_ep_clr_retry_err(host_ep->num);
144 MSS_USBH_CIF_rx_ep_clr_naktimeout_err(host_ep->num);
145 MSS_USBH_CIF_rx_ep_clr_rxstall_err(host_ep->num);
146 MSS_USBH_CIF_rx_ep_clr_data_tog_we(host_ep->num);
147 MSS_USBH_CIF_rx_ep_clr_data_tog(host_ep->num);
148 if (DMA_ENABLE == host_ep->dma_enable)
149 {
150 MSS_USBH_CIF_rx_ep_set_autoreq(host_ep->num);
151 }
152 else
153 {
154 MSS_USBH_CIF_rx_ep_clr_autoreq(host_ep->num);
155 }
156
157 /* Do the common configuration for RX EP */
158 MSS_USB_CIF_rx_ep_configure(host_ep);
159 }
160
161
162 /***************************************************************************//**
163 *
164 */
165 void
MSS_USBH_CIF_bus_suspend(uint32_t enable_suspendm)166 MSS_USBH_CIF_bus_suspend
167 (
168 uint32_t enable_suspendm
169 )
170 {
171 if (SUSPENDM_DISABLE == enable_suspendm)
172 {
173 MSS_USBH_CIF_disable_suspendm_out();
174 }
175 else
176 {
177 MSS_USBH_CIF_enable_suspendm_out();
178 }
179
180 MSS_USBH_CIF_assert_suspend_bus();
181 }
182
183
184 /***************************************************************************//**
185 *
186 */
187 void
MSS_USBH_CIF_bus_resume(void)188 MSS_USBH_CIF_bus_resume
189 (
190 void
191 )
192 {
193 MSS_USBH_CIF_clr_suspend_bus();
194 MSS_USBH_CIF_assert_bus_resume();
195
196 /* TODO:This delay should be 20ms */
197 MSS_USBH_CIF_clr_bus_resume();
198 }
199
200
201 /***************************************************************************//**
202 *
203 */
204 mss_usb_vbus_level_t
MSS_USBH_CIF_read_vbus_level(void)205 MSS_USBH_CIF_read_vbus_level
206 (
207 void
208 )
209 {
210 return (MSS_USB_CIF_get_vbus_level());
211 }
212
213
214 /***************************************************************************//**
215 *
216 */
217 uint32_t
MSS_USBH_CIF_tx_ep_mp_configure(uint8_t outpipe_num,uint8_t tdev_ep_num,uint8_t tdev_addr,uint8_t tdev_hub_addr,uint8_t tdev_hub_port,uint8_t tdev_hub_mtt,mss_usb_device_speed_t tdev_speed,uint32_t tdev_interval,mss_usb_xfr_type_t tdev_xfr_type)218 MSS_USBH_CIF_tx_ep_mp_configure
219 (
220 uint8_t outpipe_num,
221 uint8_t tdev_ep_num,
222 uint8_t tdev_addr,
223 uint8_t tdev_hub_addr,
224 uint8_t tdev_hub_port,
225 uint8_t tdev_hub_mtt,
226 mss_usb_device_speed_t tdev_speed,
227 uint32_t tdev_interval,
228 mss_usb_xfr_type_t tdev_xfr_type
229 )
230 {
231 MSS_USBH_CIF_tx_ep_clr_txtypereg((mss_usb_ep_num_t)outpipe_num);
232
233 /*
234 * Since the core has Multipoint option enabled, following settings need to
235 * be done even though there is single device connected
236 */
237 MSS_USBH_CIF_tx_ep_set_target_func_addr((mss_usb_ep_num_t)outpipe_num, tdev_addr);
238
239 #if 0
240 /* Hub and multiple devices are not supported yet */
241 MSS_USBH_CIF_tx_ep_set_target_hub_addr(outpipe_num, tdev_hub_addr, tdev_hub_mtt);
242 MSS_USBH_CIF_tx_ep_set_target_hub_port(outpipe_num, tdev_hub_port);
243 #endif
244
245 if ((MSS_USB_XFR_INTERRUPT == tdev_xfr_type) &&
246 (MSS_USB_DEVICE_HS != tdev_speed))
247 {
248 MSS_USBH_CIF_tx_ep_set_target_interval((mss_usb_ep_num_t)outpipe_num, tdev_interval);
249 }
250 else
251 {
252 /*2 pow (m-1)*/
253 MSS_USBH_CIF_tx_ep_set_target_interval((mss_usb_ep_num_t)outpipe_num,
254 ((MSS_USBH_CIF_ctz(tdev_interval)) + 1u));
255 }
256
257 MSS_USBH_CIF_tx_ep_set_target_ep_no((mss_usb_ep_num_t)outpipe_num, tdev_ep_num);
258 MSS_USBH_CIF_tx_ep_set_target_protocol((mss_usb_ep_num_t)outpipe_num, tdev_xfr_type);
259 MSS_USBH_CIF_tx_ep_set_target_speed((mss_usb_ep_num_t)outpipe_num, tdev_speed);
260
261 return (0);
262 }
263
264 /***************************************************************************//**
265 *
266 */
267 uint32_t
MSS_USBH_CIF_rx_ep_mp_configure(uint8_t inpipe_num,uint8_t tdev_ep_num,uint8_t tdev_addr,uint8_t tdev_hub_addr,uint8_t tdev_hub_port,uint8_t tdev_hub_mtt,mss_usb_device_speed_t tdev_speed,uint32_t tdev_interval,mss_usb_xfr_type_t tdev_xfr_type)268 MSS_USBH_CIF_rx_ep_mp_configure
269 (
270 uint8_t inpipe_num,
271 uint8_t tdev_ep_num,
272 uint8_t tdev_addr,
273 uint8_t tdev_hub_addr,
274 uint8_t tdev_hub_port,
275 uint8_t tdev_hub_mtt,
276 mss_usb_device_speed_t tdev_speed,
277 uint32_t tdev_interval,
278 mss_usb_xfr_type_t tdev_xfr_type
279 )
280 {
281 MSS_USBH_CIF_rx_ep_clr_rxtypereg((mss_usb_ep_num_t)inpipe_num);
282
283 /*
284 * Since the core has Multipoint option enabled, following settings need to
285 * be done even though there is single device connected
286 */
287 MSS_USBH_CIF_rx_ep_set_target_func_addr((mss_usb_ep_num_t)inpipe_num,
288 tdev_addr);
289
290 #if 0
291 /* Hub and multiple devices are not supported yet */
292 MSS_USBH_CIF_rx_ep_set_target_hub_addr((mss_usb_ep_num_t)inpipe_num,
293 tdev_hub_addr,
294 tdev_hub_mtt);
295
296 MSS_USBH_CIF_rx_ep_set_target_hub_port((mss_usb_ep_num_t)inpipe_num,
297 tdev_hub_port);
298 #endif
299
300 if((MSS_USB_XFR_INTERRUPT == tdev_xfr_type) &&
301 (MSS_USB_DEVICE_HS != tdev_speed))
302 {
303
304
305 MSS_USBH_CIF_rx_ep_set_target_interval((mss_usb_ep_num_t)inpipe_num,
306 tdev_interval);
307 }
308 else
309 {
310
311 MSS_USBH_CIF_rx_ep_set_target_interval((mss_usb_ep_num_t)inpipe_num,
312 ((MSS_USBH_CIF_ctz(tdev_interval)) + 1u));
313 }
314
315 MSS_USBH_CIF_rx_ep_set_target_ep_no((mss_usb_ep_num_t)inpipe_num, tdev_ep_num);
316 MSS_USBH_CIF_rx_ep_set_target_protocol((mss_usb_ep_num_t)inpipe_num, tdev_xfr_type);
317 MSS_USBH_CIF_rx_ep_set_target_speed((mss_usb_ep_num_t)inpipe_num, tdev_speed);
318
319 return(0);
320 }
321
322 /*******************************************************************************
323 * Writes a data packet on EP0 in host mode(control endpoint).
324 */
325 void
MSS_USBH_CIF_cep_write_pkt(mss_usb_ep_t * hcep)326 MSS_USBH_CIF_cep_write_pkt
327 (
328 mss_usb_ep_t* hcep
329 )
330 {
331 ASSERT((hcep->num == MSS_USB_CEP) &&
332 (hcep->buf_addr != 0) &&
333 (hcep->xfr_type == MSS_USB_XFR_CONTROL));
334
335 /* null buffer, xfr type, transaction type */
336 if ((hcep->num == MSS_USB_CEP) &&
337 (hcep->buf_addr != 0) &&
338 (hcep->xfr_type == MSS_USB_XFR_CONTROL))
339 {
340 MSS_USB_CIF_load_tx_fifo(hcep->num,
341 hcep->buf_addr,
342 hcep->txn_length);
343
344 hcep->txn_count = hcep->txn_length;
345 hcep->xfr_count += hcep->txn_length;
346 }
347 }
348
349 /*******************************************************************************
350 * Reads data packet arrived on EP0 in host mode(control endpoint).
351 */
352 void
MSS_USBH_CIF_cep_read_pkt(mss_usb_ep_t * hcep)353 MSS_USBH_CIF_cep_read_pkt
354 (
355 mss_usb_ep_t* hcep
356 )
357 {
358 uint16_t received_count = 0u;
359
360 ASSERT((hcep->num == MSS_USB_CEP) &&
361 (hcep->buf_addr != 0) &&
362 (hcep->xfr_type == MSS_USB_XFR_CONTROL));
363
364 /* TODO: check stalled, null buffer, xfr type, transaction type */
365 received_count = MSS_USB_CIF_cep_rx_byte_count();
366 ASSERT(received_count <= hcep->txn_length);
367 MSS_USB_CIF_read_rx_fifo(MSS_USB_CEP, hcep->buf_addr, received_count);
368 hcep->buf_addr += received_count;
369 MSS_USBH_CIF_cep_clr_rxpktrdy();
370 hcep->xfr_count += received_count;
371 hcep->txn_count = received_count;
372 }
373
374 /***************************************************************************//**
375 *
376 */
377 void
MSS_USBH_CIF_cep_abort_xfr(void)378 MSS_USBH_CIF_cep_abort_xfr
379 (
380 void
381 )
382 {
383 /* Flush the FIFO and reset all values */
384 MSS_USB_CIF_cep_disable_irq();
385 MSS_USB_CIF_cep_set_txpktrdy();
386 MSS_USB_CIF_cep_flush_fifo();
387 MSS_USB_CIF_cep_enable_irq();
388
389 /* clear all bits but retain the values of Data_tog_we and Disable_ping */
390 MSS_USBH_CIF_cep_clr_naktimeout_err();
391 MSS_USBH_CIF_cep_clr_rxstall_err();
392 MSS_USBH_CIF_cep_clr_rxpktrdy();
393
394 USB->ENDPOINT[MSS_USB_CEP].TX_CSR &= ~ (CSR0L_HOST_IN_PKT_REQ_MASK |
395 CSR0L_HOST_SETUP_PKT_MASK |
396 CSR0L_HOST_STATUS_PKT_MASK |
397 CSR0L_HOST_RX_PKT_RDY_MASK |
398 CSR0H_HOST_DATA_TOG_MASK);
399 }
400
401 /***************************************************************************//**
402 *
403 */
404 void
MSS_USBH_CIF_handle_connect_irq(void)405 MSS_USBH_CIF_handle_connect_irq
406 (
407 void
408 )
409 {
410 mss_usb_device_speed_t speed = MSS_USB_DEVICE_FS;
411
412 if (MSS_USBH_CIF_is_target_ls())
413 {
414 speed = MSS_USB_DEVICE_LS;
415 }
416 else if (MSS_USBH_CIF_is_target_fs())
417 {
418 speed = (MSS_USB_DEVICE_FS);
419 }
420
421 if (MSS_USBH_CIF_is_host_suspended())
422 {
423 MSS_USBH_CIF_clr_suspend_bus();
424 }
425
426 g_mss_usbh_cb.usbh_connect(speed , MSS_USB_CIF_get_vbus_level());
427 }
428
429 #endif /* MSS_USB_HOST_ENABLED */
430
431 #ifdef __cplusplus
432 }
433 #endif
434