• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /// Helper function for validating slot_id.
valid_slot_id(slot_id: u8) -> bool130 pub fn valid_slot_id(slot_id: u8) -> bool {
131     // slot id count from 1.
132     slot_id > 0 && slot_id <= MAX_SLOTS
133 }
134 
135 /// XhciRegs hold all xhci registers.
136 pub struct XhciRegs {
137     pub usbcmd: Register<u32>,
138     pub usbsts: Register<u32>,
139     pub dnctrl: Register<u32>,
140     pub crcr: Register<u64>,
141     pub dcbaap: Register<u64>,
142     pub config: Register<u64>,
143     pub portsc: Vec<Register<u32>>,
144     pub doorbells: Vec<Register<u32>>,
145     pub iman: Register<u32>,
146     pub imod: Register<u32>,
147     pub erstsz: Register<u32>,
148     pub erstba: Register<u64>,
149     pub erdp: Register<u64>,
150 }
151 
152 /// This function returns mmio space definition for xhci. See Xhci spec chapter 5
153 /// for details.
init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs)154 pub fn init_xhci_mmio_space_and_regs() -> (RegisterSpace, XhciRegs) {
155     let mut mmio = RegisterSpace::new();
156 
157     /* Host Controller Capability Registers */
158     mmio.add_register(
159         // CAPLENGTH
160         static_register!(
161         ty: u8,
162         offset: 0x00,
163         value: XHCI_CAPLENGTH, // Operation register start at offset 0x20
164         ),
165     );
166     mmio.add_register(
167         // HCIVERSION
168         static_register!(
169         ty: u16,
170         offset: 0x02,
171         value: 0x0110,// Revision 1.1
172         ),
173     );
174     mmio.add_register(
175         // HCSPARAMS1
176         static_register!(
177         ty: u32,
178         offset: 0x04,
179         value: 0x10000110, // max_slots = 16, max_interrupters = 1, max_ports = 16
180         ),
181     );
182 
183     mmio.add_register(
184         // HCSPARAMS2
185         static_register!(
186         ty: u32,
187         offset: 0x08,
188         // Maximum number of event ring segment table entries = 32k
189         // No scratchpad buffers.
190         value: 0xf0,
191         ),
192     );
193 
194     mmio.add_register(
195         // HCSPARAM3
196         static_register!(
197         ty: u32,
198         offset: 0x0c,
199 
200         // Exit latencies for U1 (standby with fast exit) and U2 (standby with
201         // slower exit) power states. We use the max values:
202         // - U1 to U0: < 10 us
203         // - U2 to U1: < 2047 us
204         value: 0x07FF000A,
205         ),
206     );
207 
208     mmio.add_register(
209         // HCCPARAMS1
210         static_register!(
211         ty: u32,
212         offset: 0x10,
213         // Supports 64 bit addressing
214         // Max primary stream array size = 0 (streams not supported).
215         // Extended capabilities pointer = 0xC000 offset from base.
216         value: 0x30000501,
217         ),
218     );
219     mmio.add_register(
220         // DBOFF
221         static_register!(
222         ty: u32,
223         offset: 0x14,
224         value: XHCI_DBOFF, // Doorbell array offset 0x2000 from base.
225         ),
226     );
227 
228     mmio.add_register(
229         // RTSOFF
230         static_register!(
231         ty: u32,
232         offset: 0x18,
233         value: XHCI_RTSOFF, // Runtime registers offset 0x3000 from base.
234         ),
235     );
236 
237     mmio.add_register(
238         // HCCPARAMS2
239         static_register!(
240         ty: u32,
241         offset: 0x1c,
242         value: 0,
243         ),
244     );
245     /* End of Host Controller Capability Registers */
246 
247     /* Host Controller Operational Registers */
248     let usbcmd = register!(
249         name: "usbcmd",
250         ty: u32,
251         offset: 0x20,
252         reset_value: 0,
253         guest_writeable_mask: 0x00002F0F,
254         guest_write_1_to_clear_mask: 0,
255     );
256     mmio.add_register(usbcmd.clone());
257 
258     let usbsts = register!(
259         name: "usbsts",
260         ty: u32,
261         offset: 0x24,
262         reset_value: 0x00000001,
263         guest_writeable_mask: 0x0000041C,
264         guest_write_1_to_clear_mask: 0x0000041C,
265     );
266     mmio.add_register(usbsts.clone());
267 
268     mmio.add_register(
269         //  Pagesize
270         static_register!(
271         ty: u32,
272         offset: 0x28,
273         value: 0x00000001,
274         ),
275     );
276 
277     let dnctrl = register!(
278         name: "dnctrl",
279         ty: u32,
280         offset: 0x34,
281         reset_value: 0,
282         guest_writeable_mask: 0x0000FFFF,
283         guest_write_1_to_clear_mask: 0,
284     );
285     mmio.add_register(dnctrl.clone());
286 
287     let crcr = register!(
288         name: "crcr",
289         ty: u64,
290         offset: 0x38,
291         reset_value: 9,
292         guest_writeable_mask: 0xFFFFFFFFFFFFFFC7,
293         guest_write_1_to_clear_mask: 0,
294     );
295     mmio.add_register(crcr.clone());
296 
297     let dcbaap = register!(
298         name: "dcbaap",
299         ty: u64,
300         offset: 0x50,
301         reset_value: 0x0,
302         guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
303         guest_write_1_to_clear_mask: 0,
304     );
305     mmio.add_register(dcbaap.clone());
306 
307     let config = register!(
308         name: "config",
309         ty: u64,
310         offset: 0x58,
311         reset_value: 0,
312         guest_writeable_mask: 0x0000003F,
313         guest_write_1_to_clear_mask: 0,
314     );
315     mmio.add_register(config.clone());
316 
317     let portsc = register_array!(
318         name: "portsc",
319         ty: u32,
320         cnt: MAX_PORTS,
321         base_offset: 0x420,
322         stride: 16,
323         reset_value: 0x000002A0,
324         guest_writeable_mask: 0x8EFFC3F2,
325         guest_write_1_to_clear_mask: 0x00FE0002,);
326     mmio.add_register_array(&portsc);
327 
328     // Portpmsc.
329     mmio.add_register_array(&register_array!(
330             name: "portpmsc",
331             ty: u32,
332             cnt: MAX_PORTS,
333             base_offset: 0x424,
334             stride: 16,
335             reset_value: 0,
336             guest_writeable_mask: 0x0001FFFF,
337             guest_write_1_to_clear_mask: 0,));
338 
339     // Portli
340     mmio.add_register_array(&register_array!(
341             name: "portli",
342             ty: u32,
343             cnt: MAX_PORTS,
344             base_offset: 0x428,
345             stride: 16,
346             reset_value: 0,
347             guest_writeable_mask: 0,
348             guest_write_1_to_clear_mask: 0,));
349 
350     // Porthlpmc
351     mmio.add_register_array(&register_array!(
352             name: "porthlpmc",
353             ty: u32,
354             cnt: MAX_PORTS,
355             base_offset: 0x42c,
356             stride: 16,
357             reset_value: 0,
358             guest_writeable_mask: 0x00003FFF,
359             guest_write_1_to_clear_mask: 0,));
360 
361     let doorbells = register_array!(
362         name: "doorbell",
363         ty: u32,
364         cnt: MAX_SLOTS + 1, //  Must be equal to max_slots + 1
365         base_offset: 0x2000,
366         stride: 4,
367         reset_value: 0,
368         guest_writeable_mask: 0xFFFF00FF,
369         guest_write_1_to_clear_mask: 0,);
370     mmio.add_register_array(&doorbells);
371 
372     /*Runtime Registers */
373 
374     mmio.add_register(
375         // mfindex
376         static_register!(
377         ty: u32,
378         offset: 0x3000,
379         value: 0, // 4 ports starting at port 5
380         ),
381     );
382 
383     /* Reg Array for interrupters */
384     // Although the following should be register arrays, we only have one interrupter.
385     let iman = register!(
386             name: "iman",
387             ty: u32,
388             offset: 0x3020,
389             reset_value: 0,
390             guest_writeable_mask: 0x00000003,
391             guest_write_1_to_clear_mask: 0x00000001,);
392     mmio.add_register(iman.clone());
393 
394     let imod = register!(
395             name: "imod",
396             ty: u32,
397             offset: 0x3024,
398             reset_value: 0x00000FA0,
399             guest_writeable_mask: 0xFFFFFFFF,
400             guest_write_1_to_clear_mask: 0,);
401     mmio.add_register(imod.clone());
402 
403     let erstsz = register!(
404         name: "erstsz",
405         ty: u32,
406         offset: 0x3028,
407         reset_value: 0,
408         guest_writeable_mask: 0x0000FFFF,
409         guest_write_1_to_clear_mask: 0,);
410     mmio.add_register(erstsz.clone());
411 
412     let erstba = register!(
413         name: "erstba",
414         ty: u64,
415         offset: 0x3030,
416         reset_value: 0,
417         guest_writeable_mask: 0xFFFFFFFFFFFFFFC0,
418         guest_write_1_to_clear_mask: 0,);
419     mmio.add_register(erstba.clone());
420 
421     let erdp = register!(
422         name: "erdp",
423         ty: u64,
424         offset: 0x3038,
425         reset_value: 0,
426         guest_writeable_mask: 0xFFFFFFFFFFFFFFFF,
427         guest_write_1_to_clear_mask: 0x0000000000000008,);
428     mmio.add_register(erdp.clone());
429 
430     /* End of Runtime Registers */
431 
432     let xhci_regs = XhciRegs {
433         usbcmd,
434         usbsts,
435         dnctrl,
436         crcr,
437         dcbaap,
438         config,
439         portsc,
440         doorbells,
441         iman,
442         imod,
443         erstsz,
444         erstba,
445         erdp,
446     };
447 
448     /* End of Host Controller Operational Registers */
449 
450     /* Extended Capability Registers */
451 
452     // Extended capability registers. Base offset defined by hccparams1.
453     // Each set of 4 registers represents a "Supported Protocol" extended
454     // capability.  The first capability indicates that ports 1-8 are USB 2.0. There is no USB 3.0
455     // port for now. See xHCI spec 7.1 & 7.2 for more details.
456     mmio.add_register(
457         // spcap 1.1
458         static_register!(
459         ty: u32,
460         offset: 0xc000,
461         // "Supported Protocol" capability.
462         // Next capability starts after 0x40 dwords.
463         // USB 2.0. Revision 2.0.
464         value: 0x02004002,
465         ),
466     );
467     mmio.add_register(
468         // spcap 1.2
469         static_register!(
470         ty: u32,
471         offset: 0xc004,
472         value: 0x20425355, // Name string = "USB "
473         ),
474     );
475     mmio.add_register(
476         // spcap 1.3
477         static_register!(
478         ty: u32,
479         offset: 0xc008,
480         value: 0x00000801, // 8 ports starting at port 1. See USB2_PORTS_START and USB2_PORTS_END.
481         ),
482     );
483 
484     mmio.add_register(
485         // spcap 1.4
486         static_register!(
487         ty: u32,
488         offset: 0xc00c,
489         // The specification says that this shall be set to 0.
490         // Section 7.2.2.1.4.
491         value: 0,
492         ),
493     );
494 
495     mmio.add_register(
496         // spcap 2.1
497         static_register!(
498         ty: u32,
499         offset: 0xc100,
500         // "Supported Protocol" capability.
501         // Not next capability.
502         // USB 3.0. Revision 2.0.
503         value: 0x03000002,
504         ),
505     );
506     mmio.add_register(
507         // spcap 2.2
508         static_register!(
509         ty: u32,
510         offset: 0xc104,
511         value: 0x20425355, // Name string = "USB "
512         ),
513     );
514     mmio.add_register(
515         // spcap 2.3
516         static_register!(
517         ty: u32,
518         offset: 0xc108,
519         value: 0x00000809, // 8 ports starting at port 9. See USB3_PORTS_START and USB3_PORTS_END.
520         ),
521     );
522 
523     mmio.add_register(
524         // spcap 2.4
525         static_register!(
526         ty: u32,
527         offset: 0xc10c,
528         // The specification says that this shall be set to 0.
529         // Section 7.2.2.1.4.
530         value: 0,
531         ),
532     );
533 
534     /* End of Host Controller Operational Registers */
535 
536     (mmio, xhci_regs)
537 }
538