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