Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/usb/xhci/xhci_regs.rs
5394 views
1
// Copyright 2018 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use crate::register_space::Register;
6
use crate::register_space::RegisterSpace;
7
8
/// Max interrupter number.
9
pub const MAX_INTERRUPTER: u8 = 1;
10
/// For port configuration, see register HCSPARAMS1, spcap1.3 and spcap2.3.
11
pub const MAX_SLOTS: u8 = 16;
12
13
/// Usb 2 ports start from port number 0.
14
pub const USB2_PORTS_START: u8 = 0;
15
/// Last usb 2 ports is 7.
16
pub const USB2_PORTS_END: u8 = 8;
17
/// Usb 3 ports start from port number 8.
18
pub const USB3_PORTS_START: u8 = 8;
19
/// Last usb 3 port is 15.
20
pub const USB3_PORTS_END: u8 = 16;
21
22
/// Max port number. Review the following before changing this:
23
/// HCSPARAMS1, portsc, spcap1.3 and spcap2.3.
24
pub const MAX_PORTS: u8 = USB3_PORTS_END;
25
26
/// Cap register length.
27
pub const XHCI_CAPLENGTH: u8 = 0x20;
28
/// Offset for doorbell register.
29
pub const XHCI_DBOFF: u32 = 0x00002000;
30
/// Offset for RTs.
31
pub const XHCI_RTSOFF: u32 = 0x00003000;
32
33
/// Bitmask for the usbcmd register, see spec 5.4.1.
34
pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
35
/// Bitmask for the usbcmd register, see spec 5.4.1.
36
pub const USB_CMD_RESET: u32 = 1u32 << 1;
37
/// Bitmask for the usbcmd register, see spec 5.4.1.
38
pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
39
40
/// Bitmask for the usbsts register, see spec 5.4.2.
41
pub const USB_STS_HALTED: u32 = 1u32 << 0;
42
/// Bitmask for the usbsts register, see spec 5.4.2.
43
pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
44
/// Bitmask for the usbsts register, see spec 5.4.2.
45
pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
46
/// Bitmask for the usbsts register, see spec 5.4.2.
47
pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
48
/// Bitmask for the usbsts register, see spec 5.4.2.
49
pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
50
51
/// Bitmask for the crcr register, see spec 5.4.5.
52
pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
53
/// Bitmask for the crcr register, see spec 5.4.5.
54
pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
55
/// Bitmask for the crcr register, see spec 5.4.5.
56
pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
57
/// Bitmask for the crcr register, see spec 5.4.5.
58
pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
59
/// Bitmask for the crcr register, see spec 5.4.5.
60
pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
61
62
/// Bitmask for portsc register, see spec 5.4.8.
63
pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
64
/// Bitmask for portsc register, see spec 5.4.8.
65
pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
66
/// Bitmask for portsc register, see spec 5.4.8.
67
pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
68
/// Bitmask for portsc register, see spec 5.4.8.
69
pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
70
/// Bitmask for portsc register, see spec 5.4.8.
71
pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
72
/// Bitmask for portsc register, see spec 5.4.8.
73
pub const PORTSC_PORT_SPEED_MASK: u32 = 0x00003C00;
74
/// Bitmask for portsc register, see spec 5.4.8.
75
pub const PORTSC_PORT_SPEED_SHIFT: u32 = 10;
76
/// Bitmask for portsc register, see spec 5.4.8.
77
pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
78
/// Bitmask for portsc register, see spec 5.4.8.
79
pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
80
/// Bitmask for portsc register, see spec 5.4.8.
81
pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
82
/// Bitmask for portsc register, see spec 5.4.8.
83
pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
84
/// Bitmask for portsc register, see spec 5.4.8.
85
pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
86
87
/// Bitmask for iman registers, see spec 5.5.2.1.
88
pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
89
/// Bitmask for iman registers, see spec 5.5.2.1.
90
pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
91
/// Bitmask for iman registers, see spec 5.5.2.1.
92
pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
93
94
/// Bitmask for imod registers, see spec 5.5.2.2.
95
pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
96
/// Bitmask for imod registers, see spec 5.5.2.2.
97
pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
98
99
/// Bitmask for erstsz registers, see 5.5.2.3.
100
pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
101
102
/// Bitmask for erstba registers, see 5.5.2.3.
103
pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
104
105
/// Bitmask for erdp registers, see 5.5.2.3.
106
pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
107
/// Bitmask for erdp registers, see 5.5.2.3.
108
pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
109
/// Bitmask for erdp registers, see 5.5.2.3.
110
pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
111
112
/// Bitmask for doorbell registers.
113
pub const DOORBELL_TARGET: u32 = 0xFF;
114
/// Offset of stream id.
115
pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
116
117
/// Bitmask for structural parameter registers.
118
pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
119
/// Offset of max interrupters.
120
pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
121
/// Mask to get max slots.
122
pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
123
124
/// Bitmask for extended capabilities registers.
125
pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
126
/// Offset of port count.
127
pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
128
129
/// Bitmask for hccparams1 register, see spec 5.3.6.
130
pub const HCCPARAMS1_MAX_PSA_SIZE_OFFSET: u32 = 12;
131
/// Maximum primary stream array size, support up to 16 (2^(MAX_PSA_SIZE+1)) streams
132
pub const MAX_PSA_SIZE: u32 = 3;
133
134
/// Helper function for validating slot_id.
135
pub fn valid_slot_id(slot_id: u8) -> bool {
136
// slot id count from 1.
137
slot_id > 0 && slot_id <= MAX_SLOTS
138
}
139
140
/// Helper function for validating max_pstreams.
141
pub fn valid_max_pstreams(max_pstreams: u8) -> bool {
142
max_pstreams <= MAX_PSA_SIZE as u8
143
}
144
145
/// Helper function for validating stream_id. (assuming Linear Stream Array)
146
pub fn valid_stream_id(stream_id: u16) -> bool {
147
// stream id 0 is reserved
148
stream_id > 0 && stream_id < (1 << (MAX_PSA_SIZE + 1))
149
}
150
151
/// XhciRegs hold all xhci registers.
152
pub 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
168
/// This function returns mmio space definition for xhci. See Xhci spec chapter 5
169
/// for details.
170
pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
171
let mut mmio = RegisterSpace::new();
172
173
/* Host Controller Capability Registers */
174
mmio.add_register(
175
// CAPLENGTH
176
static_register!(
177
ty: u8,
178
offset: 0x00,
179
value: XHCI_CAPLENGTH, // Operation register start at offset 0x20
180
),
181
);
182
mmio.add_register(
183
// HCIVERSION
184
static_register!(
185
ty: u16,
186
offset: 0x02,
187
value: 0x0110,// Revision 1.1
188
),
189
);
190
mmio.add_register(
191
// HCSPARAMS1
192
static_register!(
193
ty: u32,
194
offset: 0x04,
195
value: 0x10000110, // max_slots = 16, max_interrupters = 1, max_ports = 16
196
),
197
);
198
199
mmio.add_register(
200
// HCSPARAMS2
201
static_register!(
202
ty: u32,
203
offset: 0x08,
204
// Maximum number of event ring segment table entries = 32k
205
// No scratchpad buffers.
206
value: 0xf0,
207
),
208
);
209
210
mmio.add_register(
211
// HCSPARAM3
212
static_register!(
213
ty: u32,
214
offset: 0x0c,
215
216
// Exit latencies for U1 (standby with fast exit) and U2 (standby with
217
// slower exit) power states. We use the max values:
218
// - U1 to U0: < 10 us
219
// - U2 to U1: < 2047 us
220
value: 0x07FF000A,
221
),
222
);
223
224
mmio.add_register(
225
// HCCPARAMS1
226
static_register!(
227
ty: u32,
228
offset: 0x10,
229
// Supports 64 bit addressing
230
// Max primary stream array size = 3 (support up to 16 streams).
231
// Extended capabilities pointer = 0xC000 offset from base.
232
value: 0x30000501 | (MAX_PSA_SIZE << HCCPARAMS1_MAX_PSA_SIZE_OFFSET),
233
),
234
);
235
mmio.add_register(
236
// DBOFF
237
static_register!(
238
ty: u32,
239
offset: 0x14,
240
value: XHCI_DBOFF, // Doorbell array offset 0x2000 from base.
241
),
242
);
243
244
mmio.add_register(
245
// RTSOFF
246
static_register!(
247
ty: u32,
248
offset: 0x18,
249
value: XHCI_RTSOFF, // Runtime registers offset 0x3000 from base.
250
),
251
);
252
253
mmio.add_register(
254
// HCCPARAMS2
255
static_register!(
256
ty: u32,
257
offset: 0x1c,
258
value: 0,
259
),
260
);
261
/* End of Host Controller Capability Registers */
262
263
/* Host Controller Operational Registers */
264
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
// Pagesize
286
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
// Portpmsc.
345
mmio.add_register_array(&register_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
// Portli
356
mmio.add_register_array(&register_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
// Porthlpmc
367
mmio.add_register_array(&register_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, // Must be equal to max_slots + 1
381
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
/* Runtime Registers */
389
390
mmio.add_register(
391
// mfindex
392
static_register!(
393
ty: u32,
394
offset: 0x3000,
395
value: 0, // 4 ports starting at port 5
396
),
397
);
398
399
/* Reg Array for interrupters */
400
// Although the following should be register arrays, we only have one interrupter.
401
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
/* End of Runtime Registers */
447
448
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
/* End of Host Controller Operational Registers */
465
466
/* Extended Capability Registers */
467
468
// Extended capability registers. Base offset defined by hccparams1.
469
// Each set of 4 registers represents a "Supported Protocol" extended
470
// capability. The first capability indicates that ports 1-8 are USB 2.0. There is no USB 3.0
471
// port for now. See xHCI spec 7.1 & 7.2 for more details.
472
mmio.add_register(
473
// spcap 1.1
474
static_register!(
475
ty: u32,
476
offset: 0xc000,
477
// "Supported Protocol" capability.
478
// Next capability starts after 0x40 dwords.
479
// USB 2.0. Revision 2.0.
480
value: 0x02004002,
481
),
482
);
483
mmio.add_register(
484
// spcap 1.2
485
static_register!(
486
ty: u32,
487
offset: 0xc004,
488
value: 0x20425355, // Name string = "USB "
489
),
490
);
491
mmio.add_register(
492
// spcap 1.3
493
static_register!(
494
ty: u32,
495
offset: 0xc008,
496
value: 0x00000801, // 8 ports starting at port 1. See USB2_PORTS_START and USB2_PORTS_END.
497
),
498
);
499
500
mmio.add_register(
501
// spcap 1.4
502
static_register!(
503
ty: u32,
504
offset: 0xc00c,
505
// The specification says that this shall be set to 0.
506
// Section 7.2.2.1.4.
507
value: 0,
508
),
509
);
510
511
mmio.add_register(
512
// spcap 2.1
513
static_register!(
514
ty: u32,
515
offset: 0xc100,
516
// "Supported Protocol" capability.
517
// Not next capability.
518
// USB 3.0. Revision 2.0.
519
value: 0x03000002,
520
),
521
);
522
mmio.add_register(
523
// spcap 2.2
524
static_register!(
525
ty: u32,
526
offset: 0xc104,
527
value: 0x20425355, // Name string = "USB "
528
),
529
);
530
mmio.add_register(
531
// spcap 2.3
532
static_register!(
533
ty: u32,
534
offset: 0xc108,
535
value: 0x00000809, // 8 ports starting at port 9. See USB3_PORTS_START and USB3_PORTS_END.
536
),
537
);
538
539
mmio.add_register(
540
// spcap 2.4
541
static_register!(
542
ty: u32,
543
offset: 0xc10c,
544
// The specification says that this shall be set to 0.
545
// Section 7.2.2.1.4.
546
value: 0,
547
),
548
);
549
550
/* End of Host Controller Operational Registers */
551
552
(mmio, xhci_regs)
553
}
554
555