1use crate::register_space::Register;
6use crate::register_space::RegisterSpace;
7
8pub const MAX_INTERRUPTER: u8 = 1;
10pub const MAX_SLOTS: u8 = 16;
12
13pub const USB2_PORTS_START: u8 = 0;
15pub const USB2_PORTS_END: u8 = 8;
17pub const USB3_PORTS_START: u8 = 8;
19pub const USB3_PORTS_END: u8 = 16;
21
22pub const MAX_PORTS: u8 = USB3_PORTS_END;
25
26pub const XHCI_CAPLENGTH: u8 = 0x20;
28pub const XHCI_DBOFF: u32 = 0x00002000;
30pub const XHCI_RTSOFF: u32 = 0x00003000;
32
33pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
35pub const USB_CMD_RESET: u32 = 1u32 << 1;
37pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
39
40pub const USB_STS_HALTED: u32 = 1u32 << 0;
42pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
44pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
46pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
48pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
50
51pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
53pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
55pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
57pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
59pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
61
62pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
64pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
66pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
68pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
70pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
72pub const PORTSC_PORT_SPEED_MASK: u32 = 0x00003C00;
74pub const PORTSC_PORT_SPEED_SHIFT: u32 = 10;
76pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
78pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
80pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
82pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
84pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
86
87pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
89pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
91pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
93
94pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
96pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
98
99pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
101
102pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
104
105pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
107pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
109pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
111
112pub const DOORBELL_TARGET: u32 = 0xFF;
114pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
116
117pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
119pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
121pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
123
124pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
126pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
128
129pub const HCCPARAMS1_MAX_PSA_SIZE_OFFSET: u32 = 12;
131pub const MAX_PSA_SIZE: u32 = 3;
133
134pub fn valid_slot_id(slot_id: u8) -> bool {
136 slot_id > 0 && slot_id <= MAX_SLOTS
138}
139
140pub fn valid_max_pstreams(max_pstreams: u8) -> bool {
142 max_pstreams <= MAX_PSA_SIZE as u8
143}
144
145pub fn valid_stream_id(stream_id: u16) -> bool {
147 stream_id > 0 && stream_id < (1 << (MAX_PSA_SIZE + 1))
149}
150
151pub struct XhciRegs {
153 pub usbcmd: Register<u32>,
154 pub usbsts: Register<u32>,
155 pub dnctrl: Register<u32>,
156 pub crcr: Register<u64>,
157 pub dcbaap: Register<u64>,
158 pub config: Register<u64>,
159 pub portsc: Vec<Register<u32>>,
160 pub doorbells: Vec<Register<u32>>,
161 pub iman: Register<u32>,
162 pub imod: Register<u32>,
163 pub erstsz: Register<u32>,
164 pub erstba: Register<u64>,
165 pub erdp: Register<u64>,
166}
167
168pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
171 let mut mmio = RegisterSpace::new();
172
173 mmio.add_register(
175 static_register!(
177 ty: u8,
178 offset: 0x00,
179 value: XHCI_CAPLENGTH, ),
181 );
182 mmio.add_register(
183 static_register!(
185 ty: u16,
186 offset: 0x02,
187 value: 0x0110,),
189 );
190 mmio.add_register(
191 static_register!(
193 ty: u32,
194 offset: 0x04,
195 value: 0x10000110, ),
197 );
198
199 mmio.add_register(
200 static_register!(
202 ty: u32,
203 offset: 0x08,
204 value: 0xf0,
207 ),
208 );
209
210 mmio.add_register(
211 static_register!(
213 ty: u32,
214 offset: 0x0c,
215
216 value: 0x07FF000A,
221 ),
222 );
223
224 mmio.add_register(
225 static_register!(
227 ty: u32,
228 offset: 0x10,
229 value: 0x30000501 | (MAX_PSA_SIZE << HCCPARAMS1_MAX_PSA_SIZE_OFFSET),
233 ),
234 );
235 mmio.add_register(
236 static_register!(
238 ty: u32,
239 offset: 0x14,
240 value: XHCI_DBOFF, ),
242 );
243
244 mmio.add_register(
245 static_register!(
247 ty: u32,
248 offset: 0x18,
249 value: XHCI_RTSOFF, ),
251 );
252
253 mmio.add_register(
254 static_register!(
256 ty: u32,
257 offset: 0x1c,
258 value: 0,
259 ),
260 );
261 let usbcmd = register!(
265 name: "usbcmd",
266 ty: u32,
267 offset: 0x20,
268 reset_value: 0,
269 guest_writeable_mask: 0x00002F0F,
270 guest_write_1_to_clear_mask: 0,
271 );
272 mmio.add_register(usbcmd.clone());
273
274 let usbsts = register!(
275 name: "usbsts",
276 ty: u32,
277 offset: 0x24,
278 reset_value: 0x00000001,
279 guest_writeable_mask: 0x0000041C,
280 guest_write_1_to_clear_mask: 0x0000041C,
281 );
282 mmio.add_register(usbsts.clone());
283
284 mmio.add_register(
285 static_register!(
287 ty: u32,
288 offset: 0x28,
289 value: 0x00000001,
290 ),
291 );
292
293 let dnctrl = register!(
294 name: "dnctrl",
295 ty: u32,
296 offset: 0x34,
297 reset_value: 0,
298 guest_writeable_mask: 0x0000FFFF,
299 guest_write_1_to_clear_mask: 0,
300 );
301 mmio.add_register(dnctrl.clone());
302
303 let crcr = register!(
304 name: "crcr",
305 ty: u64,
306 offset: 0x38,
307 reset_value: 9,
308 guest_writeable_mask: 0xFFFFFFFFFFFFFFC7,
309 guest_write_1_to_clear_mask: 0,
310 );
311 mmio.add_register(crcr.clone());
312
313 let dcbaap = register!(
314 name: "dcbaap",
315 ty: u64,
316 offset: 0x50,
317 reset_value: 0x0,
318 guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
319 guest_write_1_to_clear_mask: 0,
320 );
321 mmio.add_register(dcbaap.clone());
322
323 let config = register!(
324 name: "config",
325 ty: u64,
326 offset: 0x58,
327 reset_value: 0,
328 guest_writeable_mask: 0x0000003F,
329 guest_write_1_to_clear_mask: 0,
330 );
331 mmio.add_register(config.clone());
332
333 let portsc = register_array!(
334 name: "portsc",
335 ty: u32,
336 cnt: MAX_PORTS,
337 base_offset: 0x420,
338 stride: 16,
339 reset_value: 0x000002A0,
340 guest_writeable_mask: 0x8EFFC3F2,
341 guest_write_1_to_clear_mask: 0x00FE0002,);
342 mmio.add_register_array(&portsc);
343
344 mmio.add_register_array(®ister_array!(
346 name: "portpmsc",
347 ty: u32,
348 cnt: MAX_PORTS,
349 base_offset: 0x424,
350 stride: 16,
351 reset_value: 0,
352 guest_writeable_mask: 0x0001FFFF,
353 guest_write_1_to_clear_mask: 0,));
354
355 mmio.add_register_array(®ister_array!(
357 name: "portli",
358 ty: u32,
359 cnt: MAX_PORTS,
360 base_offset: 0x428,
361 stride: 16,
362 reset_value: 0,
363 guest_writeable_mask: 0,
364 guest_write_1_to_clear_mask: 0,));
365
366 mmio.add_register_array(®ister_array!(
368 name: "porthlpmc",
369 ty: u32,
370 cnt: MAX_PORTS,
371 base_offset: 0x42c,
372 stride: 16,
373 reset_value: 0,
374 guest_writeable_mask: 0x00003FFF,
375 guest_write_1_to_clear_mask: 0,));
376
377 let doorbells = register_array!(
378 name: "doorbell",
379 ty: u32,
380 cnt: MAX_SLOTS + 1, base_offset: 0x2000,
382 stride: 4,
383 reset_value: 0,
384 guest_writeable_mask: 0xFFFF00FF,
385 guest_write_1_to_clear_mask: 0,);
386 mmio.add_register_array(&doorbells);
387
388 mmio.add_register(
391 static_register!(
393 ty: u32,
394 offset: 0x3000,
395 value: 0, ),
397 );
398
399 let iman = register!(
402 name: "iman",
403 ty: u32,
404 offset: 0x3020,
405 reset_value: 0,
406 guest_writeable_mask: 0x00000003,
407 guest_write_1_to_clear_mask: 0x00000001,);
408 mmio.add_register(iman.clone());
409
410 let imod = register!(
411 name: "imod",
412 ty: u32,
413 offset: 0x3024,
414 reset_value: 0x00000FA0,
415 guest_writeable_mask: 0xFFFFFFFF,
416 guest_write_1_to_clear_mask: 0,);
417 mmio.add_register(imod.clone());
418
419 let erstsz = register!(
420 name: "erstsz",
421 ty: u32,
422 offset: 0x3028,
423 reset_value: 0,
424 guest_writeable_mask: 0x0000FFFF,
425 guest_write_1_to_clear_mask: 0,);
426 mmio.add_register(erstsz.clone());
427
428 let erstba = register!(
429 name: "erstba",
430 ty: u64,
431 offset: 0x3030,
432 reset_value: 0,
433 guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
434 guest_write_1_to_clear_mask: 0,);
435 mmio.add_register(erstba.clone());
436
437 let erdp = register!(
438 name: "erdp",
439 ty: u64,
440 offset: 0x3038,
441 reset_value: 0,
442 guest_writeable_mask: 0xFFFFFFFFFFFFFFFF,
443 guest_write_1_to_clear_mask: 0x0000000000000008,);
444 mmio.add_register(erdp.clone());
445
446 let xhci_regs = XhciRegs {
449 usbcmd,
450 usbsts,
451 dnctrl,
452 crcr,
453 dcbaap,
454 config,
455 portsc,
456 doorbells,
457 iman,
458 imod,
459 erstsz,
460 erstba,
461 erdp,
462 };
463
464 mmio.add_register(
473 static_register!(
475 ty: u32,
476 offset: 0xc000,
477 value: 0x02004002,
481 ),
482 );
483 mmio.add_register(
484 static_register!(
486 ty: u32,
487 offset: 0xc004,
488 value: 0x20425355, ),
490 );
491 mmio.add_register(
492 static_register!(
494 ty: u32,
495 offset: 0xc008,
496 value: 0x00000801, ),
498 );
499
500 mmio.add_register(
501 static_register!(
503 ty: u32,
504 offset: 0xc00c,
505 value: 0,
508 ),
509 );
510
511 mmio.add_register(
512 static_register!(
514 ty: u32,
515 offset: 0xc100,
516 value: 0x03000002,
520 ),
521 );
522 mmio.add_register(
523 static_register!(
525 ty: u32,
526 offset: 0xc104,
527 value: 0x20425355, ),
529 );
530 mmio.add_register(
531 static_register!(
533 ty: u32,
534 offset: 0xc108,
535 value: 0x00000809, ),
537 );
538
539 mmio.add_register(
540 static_register!(
542 ty: u32,
543 offset: 0xc10c,
544 value: 0,
547 ),
548 );
549
550 (mmio, xhci_regs)
553}