1 /*!
2     \file    drv_usb_core.c
3     \brief   USB core driver which can operate in host and device mode
4 
5     \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 */
7 
8 /*
9     Copyright (c) 2020, GigaDevice Semiconductor Inc.
10 
11     Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13 
14     1. Redistributions of source code must retain the above copyright notice, this
15        list of conditions and the following disclaimer.
16     2. Redistributions in binary form must reproduce the above copyright notice,
17        this list of conditions and the following disclaimer in the documentation
18        and/or other materials provided with the distribution.
19     3. Neither the name of the copyright holder nor the names of its contributors
20        may be used to endorse or promote products derived from this software without
21        specific prior written permission.
22 
23     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34 
35 #include "drv_usb_core.h"
36 #include "drv_usb_hw.h"
37 
38 /* local function prototypes ('static') */
39 static void usb_core_reset (usb_core_regs *usb_regs);
40 
41 /*!
42     \brief      configure USB core basic
43     \param[in]  usb_basic: pointer to usb capabilities
44     \param[in]  usb_regs: USB core registers
45     \param[in]  usb_core: USB core
46     \param[out] none
47     \retval     operation status
48 */
usb_basic_init(usb_core_basic * usb_basic,usb_core_regs * usb_regs,usb_core_enum usb_core)49 usb_status usb_basic_init (usb_core_basic *usb_basic,
50                            usb_core_regs  *usb_regs,
51                            usb_core_enum   usb_core)
52 {
53     /* configure USB default transfer mode as FIFO mode */
54     usb_basic->transfer_mode = (uint8_t)USB_USE_FIFO;
55 
56     /* USB default speed is full-speed */
57     usb_basic->core_speed = (uint8_t)USB_SPEED_FULL;
58 
59     usb_basic->core_enum = (uint8_t)usb_core;
60 
61     switch (usb_core) {
62     case USB_CORE_ENUM_FS:
63         usb_basic->base_reg = (uint32_t)USBFS_REG_BASE;
64 
65         /* set the host channel numbers */
66         usb_basic->num_pipe = USBFS_MAX_CHANNEL_COUNT;
67 
68         /* set the device endpoint numbers */
69         usb_basic->num_ep = USBFS_MAX_EP_COUNT;
70 
71         /* USBFS core use embedded physical layer */
72         usb_basic->phy_itf = USB_EMBEDDED_PHY;
73         break;
74 
75     default:
76         return USB_FAIL;
77     }
78 
79     usb_basic->sof_enable = USB_SOF_OUTPUT;
80     usb_basic->low_power = USB_LOW_POWER;
81 
82     /* assign main registers address */
83     *usb_regs = (usb_core_regs) {
84         .gr          = (usb_gr*) (usb_basic->base_reg + USB_REG_OFFSET_CORE),
85         .hr          = (usb_hr*) (usb_basic->base_reg + USB_REG_OFFSET_HOST),
86         .dr          = (usb_dr*) (usb_basic->base_reg + USB_REG_OFFSET_DEV),
87 
88         .HPCS        = (uint32_t*) (usb_basic->base_reg + USB_REG_OFFSET_PORT),
89         .PWRCLKCTL   = (uint32_t*) (usb_basic->base_reg + USB_REG_OFFSET_PWRCLKCTL)
90     };
91 
92     /* assign device endpoint registers address */
93     for (uint8_t i = 0U; i < usb_basic->num_ep; i++) {
94         usb_regs->er_in[i] = (usb_erin *) \
95             (usb_basic->base_reg + USB_REG_OFFSET_EP_IN + (i * USB_REG_OFFSET_EP));
96 
97         usb_regs->er_out[i] = (usb_erout *)\
98             (usb_basic->base_reg + USB_REG_OFFSET_EP_OUT + (i * USB_REG_OFFSET_EP));
99     }
100 
101     /* assign host pipe registers address */
102     for (uint8_t i = 0U; i < usb_basic->num_pipe; i++) {
103         usb_regs->pr[i] = (usb_pr *) \
104             (usb_basic->base_reg + USB_REG_OFFSET_CH_INOUT + (i * USB_REG_OFFSET_CH));
105 
106         usb_regs->DFIFO[i] = (uint32_t *) \
107             (usb_basic->base_reg + USB_DATA_FIFO_OFFSET + (i * USB_DATA_FIFO_SIZE));
108     }
109 
110     return USB_OK;
111 }
112 
113 /*!
114     \brief      initializes the USB controller registers and
115                 prepares the core device mode or host mode operation
116     \param[in]  usb_basic: pointer to USB capabilities
117     \param[in]  usb_regs: pointer to USB core registers
118     \param[out] none
119     \retval     operation status
120 */
usb_core_init(usb_core_basic usb_basic,usb_core_regs * usb_regs)121 usb_status usb_core_init (usb_core_basic usb_basic, usb_core_regs *usb_regs)
122 {
123     if (USB_ULPI_PHY == usb_basic.phy_itf) {
124         usb_regs->gr->GCCFG &= ~GCCFG_PWRON;
125 
126         if (usb_basic.sof_enable) {
127             usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
128         }
129 
130         /* init the ULPI interface */
131         usb_regs->gr->GUSBCS &= ~(GUSBCS_EMBPHY | GUSBCS_ULPIEOI);
132 
133 #ifdef USBHS_EXTERNAL_VBUS_ENABLED
134         /* use external VBUS driver */
135         usb_regs->gr->GUSBCS |= GUSBCS_ULPIEVD;
136 #else
137         /* use internal VBUS driver */
138         usb_regs->gr->GUSBCS &= ~GUSBCS_ULPIEVD;
139 #endif /* USBHS_EXTERNAL_VBUS_ENABLED */
140 
141         /* soft reset the core */
142         usb_core_reset (usb_regs);
143     } else {
144         usb_regs->gr->GUSBCS |= GUSBCS_EMBPHY;
145 
146         /* soft reset the core */
147         usb_core_reset (usb_regs);
148 
149         /* active the transceiver and enable VBUS sensing */
150         usb_regs->gr->GCCFG |= GCCFG_PWRON | GCCFG_VBUSACEN | GCCFG_VBUSBCEN;
151 
152 #ifndef VBUS_SENSING_ENABLED
153         usb_regs->gr->GCCFG |= GCCFG_VBUSIG;
154 #endif /* VBUS_SENSING_ENABLED */
155 
156         /* enable SOF output */
157         if (usb_basic.sof_enable) {
158             usb_regs->gr->GCCFG |= GCCFG_SOFOEN;
159         }
160 
161         usb_mdelay(20U);
162     }
163 
164     if ((uint8_t)USB_USE_DMA == usb_basic.transfer_mode) {
165         usb_regs->gr->GAHBCS &= ~GAHBCS_BURST;
166         usb_regs->gr->GAHBCS |= DMA_INCR8 | GAHBCS_DMAEN;
167     }
168 
169 #ifdef USE_OTG_MODE
170 
171     /* enable USB OTG features */
172     usb_regs->gr->GUSBCS |= GUSBCS_HNPCEN | GUSBCS_SRPCEN;
173 
174     /* enable the USB wakeup and suspend interrupts */
175     usb_regs->gr->GINTF = 0xBFFFFFFFU;
176 
177     usb_regs->gr->GINTEN = GINTEN_WKUPIE | GINTEN_SPIE | \
178                                      GINTEN_OTGIE | GINTEN_SESIE | GINTEN_CIDPSCIE;
179 
180 #endif /* USE_OTG_MODE */
181 
182     return USB_OK;
183 }
184 
185 /*!
186     \brief      write a packet into the Tx FIFO associated with the endpoint
187     \param[in]  usb_regs: pointer to USB core registers
188     \param[in]  src_buf: pointer to source buffer
189     \param[in]  fifo_num: FIFO number which is in (0..3)
190     \param[in]  byte_count: packet byte count
191     \param[out] none
192     \retval     operation status
193 */
usb_txfifo_write(usb_core_regs * usb_regs,uint8_t * src_buf,uint8_t fifo_num,uint16_t byte_count)194 usb_status usb_txfifo_write (usb_core_regs *usb_regs,
195                              uint8_t *src_buf,
196                              uint8_t  fifo_num,
197                              uint16_t byte_count)
198 {
199     uint32_t word_count = (byte_count + 3U) / 4U;
200 
201     __IO uint32_t *fifo = usb_regs->DFIFO[fifo_num];
202 
203     while (word_count-- > 0U) {
204         *fifo = *((__packed uint32_t *)src_buf);
205 
206         src_buf += 4U;
207     }
208 
209     return USB_OK;
210 }
211 
212 /*!
213     \brief      read a packet from the Rx FIFO associated with the endpoint
214     \param[in]  usb_regs: pointer to USB core registers
215     \param[in]  dest_buf: pointer to destination buffer
216     \param[in]  byte_count: packet byte count
217     \param[out] none
218     \retval     void type pointer
219 */
usb_rxfifo_read(usb_core_regs * usb_regs,uint8_t * dest_buf,uint16_t byte_count)220 void *usb_rxfifo_read (usb_core_regs *usb_regs, uint8_t *dest_buf, uint16_t byte_count)
221 {
222     uint32_t word_count = (byte_count + 3U) / 4U;
223 
224     __IO uint32_t *fifo = usb_regs->DFIFO[0];
225 
226     while (word_count-- > 0U) {
227         *(__packed uint32_t *)dest_buf = *fifo;
228 
229         dest_buf += 4U;
230     }
231 
232     return ((void *)dest_buf);
233 }
234 
235 /*!
236     \brief      flush a Tx FIFO or all Tx FIFOs
237     \param[in]  usb_regs: pointer to USB core registers
238     \param[in]  fifo_num: FIFO number which is in (0..3)
239     \param[out] none
240     \retval     operation status
241 */
usb_txfifo_flush(usb_core_regs * usb_regs,uint8_t fifo_num)242 usb_status usb_txfifo_flush (usb_core_regs *usb_regs, uint8_t fifo_num)
243 {
244     usb_regs->gr->GRSTCTL = ((uint32_t)fifo_num << 6U) | GRSTCTL_TXFF;
245 
246     /* wait for Tx FIFO flush bit is set */
247     while (usb_regs->gr->GRSTCTL & GRSTCTL_TXFF) {
248         /* no operation */
249     }
250 
251     /* wait for 3 PHY clocks*/
252     usb_udelay(3U);
253 
254     return USB_OK;
255 }
256 
257 /*!
258     \brief      flush the entire Rx FIFO
259     \param[in]  usb_regs: pointer to usb core registers
260     \param[out] none
261     \retval     operation status
262 */
usb_rxfifo_flush(usb_core_regs * usb_regs)263 usb_status usb_rxfifo_flush (usb_core_regs *usb_regs)
264 {
265     usb_regs->gr->GRSTCTL = GRSTCTL_RXFF;
266 
267     /* wait for Rx FIFO flush bit is set */
268     while (usb_regs->gr->GRSTCTL & GRSTCTL_RXFF) {
269         /* no operation */
270     }
271 
272     /* wait for 3 PHY clocks */
273     usb_udelay(3U);
274 
275     return USB_OK;
276 }
277 
278 /*!
279     \brief      set endpoint or channel TX FIFO size
280     \param[in]  usb_regs: pointer to USB core registers
281     \param[in]  fifo: TX FIFO number
282     \param[in]  size: assigned TX FIFO size
283     \param[out] none
284     \retval     none
285 */
usb_set_txfifo(usb_core_regs * usb_regs,uint8_t fifo,uint16_t size)286 void usb_set_txfifo(usb_core_regs *usb_regs, uint8_t fifo, uint16_t size)
287 {
288     uint32_t tx_offset;
289 
290     tx_offset = usb_regs->gr->GRFLEN;
291 
292     if (fifo == 0U) {
293         usb_regs->gr->DIEP0TFLEN_HNPTFLEN = ((uint32_t)size << 16) | tx_offset;
294     } else {
295         tx_offset += (usb_regs->gr->DIEP0TFLEN_HNPTFLEN) >> 16;
296 
297         for (uint8_t i = 0U; i < (fifo - 1U); i++) {
298             tx_offset += (usb_regs->gr->DIEPTFLEN[i] >> 16);
299         }
300 
301         /* Multiply Tx_Size by 2 to get higher performance */
302         usb_regs->gr->DIEPTFLEN[fifo - 1U] = ((uint32_t)size << 16) | tx_offset;
303     }
304 }
305 
306 /*!
307     \brief      set USB current mode
308     \param[in]  usb_regs: pointer to USB core registers
309     \param[out] none
310     \retval     none
311 */
usb_curmode_set(usb_core_regs * usb_regs,uint8_t mode)312 void usb_curmode_set(usb_core_regs *usb_regs, uint8_t mode)
313 {
314     usb_regs->gr->GUSBCS &= ~(GUSBCS_FDM | GUSBCS_FHM);
315 
316     if (DEVICE_MODE == mode) {
317         usb_regs->gr->GUSBCS |= GUSBCS_FDM;
318     } else if (HOST_MODE == mode) {
319         usb_regs->gr->GUSBCS |= GUSBCS_FHM;
320     } else {
321         /* OTG mode and other mode can not be here! */
322     }
323 }
324 
325 /*!
326     \brief      configure USB core to soft reset
327     \param[in]  usb_regs: pointer to USB core registers
328     \param[out] none
329     \retval     none
330 */
usb_core_reset(usb_core_regs * usb_regs)331 static void usb_core_reset (usb_core_regs *usb_regs)
332 {
333     /* enable core soft reset */
334     usb_regs->gr->GRSTCTL |= GRSTCTL_CSRST;
335 
336     /* wait for the core to be soft reset */
337     while (usb_regs->gr->GRSTCTL & GRSTCTL_CSRST) {
338         /* no operation */
339     }
340 
341     /* wait for additional 3 PHY clocks */
342     usb_udelay(3U);
343 }
344