• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 The Chromium OS Authors. All rights reserved.
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, RegisterSpace};
6 
7 /// Max interrupter number.
8 pub const MAX_INTERRUPTER: u8 = 1;
9 /// For port configuration, see register HCSPARAMS1, spcap1.3 and spcap2.3.
10 pub const MAX_SLOTS: u8 = 16;
11 
12 /// Usb 2 ports start from port number 0.
13 pub const USB2_PORTS_START: u8 = 0;
14 /// Last usb 2 ports is 7.
15 pub const USB2_PORTS_END: u8 = 8;
16 /// Usb 3 ports start from port number 8.
17 pub const USB3_PORTS_START: u8 = 8;
18 /// Last usb 3 port is 15.
19 pub const USB3_PORTS_END: u8 = 16;
20 
21 /// Max port number. Review the following before changing this:
22 ///     HCSPARAMS1, portsc, spcap1.3 and spcap2.3.
23 pub const MAX_PORTS: u8 = USB3_PORTS_END;
24 
25 /// Cap register length.
26 pub const XHCI_CAPLENGTH: u8 = 0x20;
27 /// Offset for doorbell register.
28 pub const XHCI_DBOFF: u32 = 0x00002000;
29 /// Offset for RTs.
30 pub const XHCI_RTSOFF: u32 = 0x00003000;
31 
32 /// Bitmask for the usbcmd register, see spec 5.4.1.
33 pub const USB_CMD_RUNSTOP: u32 = 1u32 << 0;
34 /// Bitmask for the usbcmd register, see spec 5.4.1.
35 pub const USB_CMD_RESET: u32 = 1u32 << 1;
36 /// Bitmask for the usbcmd register, see spec 5.4.1.
37 pub const USB_CMD_INTERRUPTER_ENABLE: u32 = 1u32 << 2;
38 
39 /// Bitmask for the usbsts register, see spec 5.4.2.
40 pub const USB_STS_HALTED: u32 = 1u32 << 0;
41 /// Bitmask for the usbsts register, see spec 5.4.2.
42 pub const USB_STS_EVENT_INTERRUPT: u32 = 1u32 << 3;
43 /// Bitmask for the usbsts register, see spec 5.4.2.
44 pub const USB_STS_PORT_CHANGE_DETECT: u32 = 1u32 << 4;
45 /// Bitmask for the usbsts register, see spec 5.4.2.
46 pub const USB_STS_CONTROLLER_NOT_READY: u32 = 1u32 << 11;
47 /// Bitmask for the usbsts register, see spec 5.4.2.
48 pub const USB_STS_SET_TO_CLEAR_MASK: u32 = 0x0000041C;
49 
50 /// Bitmask for the crcr register, see spec 5.4.5.
51 pub const CRCR_RING_CYCLE_STATE: u64 = 1u64 << 0;
52 /// Bitmask for the crcr register, see spec 5.4.5.
53 pub const CRCR_COMMAND_STOP: u64 = 1u64 << 1;
54 /// Bitmask for the crcr register, see spec 5.4.5.
55 pub const CRCR_COMMAND_ABORT: u64 = 1u64 << 2;
56 /// Bitmask for the crcr register, see spec 5.4.5.
57 pub const CRCR_COMMAND_RING_RUNNING: u64 = 1u64 << 3;
58 /// Bitmask for the crcr register, see spec 5.4.5.
59 pub const CRCR_COMMAND_RING_POINTER: u64 = 0xFFFFFFFFFFFFFFC0;
60 
61 /// Bitmask for portsc register, see spec 5.4.8.
62 pub const PORTSC_CURRENT_CONNECT_STATUS: u32 = 1u32 << 0;
63 /// Bitmask for portsc register, see spec 5.4.8.
64 pub const PORTSC_PORT_ENABLED: u32 = 1u32 << 1;
65 /// Bitmask for portsc register, see spec 5.4.8.
66 pub const PORTSC_PORT_RESET: u32 = 1u32 << 4;
67 /// Bitmask for portsc register, see spec 5.4.8.
68 pub const PORTSC_PORT_LINK_STATE_MASK: u32 = 0x000001E0;
69 /// Bitmask for portsc register, see spec 5.4.8.
70 pub const PORTSC_PORT_POWER: u32 = 1u32 << 9;
71 /// Bitmask for portsc register, see spec 5.4.8.
72 pub const PORTSC_CONNECT_STATUS_CHANGE: u32 = 1u32 << 17;
73 /// Bitmask for portsc register, see spec 5.4.8.
74 pub const PORTSC_PORT_ENABLED_DISABLED_CHANGE: u32 = 1u32 << 18;
75 /// Bitmask for portsc register, see spec 5.4.8.
76 pub const PORTSC_PORT_RESET_CHANGE: u32 = 1u32 << 21;
77 /// Bitmask for portsc register, see spec 5.4.8.
78 pub const PORTSC_WARM_PORT_RESET: u32 = 1u32 << 31;
79 /// Bitmask for portsc register, see spec 5.4.8.
80 pub const PORTSC_SET_TO_CLEAR_MASK: u32 = 0x00FE0002;
81 
82 /// Bitmask for iman registers, see spec 5.5.2.1.
83 pub const IMAN_INTERRUPT_PENDING: u32 = 1u32 << 0;
84 /// Bitmask for iman registers, see spec 5.5.2.1.
85 pub const IMAN_INTERRUPT_ENABLE: u32 = 1u32 << 1;
86 /// Bitmask for iman registers, see spec 5.5.2.1.
87 pub const IMAN_SET_TO_CLEAR_MASK: u32 = 0x00000001;
88 
89 /// Bitmask for imod registers, see spec 5.5.2.2.
90 pub const IMOD_INTERRUPT_MODERATION_INTERVAL: u32 = 0xFFFF;
91 /// Bitmask for imod registers, see spec 5.5.2.2.
92 pub const IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET: u8 = 16;
93 
94 /// Bitmask for erstsz registers, see 5.5.2.3.
95 pub const ERSTSZ_SEGMENT_TABLE_SIZE: u32 = 0xFFFF;
96 
97 /// Bitmask for erstba registers, see 5.5.2.3.
98 pub const ERSTBA_SEGMENT_TABLE_BASE_ADDRESS: u64 = 0xFFFFFFFFFFFFFFC0;
99 
100 /// Bitmask for erdp registers, see 5.5.2.3.
101 pub const ERDP_EVENT_HANDLER_BUSY: u64 = 1u64 << 3;
102 /// Bitmask for erdp registers, see 5.5.2.3.
103 pub const ERDP_EVENT_RING_DEQUEUE_POINTER: u64 = 0xFFFFFFFFFFFFFFF0;
104 /// Bitmask for erdp registers, see 5.5.2.3.
105 pub const ERDP_SET_TO_CLEAR_MASK: u64 = 0x0000000000000008;
106 
107 /// Bitmask for doorbell registers.
108 pub const DOORBELL_TARGET: u32 = 0xFF;
109 /// Offset of stream id.
110 pub const DOORBELL_STREAM_ID_OFFSET: u32 = 16;
111 
112 /// Bitmask for structural parameter registers.
113 pub const HCSPARAMS1_MAX_INTERRUPTERS_MASK: u32 = 0x7FF00;
114 /// Offset of max interrupters.
115 pub const HCSPARAMS1_MAX_INTERRUPTERS_OFFSET: u32 = 8;
116 /// Mask to get max slots.
117 pub const HCSPARAMS1_MAX_SLOTS_MASK: u32 = 0xFF;
118 
119 /// Bitmask for extended capabilities registers.
120 pub const SPCAP_PORT_COUNT_MASK: u32 = 0xFF00;
121 /// Offset of port count.
122 pub const SPCAP_PORT_COUNT_OFFSET: u32 = 8;
123 
124 /// Helper function for validating slot_id.
valid_slot_id(slot_id: u8) -> bool125 pub fn valid_slot_id(slot_id: u8) -> bool {
126     // slot id count from 1.
127     slot_id > 0 && slot_id <= MAX_SLOTS
128 }
129 
130 /// XhciRegs hold all xhci registers.
131 pub struct XhciRegs {
132     pub usbcmd: Register<u32>,
133     pub usbsts: Register<u32>,
134     pub dnctrl: Register<u32>,
135     pub crcr: Register<u64>,
136     pub dcbaap: Register<u64>,
137     pub config: Register<u64>,
138     pub portsc: Vec<Register<u32>>,
139     pub doorbells: Vec<Register<u32>>,
140     pub iman: Register<u32>,
141     pub imod: Register<u32>,
142     pub erstsz: Register<u32>,
143     pub erstba: Register<u64>,
144     pub erdp: Register<u64>,
145 }
146 
147 /// This function returns mmio space definition for xhci. See Xhci spec chapter 5
148 /// for details.
init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs)149 pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
150     let mut mmio = RegisterSpace::new();
151 
152     /* Host Controller Capability Registers */
153     mmio.add_register(
154         // CAPLENGTH
155         static_register!(
156         ty: u8,
157         offset: 0x00,
158         value: XHCI_CAPLENGTH, // Operation register start at offset 0x20
159         ),
160     );
161     mmio.add_register(
162         // HCIVERSION
163         static_register!(
164         ty: u16,
165         offset: 0x02,
166         value: 0x0110,// Revision 1.1
167         ),
168     );
169     mmio.add_register(
170         // HCSPARAMS1
171         static_register!(
172         ty: u32,
173         offset: 0x04,
174         value: 0x10000110, // max_slots = 16, max_interrupters = 1, max_ports = 16
175         ),
176     );
177 
178     mmio.add_register(
179         // HCSPARAMS2
180         static_register!(
181         ty: u32,
182         offset: 0x08,
183         // Maximum number of event ring segment table entries = 32k
184         // No scratchpad buffers.
185         value: 0xf0,
186         ),
187     );
188 
189     mmio.add_register(
190         // HCSPARAM3
191         static_register!(
192         ty: u32,
193         offset: 0x0c,
194 
195         // Exit latencies for U1 (standby with fast exit) and U2 (standby with
196         // slower exit) power states. We use the max values:
197         // - U1 to U0: < 10 us
198         // - U2 to U1: < 2047 us
199         value: 0x07FF000A,
200         ),
201     );
202 
203     mmio.add_register(
204         // HCCPARAMS1
205         static_register!(
206         ty: u32,
207         offset: 0x10,
208         // Supports 64 bit addressing
209         // Max primary stream array size = 0 (streams not supported).
210         // Extended capabilities pointer = 0xC000 offset from base.
211         value: 0x30000501,
212         ),
213     );
214     mmio.add_register(
215         // DBOFF
216         static_register!(
217         ty: u32,
218         offset: 0x14,
219         value: XHCI_DBOFF, // Doorbell array offset 0x2000 from base.
220         ),
221     );
222 
223     mmio.add_register(
224         // RTSOFF
225         static_register!(
226         ty: u32,
227         offset: 0x18,
228         value: XHCI_RTSOFF, // Runtime registers offset 0x3000 from base.
229         ),
230     );
231 
232     mmio.add_register(
233         // HCCPARAMS2
234         static_register!(
235         ty: u32,
236         offset: 0x1c,
237         value: 0,
238         ),
239     );
240     /* End of Host Controller Capability Registers */
241 
242     /* Host Controller Operational Registers */
243     let usbcmd = register!(
244         name: "usbcmd",
245         ty: u32,
246         offset: 0x20,
247         reset_value: 0,
248         guest_writeable_mask: 0x00002F0F,
249         guest_write_1_to_clear_mask: 0,
250     );
251     mmio.add_register(usbcmd.clone());
252 
253     let usbsts = register!(
254         name: "usbsts",
255         ty: u32,
256         offset: 0x24,
257         reset_value: 0x00000001,
258         guest_writeable_mask: 0x0000041C,
259         guest_write_1_to_clear_mask: 0x0000041C,
260     );
261     mmio.add_register(usbsts.clone());
262 
263     mmio.add_register(
264         //  Pagesize
265         static_register!(
266         ty: u32,
267         offset: 0x28,
268         value: 0x00000001,
269         ),
270     );
271 
272     let dnctrl = register!(
273         name: "dnctrl",
274         ty: u32,
275         offset: 0x34,
276         reset_value: 0,
277         guest_writeable_mask: 0x0000FFFF,
278         guest_write_1_to_clear_mask: 0,
279     );
280     mmio.add_register(dnctrl.clone());
281 
282     let crcr = register!(
283         name: "crcr",
284         ty: u64,
285         offset: 0x38,
286         reset_value: 9,
287         guest_writeable_mask: 0xFFFFFFFFFFFFFFC7,
288         guest_write_1_to_clear_mask: 0,
289     );
290     mmio.add_register(crcr.clone());
291 
292     let dcbaap = register!(
293         name: "dcbaap",
294         ty: u64,
295         offset: 0x50,
296         reset_value: 0x0,
297         guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
298         guest_write_1_to_clear_mask: 0,
299     );
300     mmio.add_register(dcbaap.clone());
301 
302     let config = register!(
303         name: "config",
304         ty: u64,
305         offset: 0x58,
306         reset_value: 0,
307         guest_writeable_mask: 0x0000003F,
308         guest_write_1_to_clear_mask: 0,
309     );
310     mmio.add_register(config.clone());
311 
312     let portsc = register_array!(
313         name: "portsc",
314         ty: u32,
315         cnt: MAX_PORTS,
316         base_offset: 0x420,
317         stride: 16,
318         reset_value: 0x000002A0,
319         guest_writeable_mask: 0x8EFFC3F2,
320         guest_write_1_to_clear_mask: 0x00FE0002,);
321     mmio.add_register_array(&portsc);
322 
323     // Portpmsc.
324     mmio.add_register_array(&register_array!(
325             name: "portpmsc",
326             ty: u32,
327             cnt: MAX_PORTS,
328             base_offset: 0x424,
329             stride: 16,
330             reset_value: 0,
331             guest_writeable_mask: 0x0001FFFF,
332             guest_write_1_to_clear_mask: 0,));
333 
334     // Portli
335     mmio.add_register_array(&register_array!(
336             name: "portli",
337             ty: u32,
338             cnt: MAX_PORTS,
339             base_offset: 0x428,
340             stride: 16,
341             reset_value: 0,
342             guest_writeable_mask: 0,
343             guest_write_1_to_clear_mask: 0,));
344 
345     // Porthlpmc
346     mmio.add_register_array(&register_array!(
347             name: "porthlpmc",
348             ty: u32,
349             cnt: MAX_PORTS,
350             base_offset: 0x42c,
351             stride: 16,
352             reset_value: 0,
353             guest_writeable_mask: 0x00003FFF,
354             guest_write_1_to_clear_mask: 0,));
355 
356     let doorbells = register_array!(
357         name: "doorbell",
358         ty: u32,
359         cnt: MAX_SLOTS + 1, //  Must be equal to max_slots + 1
360         base_offset: 0x2000,
361         stride: 4,
362         reset_value: 0,
363         guest_writeable_mask: 0xFFFF00FF,
364         guest_write_1_to_clear_mask: 0,);
365     mmio.add_register_array(&doorbells);
366 
367     /*Runtime Registers */
368 
369     mmio.add_register(
370         // mfindex
371         static_register!(
372         ty: u32,
373         offset: 0x3000,
374         value: 0, // 4 ports starting at port 5
375         ),
376     );
377 
378     /* Reg Array for interrupters */
379     // Although the following should be register arrays, we only have one interrupter.
380     let iman = register!(
381             name: "iman",
382             ty: u32,
383             offset: 0x3020,
384             reset_value: 0,
385             guest_writeable_mask: 0x00000003,
386             guest_write_1_to_clear_mask: 0x00000001,);
387     mmio.add_register(iman.clone());
388 
389     let imod = register!(
390             name: "imod",
391             ty: u32,
392             offset: 0x3024,
393             reset_value: 0x00000FA0,
394             guest_writeable_mask: 0xFFFFFFFF,
395             guest_write_1_to_clear_mask: 0,);
396     mmio.add_register(imod.clone());
397 
398     let erstsz = register!(
399         name: "erstsz",
400         ty: u32,
401         offset: 0x3028,
402         reset_value: 0,
403         guest_writeable_mask: 0x0000FFFF,
404         guest_write_1_to_clear_mask: 0,);
405     mmio.add_register(erstsz.clone());
406 
407     let erstba = register!(
408         name: "erstba",
409         ty: u64,
410         offset: 0x3030,
411         reset_value: 0,
412         guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
413         guest_write_1_to_clear_mask: 0,);
414     mmio.add_register(erstba.clone());
415 
416     let erdp = register!(
417         name: "erdp",
418         ty: u64,
419         offset: 0x3038,
420         reset_value: 0,
421         guest_writeable_mask: 0xFFFFFFFFFFFFFFFF,
422         guest_write_1_to_clear_mask: 0x0000000000000008,);
423     mmio.add_register(erdp.clone());
424 
425     /* End of Runtime Registers */
426 
427     let xhci_regs = XhciRegs {
428         usbcmd,
429         usbsts,
430         dnctrl,
431         crcr,
432         dcbaap,
433         config,
434         portsc,
435         doorbells,
436         iman,
437         imod,
438         erstsz,
439         erstba,
440         erdp,
441     };
442 
443     /* End of Host Controller Operational Registers */
444 
445     /* Extended Capability Registers */
446 
447     // Extended capability registers. Base offset defined by hccparams1.
448     // Each set of 4 registers represents a "Supported Protocol" extended
449     // capability.  The first capability indicates that ports 1-8 are USB 2.0. There is no USB 3.0
450     // port for now. See xHCI spec 7.1 & 7.2 for more details.
451     mmio.add_register(
452         // spcap 1.1
453         static_register!(
454         ty: u32,
455         offset: 0xc000,
456         // "Supported Protocol" capability.
457         // Next capability starts after 0x40 dwords.
458         // USB 2.0. Revision 2.0.
459         value: 0x02004002,
460         ),
461     );
462     mmio.add_register(
463         // spcap 1.2
464         static_register!(
465         ty: u32,
466         offset: 0xc004,
467         value: 0x20425355, // Name string = "USB "
468         ),
469     );
470     mmio.add_register(
471         // spcap 1.3
472         static_register!(
473         ty: u32,
474         offset: 0xc008,
475         value: 0x00000801, // 8 ports starting at port 1. See USB2_PORTS_START and USB2_PORTS_END.
476         ),
477     );
478 
479     mmio.add_register(
480         // spcap 1.4
481         static_register!(
482         ty: u32,
483         offset: 0xc00c,
484         // The specification says that this shall be set to 0.
485         // Section 7.2.2.1.4.
486         value: 0,
487         ),
488     );
489 
490     mmio.add_register(
491         // spcap 2.1
492         static_register!(
493         ty: u32,
494         offset: 0xc100,
495         // "Supported Protocol" capability.
496         // Not next capability.
497         // USB 3.0. Revision 2.0.
498         value: 0x03000002,
499         ),
500     );
501     mmio.add_register(
502         // spcap 2.2
503         static_register!(
504         ty: u32,
505         offset: 0xc104,
506         value: 0x20425355, // Name string = "USB "
507         ),
508     );
509     mmio.add_register(
510         // spcap 2.3
511         static_register!(
512         ty: u32,
513         offset: 0xc108,
514         value: 0x00000809, // 8 ports starting at port 9. See USB3_PORTS_START and USB3_PORTS_END.
515         ),
516     );
517 
518     mmio.add_register(
519         // spcap 2.4
520         static_register!(
521         ty: u32,
522         offset: 0xc10c,
523         // The specification says that this shall be set to 0.
524         // Section 7.2.2.1.4.
525         value: 0,
526         ),
527     );
528 
529     /* End of Host Controller Operational Registers */
530 
531     (mmio, xhci_regs)
532 }
533