devices/usb/xhci/
xhci_regs.rs

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
5use crate::register_space::Register;
6use crate::register_space::RegisterSpace;
7
8/// Max interrupter number.
9pub const MAX_INTERRUPTER: u8 = 1;
10/// For port configuration, see register HCSPARAMS1, spcap1.3 and spcap2.3.
11pub const MAX_SLOTS: u8 = 16;
12
13/// Usb 2 ports start from port number 0.
14pub const USB2_PORTS_START: u8 = 0;
15/// Last usb 2 ports is 7.
16pub const USB2_PORTS_END: u8 = 8;
17/// Usb 3 ports start from port number 8.
18pub const USB3_PORTS_START: u8 = 8;
19/// Last usb 3 port is 15.
20pub 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.
24pub const MAX_PORTS: u8 = USB3_PORTS_END;
25
26/// Cap register length.
27pub const XHCI_CAPLENGTH: u8 = 0x20;
28/// Offset for doorbell register.
29pub const XHCI_DBOFF: u32 = 0x00002000;
30/// Offset for RTs.
31pub const XHCI_RTSOFF: u32 = 0x00003000;
32
33/// Bitmask for the usbcmd register, see spec 5.4.1.
34pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
35/// Bitmask for the usbcmd register, see spec 5.4.1.
36pub const USB_CMD_RESET: u32 = 1u32 << 1;
37/// Bitmask for the usbcmd register, see spec 5.4.1.
38pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
39
40/// Bitmask for the usbsts register, see spec 5.4.2.
41pub const USB_STS_HALTED: u32 = 1u32 << 0;
42/// Bitmask for the usbsts register, see spec 5.4.2.
43pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
44/// Bitmask for the usbsts register, see spec 5.4.2.
45pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
46/// Bitmask for the usbsts register, see spec 5.4.2.
47pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
48/// Bitmask for the usbsts register, see spec 5.4.2.
49pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
50
51/// Bitmask for the crcr register, see spec 5.4.5.
52pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
53/// Bitmask for the crcr register, see spec 5.4.5.
54pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
55/// Bitmask for the crcr register, see spec 5.4.5.
56pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
57/// Bitmask for the crcr register, see spec 5.4.5.
58pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
59/// Bitmask for the crcr register, see spec 5.4.5.
60pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
61
62/// Bitmask for portsc register, see spec 5.4.8.
63pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
64/// Bitmask for portsc register, see spec 5.4.8.
65pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
66/// Bitmask for portsc register, see spec 5.4.8.
67pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
68/// Bitmask for portsc register, see spec 5.4.8.
69pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
70/// Bitmask for portsc register, see spec 5.4.8.
71pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
72/// Bitmask for portsc register, see spec 5.4.8.
73pub const PORTSC_PORT_SPEED_MASK: u32 = 0x00003C00;
74/// Bitmask for portsc register, see spec 5.4.8.
75pub const PORTSC_PORT_SPEED_SHIFT: u32 = 10;
76/// Bitmask for portsc register, see spec 5.4.8.
77pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
78/// Bitmask for portsc register, see spec 5.4.8.
79pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
80/// Bitmask for portsc register, see spec 5.4.8.
81pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
82/// Bitmask for portsc register, see spec 5.4.8.
83pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
84/// Bitmask for portsc register, see spec 5.4.8.
85pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
86
87/// Bitmask for iman registers, see spec 5.5.2.1.
88pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
89/// Bitmask for iman registers, see spec 5.5.2.1.
90pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
91/// Bitmask for iman registers, see spec 5.5.2.1.
92pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
93
94/// Bitmask for imod registers, see spec 5.5.2.2.
95pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
96/// Bitmask for imod registers, see spec 5.5.2.2.
97pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
98
99/// Bitmask for erstsz registers, see 5.5.2.3.
100pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
101
102/// Bitmask for erstba registers, see 5.5.2.3.
103pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
104
105/// Bitmask for erdp registers, see 5.5.2.3.
106pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
107/// Bitmask for erdp registers, see 5.5.2.3.
108pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
109/// Bitmask for erdp registers, see 5.5.2.3.
110pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
111
112/// Bitmask for doorbell registers.
113pub const DOORBELL_TARGET: u32 = 0xFF;
114/// Offset of stream id.
115pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
116
117/// Bitmask for structural parameter registers.
118pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
119/// Offset of max interrupters.
120pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
121/// Mask to get max slots.
122pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
123
124/// Bitmask for extended capabilities registers.
125pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
126/// Offset of port count.
127pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
128
129/// Bitmask for hccparams1 register, see spec 5.3.6.
130pub const HCCPARAMS1_MAX_PSA_SIZE_OFFSET: u32 = 12;
131/// Maximum primary stream array size, support up to 16 (2^(MAX_PSA_SIZE+1)) streams
132pub const MAX_PSA_SIZE: u32 = 3;
133
134/// Helper function for validating slot_id.
135pub 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.
141pub 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)
146pub 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.
152pub 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.
170pub 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}