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