1 /* $OpenBSD: xhcivar.h,v 1.17 2025/02/01 22:46:34 patrick Exp $ */
2
3 /*
4 * Copyright (c) 2014 Martin Pieuchot
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #ifndef _XHCIVAR_H_
20 #define _XHCIVAR_H_
21
22 /* Default command execution time (implementation defined). */
23 #define XHCI_CMD_TIMEOUT MSEC_TO_NSEC(500)
24
25 #define XHCI_MAX_CMDS (16 * 1)
26 #define XHCI_MAX_EVTS (16 * 13)
27 #define XHCI_MAX_XFER (16 * 16)
28
29 struct usbd_dma_info {
30 bus_dma_tag_t tag;
31 bus_dmamap_t map;
32 bus_dma_segment_t seg;
33 int nsegs;
34 bus_addr_t paddr;
35 caddr_t vaddr;
36 bus_size_t size;
37 };
38
39 struct xhci_xfer {
40 struct usbd_xfer xfer;
41 int index; /* Index of the last TRB */
42 size_t ntrb; /* Number of associated TRBs */
43 size_t zerotd; /* Is zero len TD required? */
44 };
45
46 struct xhci_ring {
47 struct xhci_trb *trbs;
48 size_t ntrb;
49 struct usbd_dma_info dma;
50
51 uint32_t index;
52 uint32_t toggle; /* Producer/Consumer bit */
53 };
54
55 struct xhci_soft_dev {
56 struct xhci_inctx *input_ctx; /* Input context */
57 struct xhci_sctx *slot_ctx;
58 struct xhci_epctx *ep_ctx[31];
59 struct usbd_dma_info ictx_dma;
60
61 struct usbd_dma_info octx_dma; /* Output context */
62
63 struct xhci_pipe *pipes[31];
64 };
65
66 /* Device context segment table. */
67 struct xhci_devctx {
68 uint64_t *segs; /* at most USB_MAX_DEVICES+1 */
69 struct usbd_dma_info dma;
70 };
71
72 /* Event ring segment table. */
73 struct xhci_erst {
74 struct xhci_erseg *segs; /* One segment per event ring */
75 struct usbd_dma_info dma;
76 };
77
78 struct xhci_scratchpad {
79 struct usbd_dma_info table_dma;
80 struct usbd_dma_info pages_dma;
81 int npage;
82 };
83
84 struct xhci_softc {
85 struct usbd_bus sc_bus;
86
87 bus_space_tag_t iot;
88 bus_space_handle_t ioh;
89 bus_size_t sc_size;
90
91 int sc_dead;
92 int sc_saved_state;
93
94 bus_size_t sc_oper_off; /* Operational Register space */
95 bus_size_t sc_runt_off; /* Runtime */
96 bus_size_t sc_door_off; /* Doorbell */
97
98 uint16_t sc_version; /* xHCI version */
99 uint32_t sc_pagesize; /* xHCI page size, minimum 4k */
100 uint32_t sc_ctxsize; /* 32/64 byte context structs */
101
102 int sc_noport; /* Maximum number of ports */
103
104 u_int8_t sc_conf; /* Device configuration */
105 struct usbd_xfer *sc_intrxfer; /* Root HUB interrupt xfer */
106
107 struct xhci_devctx sc_dcbaa; /* Device context base addr. */
108 struct xhci_ring sc_cmd_ring; /* Command ring */
109 struct rwlock sc_cmd_lock; /* Serialize commands */
110
111 struct xhci_erst sc_erst; /* Event ring segment table */
112 struct xhci_ring sc_evt_ring; /* Event ring */
113
114 struct xhci_scratchpad sc_spad; /* Optional scratchpad */
115
116 int sc_noslot; /* Maximum number of slots */
117 struct xhci_soft_dev sc_sdevs[USB_MAX_DEVICES];
118
119 struct xhci_trb *sc_cmd_trb;
120 struct xhci_trb sc_result_trb;
121
122 char sc_vendor[16]; /* Vendor string for root hub */
123 int sc_id_vendor; /* Vendor ID for root hub */
124
125 int sc_flags;
126 #define XHCI_NOCSS 0x01
127 };
128
129 int xhci_init(struct xhci_softc *);
130 void xhci_config(struct xhci_softc *);
131 void xhci_reinit(struct xhci_softc *);
132 int xhci_intr(void *);
133 int xhci_detach(struct device *, int);
134 int xhci_activate(struct device *, int);
135
136 static inline uint8_t
xhci_read_1(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset)137 xhci_read_1(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset)
138 {
139 uint32_t reg;
140 reg = bus_space_read_4(iot, ioh, offset & ~3);
141 return (reg >> ((offset & 3) * 8)) & 0xff;
142 }
143
144 static inline uint16_t
xhci_read_2(bus_space_tag_t iot,bus_space_handle_t ioh,bus_size_t offset)145 xhci_read_2(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t offset)
146 {
147 uint32_t reg;
148 reg = bus_space_read_4(iot, ioh, offset & ~2);
149 return (reg >> ((offset & 2) * 8)) & 0xffff;
150 }
151
152 #define XREAD1(sc, a) xhci_read_1((sc)->iot, (sc)->ioh, (a))
153 #define XREAD2(sc, a) xhci_read_2((sc)->iot, (sc)->ioh, (a))
154 #define XREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
155 #define XWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
156 #define XWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
157 #define XWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))
158
159 #define XOREAD4(sc, a) \
160 bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_oper_off + (a))
161 #define XOWRITE4(sc, a, x) \
162 bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_oper_off + (a), (x))
163
164 #define XRREAD4(sc, a) \
165 bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_runt_off + (a))
166 #define XRWRITE4(sc, a, x) \
167 bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_runt_off + (a), (x))
168
169 #define XDREAD4(sc, a) \
170 bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_door_off + (a))
171 #define XDWRITE4(sc, a, x) \
172 bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_door_off + (a), (x))
173
174 #endif /* _XHCIVAR_H_ */
175