1 /*
2 * Copyright (c) 2021 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #ifndef HPM_USB_HOST_H
9 #define HPM_USB_HOST_H
10
11 /*---------------------------------------------------------------------
12 * Includes
13 *---------------------------------------------------------------------
14 */
15 #include "hpm_usb_drv.h"
16 #include "hpm_common.h"
17 #include "hpm_soc_feature.h"
18
19 /*---------------------------------------------------------------------
20 * Macros
21 *---------------------------------------------------------------------
22 */
23
24
25 #ifndef USB_HCD_PERIODIC_ARR_COUNT
26 #define USB_HCD_PERIODIC_ARR_COUNT (4U)
27 #endif
28
29 #ifndef USB_HCD_MAX_CONNECTED_DEVICES
30 #define USB_HCD_MAX_CONNECTED_DEVICES (5U)
31 #endif
32
33 #ifndef USB_HCD_MAX_QHD_COUNT
34 #define USB_HCD_MAX_QHD_COUNT (USB_HCD_MAX_CONNECTED_DEVICES * 16U * 2U)
35 #endif
36
37 #ifndef USB_HCD_MAX_QTD_COUNT
38 #define USB_HCD_MAX_QTD_COUNT (USB_HCD_MAX_QHD_COUNT * 2U)
39 #endif
40 /*---------------------------------------------------------------------
41 * Enum Declarations
42 *---------------------------------------------------------------------
43 */
44 typedef enum {
45 usb_max_itd = 4,
46 usb_max_sitd = 16
47 } usb_max_xtd_t;
48
49 typedef enum {
50 usb_qtype_itd = 0,
51 usb_qtype_qhd,
52 usb_qtype_sitd,
53 usb_qtype_fstn
54 } usb_qtype_t;
55
56 typedef enum {
57 usb_pid_out = 0,
58 usb_pid_in,
59 usb_pid_setup
60 } usb_pid_t;
61
62 typedef enum {
63 usb_speed_full = 0,
64 usb_speed_low,
65 usb_speed_high,
66 usb_speed_invalid = 0xff,
67 } usb_speed_t;
68
69 typedef enum {
70 usb_cmd_pos_run_stop = 0,
71 usb_cmd_pos_framelist_szie = 2,
72 usb_cmd_pos_period_enable = 4,
73 usb_cmd_pos_async_enable = 5,
74 usb_cmd_pos_framelist_size_msb = 15,
75 usb_cmd_pos_interrupt_threshold = 16
76 } usb_cmd_pos_t;
77
78 typedef enum {
79 usb_portsc_mask_current_connect_status = HPM_BITSMASK(1, 0),
80 usb_portsc_mask_connect_status_change = HPM_BITSMASK(1, 1),
81 usb_portsc_mask_port_eanbled = HPM_BITSMASK(1, 2),
82 usb_portsc_mask_port_enable_chagne = HPM_BITSMASK(1, 3),
83 usb_portsc_mask_over_current_change = HPM_BITSMASK(1, 5),
84 usb_portsc_mask_port_reset = HPM_BITSMASK(1, 8),
85
86 usb_portsc_mask_all = usb_portsc_mask_connect_status_change
87 | usb_portsc_mask_port_enable_chagne
88 | usb_portsc_mask_over_current_change
89 } usb_portsc_change_mask_t;
90
91 /* Link pointer */
92 typedef union {
93 volatile uint32_t address;
94 struct {
95 volatile uint32_t terminate : 1;
96 volatile uint32_t type : 2;
97 };
98 } hcd_link_t;
99
100 /* Queue Element Transfer Descriptor */
101 /* Qtd is used to declare overlay in hcd_qhd_t */
102 typedef struct {
103 /* Word 0: Next QTD Pointer */
104 volatile hcd_link_t next;
105
106 /* Word 1: Alternate Next QTD Pointer (not used) */
107 union{
108 volatile hcd_link_t alternate;
109 struct {
110 volatile uint32_t : 5;
111 volatile uint32_t used : 1;
112 volatile uint32_t : 10;
113 volatile uint32_t expected_bytes : 16;
114 };
115 };
116
117 /* Word 2: qTQ Token */
118 volatile uint32_t ping_err : 1 ; /* For Highspeed: 0 Out, 1 Ping. Full/Slow used as error indicator */
119 volatile uint32_t non_hs_split_state : 1 ; /* Used by HC to track the state of slipt transaction */
120 volatile uint32_t non_hs_missed_uframe : 1 ; /* HC misses a complete slip transaction */
121 volatile uint32_t xact_err : 1 ; /* Error (Timeout, CRC, Bad PID ... ) */
122 volatile uint32_t babble_err : 1 ; /* Babble detected, also set Halted bit to 1 */
123 volatile uint32_t buffer_err : 1 ; /* Data overrun/underrun error */
124 volatile uint32_t halted : 1 ; /* Serious error or STALL received */
125 volatile uint32_t active : 1 ; /* Start transfer, clear by HC when complete */
126 volatile uint32_t pid : 2 ; /* 0: OUT, 1: IN, 2 Setup */
127 volatile uint32_t err_count : 2 ; /* Error Counter of consecutive errors */
128 volatile uint32_t current_page : 3 ; /* Index into the qTD buffer pointer list */
129 volatile uint32_t int_on_complete : 1 ; /* Interrupt on complete */
130 volatile uint32_t total_bytes : 15 ; /* Transfer bytes, decreased during transaction */
131 volatile uint32_t data_toggle : 1 ; /* Data Toggle bit */
132
133 /* Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page */
134 volatile uint32_t buffer[USB_SOC_HCD_QTD_BUFFER_COUNT];
135 } hcd_qtd_t;
136
137 /* Queue Head */
138 typedef struct {
139 /* Word 0: Next QHD */
140 hcd_link_t next;
141
142 /* Word 1: Endpoint Characteristics */
143 volatile uint32_t dev_addr : 7 ; /* device address */
144 volatile uint32_t fl_inactive_next_xact : 1 ; /* Only valid for Periodic with Full/Slow speed */
145 volatile uint32_t ep_number : 4 ; /* EP number */
146 volatile uint32_t ep_speed : 2 ; /* 0: Full, 1: Low, 2: High */
147 volatile uint32_t data_toggle_control : 1 ; /* 0: use DT in qHD, 1: use DT in qTD */
148 volatile uint32_t head_list_flag : 1 ; /* Head of the queue */
149 volatile uint32_t max_packet_size : 11 ; /* Max packet size */
150 volatile uint32_t fl_ctrl_ep_flag : 1 ; /* 1 if is Full/Low speed control endpoint */
151 volatile uint32_t nak_reload : 4 ; /* Used by HC */
152
153 /* Word 2: Endpoint Capabilities */
154 volatile uint32_t int_smask : 8 ; /* Interrupt Schedule Mask */
155 volatile uint32_t fl_int_cmask : 8 ; /* Split Completion Mask for Full/Slow speed */
156 volatile uint32_t fl_hub_addr : 7 ; /* Hub Address for Full/Slow speed */
157 volatile uint32_t fl_hub_port : 7 ; /* Hub Port for Full/Slow speed */
158 volatile uint32_t mult : 2 ; /* Transaction per micro frame */
159
160 /* Word 3: Current qTD Pointer */
161 volatile uint32_t qtd_addr;
162
163 /* Word 4-11: Transfer Overlay */
164 volatile hcd_qtd_t qtd_overlay;
165
166 /*--------------------------------------------------------------------
167 * Due to the fact QHD is 32 bytes aligned but occupies only 48 bytes
168 * thus there are 16 bytes padding free that we can make use of.
169 *--------------------------------------------------------------------
170 */
171 uint8_t used;
172 uint8_t removing; /* removed from async list, waiting for async advance */
173 uint8_t pid;
174 uint8_t interval_ms; /* polling interval in frames (or millisecond) */
175
176 uint16_t total_xferred_bytes; /* number of bytes xferred until a qtd with ioc bit set */
177 uint8_t reserved2[2];
178
179 hcd_qtd_t * volatile p_qtd_list_head; /* head of the scheduled TD list */
180 hcd_qtd_t * volatile p_qtd_list_tail; /* tail of the scheduled TD list */
181 } hcd_qhd_t;
182
183 typedef struct {
184 hcd_link_t period_framelist[USB_HOST_FRAMELIST_SIZE];
185
186 /* for ECHI, only implement 1 ms & 2 ms & 4 ms, 8 ms (framelist)
187 * [0] : 1ms, [1] : 2ms, [2] : 4ms, [3] : 8 ms
188 */
189 hcd_qhd_t period_head_arr[USB_HCD_PERIODIC_ARR_COUNT];
190
191 /* Note control qhd of dev0 is used as head of async list */
192 struct {
193 hcd_qhd_t qhd;
194 hcd_qtd_t qtd;
195 } control[USB_HCD_MAX_CONNECTED_DEVICES + 1];
196
197 hcd_qhd_t qhd_pool[USB_HCD_MAX_QHD_COUNT];
198 hcd_qtd_t qtd_pool[USB_HCD_MAX_QTD_COUNT];
199
200 uint32_t uframe_number;
201 } hcd_data_t;
202
203 typedef struct {
204 uint8_t rhport;
205 uint8_t ep_speed;
206 uint8_t hub_addr;
207 uint8_t hub_port;
208 USB_Type *regs;
209 hcd_data_t *hcd_data;
210 void (*hcd_vbus_ctrl_cb)(uint8_t rhport, uint8_t level);
211 } usb_host_handle_t;
212
213 /* USB Endpoint Descriptor */
214 typedef struct __attribute__ ((packed))
215 {
216 uint8_t bLength;
217 uint8_t bDescriptorType;
218 uint8_t bEndpointAddress;
219
220 struct __attribute__ ((packed)) {
221 uint8_t xfer : 2;
222 uint8_t sync : 2;
223 uint8_t usage : 2;
224 uint8_t : 2;
225 } bmAttributes;
226
227 struct __attribute__ ((packed)) {
228 uint16_t size : 11;
229 uint16_t hs_period_mult : 2;
230 uint16_t : 3;
231 } wMaxPacketSize;
232
233 uint8_t bInterval;
234 } usb_desc_endpoint_t;
235
236 #if defined(__cplusplus)
237 extern "C" {
238 #endif /* __cplusplus */
239
240 /* Get direction from Endpoint address */
usb_edpt_dir(uint8_t addr)241 static inline usb_dir_t usb_edpt_dir(uint8_t addr)
242 {
243 return (addr & usb_dir_in_mask) ? usb_dir_in : usb_dir_out;
244 }
245
246 /* Get Endpoint number from address */
usb_edpt_number(uint8_t addr)247 static inline uint8_t usb_edpt_number(uint8_t addr)
248 {
249 return (uint8_t)(addr & (~usb_dir_in_mask));
250 }
251
252 /* Get Endpoint address */
usb_edpt_addr(uint8_t num,uint8_t dir)253 static inline uint8_t usb_edpt_addr(uint8_t num, uint8_t dir)
254 {
255 return (uint8_t)(num | (dir ? usb_dir_in_mask : 0));
256 }
257
usb_host_align16(uint32_t value)258 static inline uint32_t usb_host_align16(uint32_t value) { return (value & 0xFFFFFFF0UL); }
usb_host_align32(uint32_t value)259 static inline uint32_t usb_host_align32(uint32_t value) { return (value & 0xFFFFFFE0UL); }
usb_host_align4k(uint32_t value)260 static inline uint32_t usb_host_align4k(uint32_t value) { return (value & 0xFFFFF000UL); }
usb_host_offset4k(uint32_t value)261 static inline uint32_t usb_host_offset4k(uint32_t value) { return (value & 0xFFFUL); }
262
263 bool usb_host_qhd_has_xact_error(hcd_qhd_t *p_qhd);
264 bool usb_host_qhd_has_xact_error(hcd_qhd_t *p_qhd);
265 void usb_host_qtd_remove_1st_from_qhd(hcd_qhd_t *p_qhd);
266 hcd_link_t *usb_host_list_next(hcd_link_t *p_link_pointer);
267 hcd_link_t *usb_host_get_period_head(usb_host_handle_t *handle, uint8_t interval_ms);
268 hcd_qhd_t *usb_host_qhd_async_head(usb_host_handle_t *handle);
269 hcd_qhd_t *usb_host_qhd_next(hcd_qhd_t const *p_qhd);
270 hcd_qtd_t *usb_host_qtd_control(usb_host_handle_t *handle, uint8_t dev_addr);
271 uint32_t usb_host_uframe_number(usb_host_handle_t *handle);
272 uint32_t usb_host_status_flags(usb_host_handle_t *handle);
273 uint32_t usb_host_interrupts(usb_host_handle_t *handle);
274 void usb_host_clear_status_flags(usb_host_handle_t *handle, uint32_t status);
275 uint8_t usb_host_get_port_speed(usb_host_handle_t *handle);
276 void usb_host_port_reset(usb_host_handle_t *handle);
277 bool usb_host_init(usb_host_handle_t *handle, uint32_t int_mask, uint16_t framelist_size);
278 bool usb_host_get_port_ccs(usb_host_handle_t *handle);
279 bool usb_host_port_csc(usb_host_handle_t *handle);
280 void usb_host_device_close(usb_host_handle_t *handle, uint8_t dev_addr);
281 bool usb_host_edpt_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t *buffer, uint16_t buflen);
282 bool usb_host_setup_send(usb_host_handle_t *handle, uint8_t dev_addr, const uint8_t *setup_packet);
283 bool usb_host_edpt_open(usb_host_handle_t *handle, uint8_t dev_addr, usb_desc_endpoint_t const *ep_desc);
284 bool usb_host_pipe_queue_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes);
285 bool usb_host_pipe_xfer(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t total_bytes, bool int_on_complete);
286 bool usb_host_edpt_busy(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr);
287 bool usb_host_edpt_stalled(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr);
288 bool usb_host_edpt_clear_stall(usb_host_handle_t *handle, uint8_t dev_addr, uint8_t ep_addr);
289
290 #if defined(__cplusplus)
291 }
292 #endif /* __cplusplus */
293 #endif /* HPM_USB_HOST_H */
294