1184610Salfred/* $FreeBSD: releng/11.0/sys/dev/usb/controller/uhci.h 291199 2015-11-23 12:55:37Z hselasky $ */
2184610Salfred/*-
3184610Salfred * Copyright (c) 1998 The NetBSD Foundation, Inc.
4184610Salfred * All rights reserved.
5184610Salfred *
6184610Salfred * This code is derived from software contributed to The NetBSD Foundation
7184610Salfred * by Lennart Augustsson (lennart@augustsson.net) at
8184610Salfred * Carlstedt Research & Technology.
9184610Salfred *
10184610Salfred * Redistribution and use in source and binary forms, with or without
11184610Salfred * modification, are permitted provided that the following conditions
12184610Salfred * are met:
13184610Salfred * 1. Redistributions of source code must retain the above copyright
14184610Salfred *    notice, this list of conditions and the following disclaimer.
15184610Salfred * 2. Redistributions in binary form must reproduce the above copyright
16184610Salfred *    notice, this list of conditions and the following disclaimer in the
17184610Salfred *    documentation and/or other materials provided with the distribution.
18184610Salfred *
19184610Salfred * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20184610Salfred * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21184610Salfred * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22184610Salfred * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23184610Salfred * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24184610Salfred * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25184610Salfred * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26184610Salfred * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27184610Salfred * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28184610Salfred * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29184610Salfred * POSSIBILITY OF SUCH DAMAGE.
30184610Salfred */
31184610Salfred
32184610Salfred#ifndef _UHCI_H_
33184610Salfred#define	_UHCI_H_
34184610Salfred
35190174Sthompsa#define	UHCI_MAX_DEVICES MIN(USB_MAX_DEVICES, 128)
36187170Sthompsa
37184610Salfred#define	UHCI_FRAMELIST_COUNT	1024	/* units */
38184610Salfred#define	UHCI_FRAMELIST_ALIGN	4096	/* bytes */
39184610Salfred
40184610Salfred/* Structures alignment (bytes) */
41184610Salfred#define	UHCI_TD_ALIGN		16
42184610Salfred#define	UHCI_QH_ALIGN		16
43184610Salfred
44184610Salfred#if	((USB_PAGE_SIZE < UHCI_TD_ALIGN) || (UHCI_TD_ALIGN == 0) ||	\
45184610Salfred	(USB_PAGE_SIZE < UHCI_QH_ALIGN) || (UHCI_QH_ALIGN == 0))
46184610Salfred#error	"Invalid USB page size!"
47184610Salfred#endif
48184610Salfred
49184610Salfredtypedef uint32_t uhci_physaddr_t;
50184610Salfred
51184610Salfred#define	UHCI_PTR_T		0x00000001
52184610Salfred#define	UHCI_PTR_TD		0x00000000
53184610Salfred#define	UHCI_PTR_QH		0x00000002
54184610Salfred#define	UHCI_PTR_VF		0x00000004
55184610Salfred
56184610Salfred/*
57184610Salfred * The Queue Heads (QH) and Transfer Descriptors (TD) are accessed by
58184610Salfred * both the CPU and the USB-controller which run concurrently. Great
59184610Salfred * care must be taken. When the data-structures are linked into the
60184610Salfred * USB controller's frame list, the USB-controller "owns" the
61184610Salfred * td_status and qh_elink fields, which will not be written by the
62184610Salfred * CPU.
63184610Salfred *
64184610Salfred */
65184610Salfred
66184610Salfredstruct uhci_td {
67184610Salfred/*
68184610Salfred * Data used by the UHCI controller.
69184610Salfred * volatile is used in order to mantain struct members ordering.
70184610Salfred */
71184610Salfred	volatile uint32_t td_next;
72184610Salfred	volatile uint32_t td_status;
73184610Salfred#define	UHCI_TD_GET_ACTLEN(s)	(((s) + 1) & 0x3ff)
74184610Salfred#define	UHCI_TD_ZERO_ACTLEN(t)	((t) | 0x3ff)
75184610Salfred#define	UHCI_TD_BITSTUFF	0x00020000
76184610Salfred#define	UHCI_TD_CRCTO		0x00040000
77184610Salfred#define	UHCI_TD_NAK		0x00080000
78184610Salfred#define	UHCI_TD_BABBLE		0x00100000
79184610Salfred#define	UHCI_TD_DBUFFER		0x00200000
80184610Salfred#define	UHCI_TD_STALLED		0x00400000
81184610Salfred#define	UHCI_TD_ACTIVE		0x00800000
82184610Salfred#define	UHCI_TD_IOC		0x01000000
83184610Salfred#define	UHCI_TD_IOS		0x02000000
84184610Salfred#define	UHCI_TD_LS		0x04000000
85184610Salfred#define	UHCI_TD_GET_ERRCNT(s)	(((s) >> 27) & 3)
86184610Salfred#define	UHCI_TD_SET_ERRCNT(n)	((n) << 27)
87184610Salfred#define	UHCI_TD_SPD		0x20000000
88184610Salfred	volatile uint32_t td_token;
89184610Salfred#define	UHCI_TD_PID		0x000000ff
90184610Salfred#define	UHCI_TD_PID_IN		0x00000069
91184610Salfred#define	UHCI_TD_PID_OUT		0x000000e1
92184610Salfred#define	UHCI_TD_PID_SETUP	0x0000002d
93184610Salfred#define	UHCI_TD_GET_PID(s)	((s) & 0xff)
94184610Salfred#define	UHCI_TD_SET_DEVADDR(a)	((a) << 8)
95184610Salfred#define	UHCI_TD_GET_DEVADDR(s)	(((s) >> 8) & 0x7f)
96184610Salfred#define	UHCI_TD_SET_ENDPT(e)	(((e) & 0xf) << 15)
97184610Salfred#define	UHCI_TD_GET_ENDPT(s)	(((s) >> 15) & 0xf)
98184610Salfred#define	UHCI_TD_SET_DT(t)	((t) << 19)
99184610Salfred#define	UHCI_TD_GET_DT(s)	(((s) >> 19) & 1)
100291199Shselasky#define	UHCI_TD_SET_MAXLEN(l)	(((l)-1U) << 21)
101184610Salfred#define	UHCI_TD_GET_MAXLEN(s)	((((s) >> 21) + 1) & 0x7ff)
102184610Salfred#define	UHCI_TD_MAXLEN_MASK	0xffe00000
103184610Salfred	volatile uint32_t td_buffer;
104184610Salfred/*
105184610Salfred * Extra information needed:
106184610Salfred */
107184610Salfred	struct uhci_td *next;
108184610Salfred	struct uhci_td *prev;
109184610Salfred	struct uhci_td *obj_next;
110192984Sthompsa	struct usb_page_cache *page_cache;
111192984Sthompsa	struct usb_page_cache *fix_pc;
112184610Salfred	uint32_t td_self;
113184610Salfred	uint16_t len;
114184610Salfred} __aligned(UHCI_TD_ALIGN);
115184610Salfred
116184610Salfredtypedef struct uhci_td uhci_td_t;
117184610Salfred
118184610Salfred#define	UHCI_TD_ERROR	(UHCI_TD_BITSTUFF | UHCI_TD_CRCTO | 		\
119184610Salfred			UHCI_TD_BABBLE | UHCI_TD_DBUFFER | UHCI_TD_STALLED)
120184610Salfred
121184610Salfred#define	UHCI_TD_SETUP(len, endp, dev)	(UHCI_TD_SET_MAXLEN(len) |	\
122184610Salfred					UHCI_TD_SET_ENDPT(endp) |	\
123184610Salfred					UHCI_TD_SET_DEVADDR(dev) |	\
124184610Salfred					UHCI_TD_PID_SETUP)
125184610Salfred
126184610Salfred#define	UHCI_TD_OUT(len, endp, dev, dt)	(UHCI_TD_SET_MAXLEN(len) |	\
127184610Salfred					UHCI_TD_SET_ENDPT(endp) |	\
128184610Salfred					UHCI_TD_SET_DEVADDR(dev) |	\
129184610Salfred					UHCI_TD_PID_OUT | UHCI_TD_SET_DT(dt))
130184610Salfred
131184610Salfred#define	UHCI_TD_IN(len, endp, dev, dt)	(UHCI_TD_SET_MAXLEN(len) |	\
132184610Salfred					UHCI_TD_SET_ENDPT(endp) |	\
133184610Salfred					UHCI_TD_SET_DEVADDR(dev) |	\
134184610Salfred					UHCI_TD_PID_IN | UHCI_TD_SET_DT(dt))
135184610Salfred
136184610Salfredstruct uhci_qh {
137184610Salfred/*
138184610Salfred * Data used by the UHCI controller.
139184610Salfred */
140184610Salfred	volatile uint32_t qh_h_next;
141184610Salfred	volatile uint32_t qh_e_next;
142184610Salfred/*
143184610Salfred * Extra information needed:
144184610Salfred */
145184610Salfred	struct uhci_qh *h_next;
146184610Salfred	struct uhci_qh *h_prev;
147184610Salfred	struct uhci_qh *obj_next;
148184610Salfred	struct uhci_td *e_next;
149192984Sthompsa	struct usb_page_cache *page_cache;
150184610Salfred	uint32_t qh_self;
151184610Salfred	uint16_t intr_pos;
152184610Salfred} __aligned(UHCI_QH_ALIGN);
153184610Salfred
154184610Salfredtypedef struct uhci_qh uhci_qh_t;
155184610Salfred
156184610Salfred/* Maximum number of isochronous TD's and QH's interrupt */
157184610Salfred#define	UHCI_VFRAMELIST_COUNT	128
158184610Salfred#define	UHCI_IFRAMELIST_COUNT	(2 * UHCI_VFRAMELIST_COUNT)
159184610Salfred
160184610Salfred#if	(((UHCI_VFRAMELIST_COUNT & (UHCI_VFRAMELIST_COUNT-1)) != 0) ||	\
161184610Salfred	(UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT))
162184610Salfred#error	"UHCI_VFRAMELIST_COUNT is not power of two"
163184610Salfred#error	"or UHCI_VFRAMELIST_COUNT > UHCI_FRAMELIST_COUNT"
164184610Salfred#endif
165184610Salfred
166184610Salfred#if (UHCI_VFRAMELIST_COUNT < USB_MAX_FS_ISOC_FRAMES_PER_XFER)
167184610Salfred#error "maximum number of full-speed isochronous frames is higher than supported!"
168184610Salfred#endif
169184610Salfred
170184610Salfredstruct uhci_config_desc {
171192984Sthompsa	struct usb_config_descriptor confd;
172192984Sthompsa	struct usb_interface_descriptor ifcd;
173192984Sthompsa	struct usb_endpoint_descriptor endpd;
174184610Salfred} __packed;
175184610Salfred
176184610Salfredunion uhci_hub_desc {
177192984Sthompsa	struct usb_status stat;
178192984Sthompsa	struct usb_port_status ps;
179184610Salfred	uint8_t	temp[128];
180184610Salfred};
181184610Salfred
182184610Salfredstruct uhci_hw_softc {
183192984Sthompsa	struct usb_page_cache pframes_pc;
184192984Sthompsa	struct usb_page_cache isoc_start_pc[UHCI_VFRAMELIST_COUNT];
185192984Sthompsa	struct usb_page_cache intr_start_pc[UHCI_IFRAMELIST_COUNT];
186192984Sthompsa	struct usb_page_cache ls_ctl_start_pc;
187192984Sthompsa	struct usb_page_cache fs_ctl_start_pc;
188192984Sthompsa	struct usb_page_cache bulk_start_pc;
189192984Sthompsa	struct usb_page_cache last_qh_pc;
190192984Sthompsa	struct usb_page_cache last_td_pc;
191184610Salfred
192192984Sthompsa	struct usb_page pframes_pg;
193192984Sthompsa	struct usb_page isoc_start_pg[UHCI_VFRAMELIST_COUNT];
194192984Sthompsa	struct usb_page intr_start_pg[UHCI_IFRAMELIST_COUNT];
195192984Sthompsa	struct usb_page ls_ctl_start_pg;
196192984Sthompsa	struct usb_page fs_ctl_start_pg;
197192984Sthompsa	struct usb_page bulk_start_pg;
198192984Sthompsa	struct usb_page last_qh_pg;
199192984Sthompsa	struct usb_page last_td_pg;
200184610Salfred};
201184610Salfred
202184610Salfredtypedef struct uhci_softc {
203184610Salfred	struct uhci_hw_softc sc_hw;
204192984Sthompsa	struct usb_bus sc_bus;		/* base device */
205184610Salfred	union uhci_hub_desc sc_hub_desc;
206192984Sthompsa	struct usb_callout sc_root_intr;
207184610Salfred
208192984Sthompsa	struct usb_device *sc_devices[UHCI_MAX_DEVICES];
209190735Sthompsa	/* pointer to last TD for isochronous */
210190735Sthompsa	struct uhci_td *sc_isoc_p_last[UHCI_VFRAMELIST_COUNT];
211190735Sthompsa	/* pointer to last QH for interrupt */
212190735Sthompsa	struct uhci_qh *sc_intr_p_last[UHCI_IFRAMELIST_COUNT];
213190735Sthompsa	/* pointer to last QH for low speed control */
214190735Sthompsa	struct uhci_qh *sc_ls_ctl_p_last;
215190735Sthompsa	/* pointer to last QH for full speed control */
216190735Sthompsa	struct uhci_qh *sc_fs_ctl_p_last;
217190735Sthompsa	/* pointer to last QH for bulk */
218190735Sthompsa	struct uhci_qh *sc_bulk_p_last;
219184610Salfred	struct uhci_qh *sc_reclaim_qh_p;
220184610Salfred	struct uhci_qh *sc_last_qh_p;
221184610Salfred	struct uhci_td *sc_last_td_p;
222184610Salfred	struct resource *sc_io_res;
223184610Salfred	struct resource *sc_irq_res;
224184610Salfred	void   *sc_intr_hdl;
225184610Salfred	device_t sc_dev;
226184610Salfred	bus_size_t sc_io_size;
227184610Salfred	bus_space_tag_t sc_io_tag;
228184610Salfred	bus_space_handle_t sc_io_hdl;
229184610Salfred
230184610Salfred	uint32_t sc_loops;		/* number of QHs that wants looping */
231184610Salfred
232184610Salfred	uint16_t sc_intr_stat[UHCI_IFRAMELIST_COUNT];
233184610Salfred
234184610Salfred	uint8_t	sc_addr;		/* device address */
235184610Salfred	uint8_t	sc_conf;		/* device configuration */
236186730Salfred	uint8_t	sc_isreset;		/* bits set if a root hub is reset */
237186730Salfred	uint8_t	sc_isresumed;		/* bits set if a port was resumed */
238184610Salfred	uint8_t	sc_hub_idata[1];
239184610Salfred
240184610Salfred	char	sc_vendor[16];		/* vendor string for root hub */
241184610Salfred} uhci_softc_t;
242184610Salfred
243193045Sthompsausb_bus_mem_cb_t uhci_iterate_hw_softc;
244184610Salfred
245193045Sthompsausb_error_t uhci_init(uhci_softc_t *sc);
246184610Salfredvoid	uhci_reset(uhci_softc_t *sc);
247184610Salfredvoid	uhci_interrupt(uhci_softc_t *sc);
248184610Salfred
249184610Salfred#endif					/* _UHCI_H_ */
250