summaryrefslogtreecommitdiff
path: root/sys/dev/usb/xhcivar.h
blob: 533032ae9c7e239de782954acaacdfa8e01c4b32 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/* $OpenBSD: xhcivar.h,v 1.12 2020/12/24 14:11:38 mglocker Exp $ */

/*
 * Copyright (c) 2014 Martin Pieuchot
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef	_XHCIVAR_H_
#define	_XHCIVAR_H_

/* Default command execution time (implementation defined). */
#define	XHCI_CMD_TIMEOUT	MSEC_TO_NSEC(500)

#define	XHCI_MAX_CMDS		(16 * 1)
#define	XHCI_MAX_EVTS		(16 * 13)
#define	XHCI_MAX_XFER		(16 * 16)

struct usbd_dma_info {
	bus_dma_tag_t		 tag;
	bus_dmamap_t		 map;
	bus_dma_segment_t	 seg;
	int			 nsegs;
	bus_addr_t		 paddr;
	caddr_t			 vaddr;
	bus_size_t		 size;
};

struct xhci_xfer {
	struct usbd_xfer	 xfer;
	int			 index;		/* Index of the last TRB */
	size_t			 ntrb;		/* Number of associated TRBs */
	size_t			 zerotd;	/* Is zero len TD required? */
};

struct xhci_ring {
	struct xhci_trb		*trbs;
	size_t			 ntrb;
	struct usbd_dma_info	 dma;

	uint32_t		 index;
	uint32_t		 toggle;	/* Producer/Consumer bit */
};

struct xhci_soft_dev {
	struct xhci_inctx	*input_ctx;	/* Input context */
	struct xhci_sctx	*slot_ctx;
	struct xhci_epctx	*ep_ctx[31];
	struct usbd_dma_info	 ictx_dma;

	struct usbd_dma_info	 octx_dma;	/* Output context */

	struct xhci_pipe	*pipes[31];
};

/* Device context segment table. */
struct xhci_devctx {
	uint64_t		*segs;		/* at most USB_MAX_DEVICES+1 */
	struct usbd_dma_info	 dma;
};

/* Event ring segment table. */
struct xhci_erst {
	struct xhci_erseg	*segs;		/* One segment per event ring */
	struct usbd_dma_info	 dma;
};

struct xhci_scratchpad {
	struct usbd_dma_info	 table_dma;
	struct usbd_dma_info	 pages_dma;
	int			 npage;
};

struct xhci_softc {
	struct usbd_bus		 sc_bus;

	bus_space_tag_t		 iot;
	bus_space_handle_t	 ioh;
	bus_size_t		 sc_size;

	bus_size_t		 sc_oper_off;	/* Operational Register space */
	bus_size_t		 sc_runt_off;	/* Runtime */
	bus_size_t		 sc_door_off;	/* Doorbell  */

	uint16_t		 sc_version;	/* xHCI version */
	uint32_t		 sc_pagesize;	/* xHCI page size, minimum 4k */
	uint32_t		 sc_ctxsize;	/* 32/64 byte context structs */

	int			 sc_noport;	/* Maximum number of ports */

	u_int8_t		 sc_conf;	/* Device configuration */
	struct usbd_xfer	*sc_intrxfer;	/* Root HUB interrupt xfer */

	struct xhci_devctx	 sc_dcbaa;	/* Device context base addr. */
	struct xhci_ring	 sc_cmd_ring;	/* Command ring */
	struct rwlock		 sc_cmd_lock;	/* Serialize commands */

	struct xhci_erst	 sc_erst;	/* Event ring segment table */
	struct xhci_ring	 sc_evt_ring;	/* Event ring */

	struct xhci_scratchpad	 sc_spad;	/* Optional scratchpad */

	int 			 sc_noslot;	/* Maximum number of slots */
	struct xhci_soft_dev	 sc_sdevs[USB_MAX_DEVICES];

	struct xhci_trb		*sc_cmd_trb;
	struct xhci_trb		 sc_result_trb;

	char			 sc_vendor[16];	/* Vendor string for root hub */
	int			 sc_id_vendor;	/* Vendor ID for root hub */
};

int	xhci_init(struct xhci_softc *);
void	xhci_config(struct xhci_softc *);
int	xhci_intr(void *);
int	xhci_detach(struct device *, int);
int	xhci_activate(struct device *, int);

#define	XREAD1(sc, a) bus_space_read_1((sc)->iot, (sc)->ioh, (a))
#define	XREAD2(sc, a) bus_space_read_2((sc)->iot, (sc)->ioh, (a))
#define	XREAD4(sc, a) bus_space_read_4((sc)->iot, (sc)->ioh, (a))
#define	XWRITE1(sc, a, x) bus_space_write_1((sc)->iot, (sc)->ioh, (a), (x))
#define	XWRITE2(sc, a, x) bus_space_write_2((sc)->iot, (sc)->ioh, (a), (x))
#define	XWRITE4(sc, a, x) bus_space_write_4((sc)->iot, (sc)->ioh, (a), (x))

#define	XOREAD4(sc, a)							\
	bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_oper_off + (a))
#define	XOWRITE4(sc, a, x)						\
	bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_oper_off + (a), (x))

#define	XRREAD4(sc, a) \
	bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_runt_off + (a))
#define	XRWRITE4(sc, a, x) \
	bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_runt_off + (a), (x))

#define	XDREAD4(sc, a) \
	bus_space_read_4((sc)->iot, (sc)->ioh, (sc)->sc_door_off + (a))
#define	XDWRITE4(sc, a, x) \
	bus_space_write_4((sc)->iot, (sc)->ioh, (sc)->sc_door_off + (a), (x))

#endif /* _XHCIVAR_H_ */