xref: /openbmc/qemu/hw/usb/hcd-musb.c (revision 2c89d911)
1f1ae32a1SGerd Hoffmann /*
2f1ae32a1SGerd Hoffmann  * "Inventra" High-speed Dual-Role Controller (MUSB-HDRC), Mentor Graphics,
3f1ae32a1SGerd Hoffmann  * USB2.0 OTG compliant core used in various chips.
4f1ae32a1SGerd Hoffmann  *
5f1ae32a1SGerd Hoffmann  * Copyright (C) 2008 Nokia Corporation
6f1ae32a1SGerd Hoffmann  * Written by Andrzej Zaborowski <andrew@openedhand.com>
7f1ae32a1SGerd Hoffmann  *
8f1ae32a1SGerd Hoffmann  * This program is free software; you can redistribute it and/or
9f1ae32a1SGerd Hoffmann  * modify it under the terms of the GNU General Public License as
10f1ae32a1SGerd Hoffmann  * published by the Free Software Foundation; either version 2 or
11f1ae32a1SGerd Hoffmann  * (at your option) version 3 of the License.
12f1ae32a1SGerd Hoffmann  *
13f1ae32a1SGerd Hoffmann  * This program is distributed in the hope that it will be useful,
14f1ae32a1SGerd Hoffmann  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15f1ae32a1SGerd Hoffmann  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16f1ae32a1SGerd Hoffmann  * GNU General Public License for more details.
17f1ae32a1SGerd Hoffmann  *
18f1ae32a1SGerd Hoffmann  * You should have received a copy of the GNU General Public License along
19f1ae32a1SGerd Hoffmann  * with this program; if not, see <http://www.gnu.org/licenses/>.
20f1ae32a1SGerd Hoffmann  *
21f1ae32a1SGerd Hoffmann  * Only host-mode and non-DMA accesses are currently supported.
22f1ae32a1SGerd Hoffmann  */
23e532b2e0SPeter Maydell #include "qemu/osdep.h"
241de7afc9SPaolo Bonzini #include "qemu/timer.h"
25f1ae32a1SGerd Hoffmann #include "hw/usb.h"
26*2c89d911SPhilippe Mathieu-Daudé #include "hw/usb/hcd-musb.h"
27f1ae32a1SGerd Hoffmann #include "hw/irq.h"
28f1ae32a1SGerd Hoffmann #include "hw/hw.h"
29f1ae32a1SGerd Hoffmann 
30f1ae32a1SGerd Hoffmann /* Common USB registers */
31f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FADDR		0x00	/* 8-bit */
32f1ae32a1SGerd Hoffmann #define MUSB_HDRC_POWER		0x01	/* 8-bit */
33f1ae32a1SGerd Hoffmann 
34f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRTX	0x02	/* 16-bit */
35f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRRX	0x04
36f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRTXE	0x06
37f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRRXE	0x08
38f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRUSB	0x0a	/* 8 bit */
39f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INTRUSBE	0x0b	/* 8 bit */
40f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FRAME		0x0c	/* 16-bit */
41f1ae32a1SGerd Hoffmann #define MUSB_HDRC_INDEX		0x0e	/* 8 bit */
42f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TESTMODE	0x0f	/* 8 bit */
43f1ae32a1SGerd Hoffmann 
44f1ae32a1SGerd Hoffmann /* Per-EP registers in indexed mode */
45f1ae32a1SGerd Hoffmann #define MUSB_HDRC_EP_IDX	0x10	/* 8-bit */
46f1ae32a1SGerd Hoffmann 
47f1ae32a1SGerd Hoffmann /* EP FIFOs */
48f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FIFO		0x20
49f1ae32a1SGerd Hoffmann 
50f1ae32a1SGerd Hoffmann /* Additional Control Registers */
51f1ae32a1SGerd Hoffmann #define	MUSB_HDRC_DEVCTL	0x60	/* 8 bit */
52f1ae32a1SGerd Hoffmann 
53f1ae32a1SGerd Hoffmann /* These are indexed */
54f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFIFOSZ	0x62	/* 8 bit (see masks) */
55f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFIFOSZ	0x63	/* 8 bit (see masks) */
56f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFIFOADDR	0x64	/* 16 bit offset shifted right 3 */
57f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFIFOADDR	0x66	/* 16 bit offset shifted right 3 */
58f1ae32a1SGerd Hoffmann 
59f1ae32a1SGerd Hoffmann /* Some more registers */
60f1ae32a1SGerd Hoffmann #define MUSB_HDRC_VCTRL		0x68	/* 8 bit */
61f1ae32a1SGerd Hoffmann #define MUSB_HDRC_HWVERS	0x6c	/* 8 bit */
62f1ae32a1SGerd Hoffmann 
63f1ae32a1SGerd Hoffmann /* Added in HDRC 1.9(?) & MHDRC 1.4 */
64f1ae32a1SGerd Hoffmann /* ULPI pass-through */
65f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_VBUSCTL	0x70
66f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGDATA	0x74
67f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGADDR	0x75
68f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ULPI_REGCTL	0x76
69f1ae32a1SGerd Hoffmann 
70f1ae32a1SGerd Hoffmann /* Extended config & PHY control */
71f1ae32a1SGerd Hoffmann #define MUSB_HDRC_ENDCOUNT	0x78	/* 8 bit */
72f1ae32a1SGerd Hoffmann #define MUSB_HDRC_DMARAMCFG	0x79	/* 8 bit */
73f1ae32a1SGerd Hoffmann #define MUSB_HDRC_PHYWAIT	0x7a	/* 8 bit */
74f1ae32a1SGerd Hoffmann #define MUSB_HDRC_PHYVPLEN	0x7b	/* 8 bit */
75f1ae32a1SGerd Hoffmann #define MUSB_HDRC_HS_EOF1	0x7c	/* 8 bit, units of 546.1 us */
76f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FS_EOF1	0x7d	/* 8 bit, units of 533.3 ns */
77f1ae32a1SGerd Hoffmann #define MUSB_HDRC_LS_EOF1	0x7e	/* 8 bit, units of 1.067 us */
78f1ae32a1SGerd Hoffmann 
79f1ae32a1SGerd Hoffmann /* Per-EP BUSCTL registers */
80f1ae32a1SGerd Hoffmann #define MUSB_HDRC_BUSCTL	0x80
81f1ae32a1SGerd Hoffmann 
82f1ae32a1SGerd Hoffmann /* Per-EP registers in flat mode */
83f1ae32a1SGerd Hoffmann #define MUSB_HDRC_EP		0x100
84f1ae32a1SGerd Hoffmann 
85f1ae32a1SGerd Hoffmann /* offsets to registers in flat model */
86f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXMAXP	0x00	/* 16 bit apparently */
87f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXCSR		0x02	/* 16 bit apparently */
88f1ae32a1SGerd Hoffmann #define MUSB_HDRC_CSR0		MUSB_HDRC_TXCSR		/* re-used for EP0 */
89f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXMAXP	0x04	/* 16 bit apparently */
90f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXCSR		0x06	/* 16 bit apparently */
91f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXCOUNT	0x08	/* 16 bit apparently */
92f1ae32a1SGerd Hoffmann #define MUSB_HDRC_COUNT0	MUSB_HDRC_RXCOUNT	/* re-used for EP0 */
93f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXTYPE	0x0a	/* 8 bit apparently */
94f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TYPE0		MUSB_HDRC_TXTYPE	/* re-used for EP0 */
95f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXINTERVAL	0x0b	/* 8 bit apparently */
96f1ae32a1SGerd Hoffmann #define MUSB_HDRC_NAKLIMIT0	MUSB_HDRC_TXINTERVAL	/* re-used for EP0 */
97f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXTYPE	0x0c	/* 8 bit apparently */
98f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXINTERVAL	0x0d	/* 8 bit apparently */
99f1ae32a1SGerd Hoffmann #define MUSB_HDRC_FIFOSIZE	0x0f	/* 8 bit apparently */
100f1ae32a1SGerd Hoffmann #define MUSB_HDRC_CONFIGDATA	MGC_O_HDRC_FIFOSIZE	/* re-used for EP0 */
101f1ae32a1SGerd Hoffmann 
102f1ae32a1SGerd Hoffmann /* "Bus control" registers */
103f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXFUNCADDR	0x00
104f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXHUBADDR	0x02
105f1ae32a1SGerd Hoffmann #define MUSB_HDRC_TXHUBPORT	0x03
106f1ae32a1SGerd Hoffmann 
107f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXFUNCADDR	0x04
108f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXHUBADDR	0x06
109f1ae32a1SGerd Hoffmann #define MUSB_HDRC_RXHUBPORT	0x07
110f1ae32a1SGerd Hoffmann 
111f1ae32a1SGerd Hoffmann /*
112f1ae32a1SGerd Hoffmann  * MUSBHDRC Register bit masks
113f1ae32a1SGerd Hoffmann  */
114f1ae32a1SGerd Hoffmann 
115f1ae32a1SGerd Hoffmann /* POWER */
116f1ae32a1SGerd Hoffmann #define MGC_M_POWER_ISOUPDATE		0x80
117f1ae32a1SGerd Hoffmann #define	MGC_M_POWER_SOFTCONN		0x40
118f1ae32a1SGerd Hoffmann #define	MGC_M_POWER_HSENAB		0x20
119f1ae32a1SGerd Hoffmann #define	MGC_M_POWER_HSMODE		0x10
120f1ae32a1SGerd Hoffmann #define MGC_M_POWER_RESET		0x08
121f1ae32a1SGerd Hoffmann #define MGC_M_POWER_RESUME		0x04
122f1ae32a1SGerd Hoffmann #define MGC_M_POWER_SUSPENDM		0x02
123f1ae32a1SGerd Hoffmann #define MGC_M_POWER_ENSUSPEND		0x01
124f1ae32a1SGerd Hoffmann 
125f1ae32a1SGerd Hoffmann /* INTRUSB */
126f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SUSPEND		0x01
127f1ae32a1SGerd Hoffmann #define MGC_M_INTR_RESUME		0x02
128f1ae32a1SGerd Hoffmann #define MGC_M_INTR_RESET		0x04
129f1ae32a1SGerd Hoffmann #define MGC_M_INTR_BABBLE		0x04
130f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SOF			0x08
131f1ae32a1SGerd Hoffmann #define MGC_M_INTR_CONNECT		0x10
132f1ae32a1SGerd Hoffmann #define MGC_M_INTR_DISCONNECT		0x20
133f1ae32a1SGerd Hoffmann #define MGC_M_INTR_SESSREQ		0x40
134f1ae32a1SGerd Hoffmann #define MGC_M_INTR_VBUSERROR		0x80	/* FOR SESSION END */
135f1ae32a1SGerd Hoffmann #define MGC_M_INTR_EP0			0x01	/* FOR EP0 INTERRUPT */
136f1ae32a1SGerd Hoffmann 
137f1ae32a1SGerd Hoffmann /* DEVCTL */
138f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_BDEVICE		0x80
139f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_FSDEV		0x40
140f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_LSDEV		0x20
141f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_VBUS		0x18
142f1ae32a1SGerd Hoffmann #define MGC_S_DEVCTL_VBUS		3
143f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_HM			0x04
144f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_HR			0x02
145f1ae32a1SGerd Hoffmann #define MGC_M_DEVCTL_SESSION		0x01
146f1ae32a1SGerd Hoffmann 
147f1ae32a1SGerd Hoffmann /* TESTMODE */
148f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_HOST		0x80
149f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FIFO_ACCESS		0x40
150f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_FS		0x20
151f1ae32a1SGerd Hoffmann #define MGC_M_TEST_FORCE_HS		0x10
152f1ae32a1SGerd Hoffmann #define MGC_M_TEST_PACKET		0x08
153f1ae32a1SGerd Hoffmann #define MGC_M_TEST_K			0x04
154f1ae32a1SGerd Hoffmann #define MGC_M_TEST_J			0x02
155f1ae32a1SGerd Hoffmann #define MGC_M_TEST_SE0_NAK		0x01
156f1ae32a1SGerd Hoffmann 
157f1ae32a1SGerd Hoffmann /* CSR0 */
158f1ae32a1SGerd Hoffmann #define	MGC_M_CSR0_FLUSHFIFO		0x0100
159f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_TXPKTRDY		0x0002
160f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_RXPKTRDY		0x0001
161f1ae32a1SGerd Hoffmann 
162f1ae32a1SGerd Hoffmann /* CSR0 in Peripheral mode */
163f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SVDSETUPEND	0x0080
164f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SVDRXPKTRDY	0x0040
165f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SENDSTALL		0x0020
166f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SETUPEND		0x0010
167f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_DATAEND		0x0008
168f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_P_SENTSTALL		0x0004
169f1ae32a1SGerd Hoffmann 
170f1ae32a1SGerd Hoffmann /* CSR0 in Host mode */
171f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_NO_PING		0x0800
172f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_WR_DATATOGGLE	0x0400	/* set to allow setting: */
173f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_DATATOGGLE		0x0200	/* data toggle control */
174f1ae32a1SGerd Hoffmann #define	MGC_M_CSR0_H_NAKTIMEOUT		0x0080
175f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_STATUSPKT		0x0040
176f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_REQPKT		0x0020
177f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_ERROR		0x0010
178f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_SETUPPKT		0x0008
179f1ae32a1SGerd Hoffmann #define MGC_M_CSR0_H_RXSTALL		0x0004
180f1ae32a1SGerd Hoffmann 
181f1ae32a1SGerd Hoffmann /* CONFIGDATA */
182f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_MPRXE		0x80	/* auto bulk pkt combining */
183f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_MPTXE		0x40	/* auto bulk pkt splitting */
184f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_BIGENDIAN	0x20
185f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_HBRXE		0x10	/* HB-ISO for RX */
186f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_HBTXE		0x08	/* HB-ISO for TX */
187f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_DYNFIFO	0x04	/* dynamic FIFO sizing */
188f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_SOFTCONE	0x02	/* SoftConnect */
189f1ae32a1SGerd Hoffmann #define MGC_M_CONFIGDATA_UTMIDW		0x01	/* Width, 0 => 8b, 1 => 16b */
190f1ae32a1SGerd Hoffmann 
191f1ae32a1SGerd Hoffmann /* TXCSR in Peripheral and Host mode */
192f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_AUTOSET		0x8000
193f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_ISO			0x4000
194f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_MODE		0x2000
195f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_DMAENAB		0x1000
196f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FRCDATATOG		0x0800
197f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_DMAMODE		0x0400
198f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_CLRDATATOG		0x0040
199f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FLUSHFIFO		0x0008
200f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_FIFONOTEMPTY	0x0002
201f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_TXPKTRDY		0x0001
202f1ae32a1SGerd Hoffmann 
203f1ae32a1SGerd Hoffmann /* TXCSR in Peripheral mode */
204f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_INCOMPTX		0x0080
205f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_SENTSTALL		0x0020
206f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_SENDSTALL		0x0010
207f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_P_UNDERRUN		0x0004
208f1ae32a1SGerd Hoffmann 
209f1ae32a1SGerd Hoffmann /* TXCSR in Host mode */
210f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_WR_DATATOGGLE	0x0200
211f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_DATATOGGLE	0x0100
212f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_NAKTIMEOUT	0x0080
213f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_RXSTALL		0x0020
214f1ae32a1SGerd Hoffmann #define MGC_M_TXCSR_H_ERROR		0x0004
215f1ae32a1SGerd Hoffmann 
216f1ae32a1SGerd Hoffmann /* RXCSR in Peripheral and Host mode */
217f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_AUTOCLEAR		0x8000
218f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DMAENAB		0x2000
219f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DISNYET		0x1000
220f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DMAMODE		0x0800
221f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_INCOMPRX		0x0100
222f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_CLRDATATOG		0x0080
223f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_FLUSHFIFO		0x0010
224f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_DATAERROR		0x0008
225f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_FIFOFULL		0x0002
226f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_RXPKTRDY		0x0001
227f1ae32a1SGerd Hoffmann 
228f1ae32a1SGerd Hoffmann /* RXCSR in Peripheral mode */
229f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_ISO		0x4000
230f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_SENTSTALL		0x0040
231f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_SENDSTALL		0x0020
232f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_P_OVERRUN		0x0004
233f1ae32a1SGerd Hoffmann 
234f1ae32a1SGerd Hoffmann /* RXCSR in Host mode */
235f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_AUTOREQ		0x4000
236f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_WR_DATATOGGLE	0x0400
237f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_DATATOGGLE	0x0200
238f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_RXSTALL		0x0040
239f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_REQPKT		0x0020
240f1ae32a1SGerd Hoffmann #define MGC_M_RXCSR_H_ERROR		0x0004
241f1ae32a1SGerd Hoffmann 
242f1ae32a1SGerd Hoffmann /* HUBADDR */
243f1ae32a1SGerd Hoffmann #define MGC_M_HUBADDR_MULTI_TT		0x80
244f1ae32a1SGerd Hoffmann 
245f1ae32a1SGerd Hoffmann /* ULPI: Added in HDRC 1.9(?) & MHDRC 1.4 */
246f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_VBCTL_USEEXTVBUSIND	0x02
247f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_VBCTL_USEEXTVBUS	0x01
248f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_INT_ENABLE	0x08
249f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_READNOTWRITE	0x04
250f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_COMPLETE	0x02
251f1ae32a1SGerd Hoffmann #define MGC_M_ULPI_REGCTL_REG		0x01
252f1ae32a1SGerd Hoffmann 
253f1ae32a1SGerd Hoffmann /* #define MUSB_DEBUG */
254f1ae32a1SGerd Hoffmann 
255f1ae32a1SGerd Hoffmann #ifdef MUSB_DEBUG
256a89f364aSAlistair Francis #define TRACE(fmt, ...) fprintf(stderr, "%s@%d: " fmt "\n", __func__, \
257f1ae32a1SGerd Hoffmann                                 __LINE__, ##__VA_ARGS__)
258f1ae32a1SGerd Hoffmann #else
259f1ae32a1SGerd Hoffmann #define TRACE(...)
260f1ae32a1SGerd Hoffmann #endif
261f1ae32a1SGerd Hoffmann 
262f1ae32a1SGerd Hoffmann 
263f1ae32a1SGerd Hoffmann static void musb_attach(USBPort *port);
264f1ae32a1SGerd Hoffmann static void musb_detach(USBPort *port);
265f1ae32a1SGerd Hoffmann static void musb_child_detach(USBPort *port, USBDevice *child);
266f1ae32a1SGerd Hoffmann static void musb_schedule_cb(USBPort *port, USBPacket *p);
267f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev);
268f1ae32a1SGerd Hoffmann 
269f1ae32a1SGerd Hoffmann static USBPortOps musb_port_ops = {
270f1ae32a1SGerd Hoffmann     .attach = musb_attach,
271f1ae32a1SGerd Hoffmann     .detach = musb_detach,
272f1ae32a1SGerd Hoffmann     .child_detach = musb_child_detach,
273f1ae32a1SGerd Hoffmann     .complete = musb_schedule_cb,
274f1ae32a1SGerd Hoffmann };
275f1ae32a1SGerd Hoffmann 
276f1ae32a1SGerd Hoffmann static USBBusOps musb_bus_ops = {
277f1ae32a1SGerd Hoffmann };
278f1ae32a1SGerd Hoffmann 
279f1ae32a1SGerd Hoffmann typedef struct MUSBPacket MUSBPacket;
280f1ae32a1SGerd Hoffmann typedef struct MUSBEndPoint MUSBEndPoint;
281f1ae32a1SGerd Hoffmann 
282f1ae32a1SGerd Hoffmann struct MUSBPacket {
283f1ae32a1SGerd Hoffmann     USBPacket p;
284f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep;
285f1ae32a1SGerd Hoffmann     int dir;
286f1ae32a1SGerd Hoffmann };
287f1ae32a1SGerd Hoffmann 
288f1ae32a1SGerd Hoffmann struct MUSBEndPoint {
289f1ae32a1SGerd Hoffmann     uint16_t faddr[2];
290f1ae32a1SGerd Hoffmann     uint8_t haddr[2];
291f1ae32a1SGerd Hoffmann     uint8_t hport[2];
292f1ae32a1SGerd Hoffmann     uint16_t csr[2];
293f1ae32a1SGerd Hoffmann     uint16_t maxp[2];
294f1ae32a1SGerd Hoffmann     uint16_t rxcount;
295f1ae32a1SGerd Hoffmann     uint8_t type[2];
296f1ae32a1SGerd Hoffmann     uint8_t interval[2];
297f1ae32a1SGerd Hoffmann     uint8_t config;
298f1ae32a1SGerd Hoffmann     uint8_t fifosize;
299f1ae32a1SGerd Hoffmann     int timeout[2];	/* Always in microframes */
300f1ae32a1SGerd Hoffmann 
301f1ae32a1SGerd Hoffmann     uint8_t *buf[2];
302f1ae32a1SGerd Hoffmann     int fifolen[2];
303f1ae32a1SGerd Hoffmann     int fifostart[2];
304f1ae32a1SGerd Hoffmann     int fifoaddr[2];
305f1ae32a1SGerd Hoffmann     MUSBPacket packey[2];
306f1ae32a1SGerd Hoffmann     int status[2];
307f1ae32a1SGerd Hoffmann     int ext_size[2];
308f1ae32a1SGerd Hoffmann 
309f1ae32a1SGerd Hoffmann     /* For callbacks' use */
310f1ae32a1SGerd Hoffmann     int epnum;
311f1ae32a1SGerd Hoffmann     int interrupt[2];
312f1ae32a1SGerd Hoffmann     MUSBState *musb;
313f1ae32a1SGerd Hoffmann     USBCallback *delayed_cb[2];
314f1ae32a1SGerd Hoffmann     QEMUTimer *intv_timer[2];
315f1ae32a1SGerd Hoffmann };
316f1ae32a1SGerd Hoffmann 
317f1ae32a1SGerd Hoffmann struct MUSBState {
318f1ae32a1SGerd Hoffmann     qemu_irq irqs[musb_irq_max];
319f1ae32a1SGerd Hoffmann     USBBus bus;
320f1ae32a1SGerd Hoffmann     USBPort port;
321f1ae32a1SGerd Hoffmann 
322f1ae32a1SGerd Hoffmann     int idx;
323f1ae32a1SGerd Hoffmann     uint8_t devctl;
324f1ae32a1SGerd Hoffmann     uint8_t power;
325f1ae32a1SGerd Hoffmann     uint8_t faddr;
326f1ae32a1SGerd Hoffmann 
327f1ae32a1SGerd Hoffmann     uint8_t intr;
328f1ae32a1SGerd Hoffmann     uint8_t mask;
329f1ae32a1SGerd Hoffmann     uint16_t tx_intr;
330f1ae32a1SGerd Hoffmann     uint16_t tx_mask;
331f1ae32a1SGerd Hoffmann     uint16_t rx_intr;
332f1ae32a1SGerd Hoffmann     uint16_t rx_mask;
333f1ae32a1SGerd Hoffmann 
334f1ae32a1SGerd Hoffmann     int setup_len;
335f1ae32a1SGerd Hoffmann     int session;
336f1ae32a1SGerd Hoffmann 
337f1ae32a1SGerd Hoffmann     uint8_t buf[0x8000];
338f1ae32a1SGerd Hoffmann 
339f1ae32a1SGerd Hoffmann         /* Duplicating the world since 2008!...  probably we should have 32
340f1ae32a1SGerd Hoffmann          * logical, single endpoints instead.  */
341f1ae32a1SGerd Hoffmann     MUSBEndPoint ep[16];
342f1ae32a1SGerd Hoffmann };
343f1ae32a1SGerd Hoffmann 
344f1ae32a1SGerd Hoffmann void musb_reset(MUSBState *s)
345f1ae32a1SGerd Hoffmann {
346f1ae32a1SGerd Hoffmann     int i;
347f1ae32a1SGerd Hoffmann 
348f1ae32a1SGerd Hoffmann     s->faddr = 0x00;
349f1ae32a1SGerd Hoffmann     s->devctl = 0;
350f1ae32a1SGerd Hoffmann     s->power = MGC_M_POWER_HSENAB;
351f1ae32a1SGerd Hoffmann     s->tx_intr = 0x0000;
352f1ae32a1SGerd Hoffmann     s->rx_intr = 0x0000;
353f1ae32a1SGerd Hoffmann     s->tx_mask = 0xffff;
354f1ae32a1SGerd Hoffmann     s->rx_mask = 0xffff;
355f1ae32a1SGerd Hoffmann     s->intr = 0x00;
356f1ae32a1SGerd Hoffmann     s->mask = 0x06;
357f1ae32a1SGerd Hoffmann     s->idx = 0;
358f1ae32a1SGerd Hoffmann 
359f1ae32a1SGerd Hoffmann     s->setup_len = 0;
360f1ae32a1SGerd Hoffmann     s->session = 0;
361f1ae32a1SGerd Hoffmann     memset(s->buf, 0, sizeof(s->buf));
362f1ae32a1SGerd Hoffmann 
363f1ae32a1SGerd Hoffmann     /* TODO: _DW */
364f1ae32a1SGerd Hoffmann     s->ep[0].config = MGC_M_CONFIGDATA_SOFTCONE | MGC_M_CONFIGDATA_DYNFIFO;
365f1ae32a1SGerd Hoffmann     for (i = 0; i < 16; i ++) {
366f1ae32a1SGerd Hoffmann         s->ep[i].fifosize = 64;
367f1ae32a1SGerd Hoffmann         s->ep[i].maxp[0] = 0x40;
368f1ae32a1SGerd Hoffmann         s->ep[i].maxp[1] = 0x40;
369f1ae32a1SGerd Hoffmann         s->ep[i].musb = s;
370f1ae32a1SGerd Hoffmann         s->ep[i].epnum = i;
371f1ae32a1SGerd Hoffmann         usb_packet_init(&s->ep[i].packey[0].p);
372f1ae32a1SGerd Hoffmann         usb_packet_init(&s->ep[i].packey[1].p);
373f1ae32a1SGerd Hoffmann     }
374f1ae32a1SGerd Hoffmann }
375f1ae32a1SGerd Hoffmann 
376f1ae32a1SGerd Hoffmann struct MUSBState *musb_init(DeviceState *parent_device, int gpio_base)
377f1ae32a1SGerd Hoffmann {
378f1ae32a1SGerd Hoffmann     MUSBState *s = g_malloc0(sizeof(*s));
379f1ae32a1SGerd Hoffmann     int i;
380f1ae32a1SGerd Hoffmann 
381f1ae32a1SGerd Hoffmann     for (i = 0; i < musb_irq_max; i++) {
382f1ae32a1SGerd Hoffmann         s->irqs[i] = qdev_get_gpio_in(parent_device, gpio_base + i);
383f1ae32a1SGerd Hoffmann     }
384f1ae32a1SGerd Hoffmann 
385f1ae32a1SGerd Hoffmann     musb_reset(s);
386f1ae32a1SGerd Hoffmann 
387c889b3a5SAndreas Färber     usb_bus_new(&s->bus, sizeof(s->bus), &musb_bus_ops, parent_device);
388f1ae32a1SGerd Hoffmann     usb_register_port(&s->bus, &s->port, s, 0, &musb_port_ops,
389f1ae32a1SGerd Hoffmann                       USB_SPEED_MASK_LOW | USB_SPEED_MASK_FULL);
390f1ae32a1SGerd Hoffmann 
391f1ae32a1SGerd Hoffmann     return s;
392f1ae32a1SGerd Hoffmann }
393f1ae32a1SGerd Hoffmann 
394f1ae32a1SGerd Hoffmann static void musb_vbus_set(MUSBState *s, int level)
395f1ae32a1SGerd Hoffmann {
396f1ae32a1SGerd Hoffmann     if (level)
397f1ae32a1SGerd Hoffmann         s->devctl |= 3 << MGC_S_DEVCTL_VBUS;
398f1ae32a1SGerd Hoffmann     else
399f1ae32a1SGerd Hoffmann         s->devctl &= ~MGC_M_DEVCTL_VBUS;
400f1ae32a1SGerd Hoffmann 
401f1ae32a1SGerd Hoffmann     qemu_set_irq(s->irqs[musb_set_vbus], level);
402f1ae32a1SGerd Hoffmann }
403f1ae32a1SGerd Hoffmann 
404f1ae32a1SGerd Hoffmann static void musb_intr_set(MUSBState *s, int line, int level)
405f1ae32a1SGerd Hoffmann {
406f1ae32a1SGerd Hoffmann     if (!level) {
407f1ae32a1SGerd Hoffmann         s->intr &= ~(1 << line);
408f1ae32a1SGerd Hoffmann         qemu_irq_lower(s->irqs[line]);
409f1ae32a1SGerd Hoffmann     } else if (s->mask & (1 << line)) {
410f1ae32a1SGerd Hoffmann         s->intr |= 1 << line;
411f1ae32a1SGerd Hoffmann         qemu_irq_raise(s->irqs[line]);
412f1ae32a1SGerd Hoffmann     }
413f1ae32a1SGerd Hoffmann }
414f1ae32a1SGerd Hoffmann 
415f1ae32a1SGerd Hoffmann static void musb_tx_intr_set(MUSBState *s, int line, int level)
416f1ae32a1SGerd Hoffmann {
417f1ae32a1SGerd Hoffmann     if (!level) {
418f1ae32a1SGerd Hoffmann         s->tx_intr &= ~(1 << line);
419f1ae32a1SGerd Hoffmann         if (!s->tx_intr)
420f1ae32a1SGerd Hoffmann             qemu_irq_lower(s->irqs[musb_irq_tx]);
421f1ae32a1SGerd Hoffmann     } else if (s->tx_mask & (1 << line)) {
422f1ae32a1SGerd Hoffmann         s->tx_intr |= 1 << line;
423f1ae32a1SGerd Hoffmann         qemu_irq_raise(s->irqs[musb_irq_tx]);
424f1ae32a1SGerd Hoffmann     }
425f1ae32a1SGerd Hoffmann }
426f1ae32a1SGerd Hoffmann 
427f1ae32a1SGerd Hoffmann static void musb_rx_intr_set(MUSBState *s, int line, int level)
428f1ae32a1SGerd Hoffmann {
429f1ae32a1SGerd Hoffmann     if (line) {
430f1ae32a1SGerd Hoffmann         if (!level) {
431f1ae32a1SGerd Hoffmann             s->rx_intr &= ~(1 << line);
432f1ae32a1SGerd Hoffmann             if (!s->rx_intr)
433f1ae32a1SGerd Hoffmann                 qemu_irq_lower(s->irqs[musb_irq_rx]);
434f1ae32a1SGerd Hoffmann         } else if (s->rx_mask & (1 << line)) {
435f1ae32a1SGerd Hoffmann             s->rx_intr |= 1 << line;
436f1ae32a1SGerd Hoffmann             qemu_irq_raise(s->irqs[musb_irq_rx]);
437f1ae32a1SGerd Hoffmann         }
438f1ae32a1SGerd Hoffmann     } else
439f1ae32a1SGerd Hoffmann         musb_tx_intr_set(s, line, level);
440f1ae32a1SGerd Hoffmann }
441f1ae32a1SGerd Hoffmann 
442f1ae32a1SGerd Hoffmann uint32_t musb_core_intr_get(MUSBState *s)
443f1ae32a1SGerd Hoffmann {
444f1ae32a1SGerd Hoffmann     return (s->rx_intr << 15) | s->tx_intr;
445f1ae32a1SGerd Hoffmann }
446f1ae32a1SGerd Hoffmann 
447f1ae32a1SGerd Hoffmann void musb_core_intr_clear(MUSBState *s, uint32_t mask)
448f1ae32a1SGerd Hoffmann {
449f1ae32a1SGerd Hoffmann     if (s->rx_intr) {
450f1ae32a1SGerd Hoffmann         s->rx_intr &= mask >> 15;
451f1ae32a1SGerd Hoffmann         if (!s->rx_intr)
452f1ae32a1SGerd Hoffmann             qemu_irq_lower(s->irqs[musb_irq_rx]);
453f1ae32a1SGerd Hoffmann     }
454f1ae32a1SGerd Hoffmann 
455f1ae32a1SGerd Hoffmann     if (s->tx_intr) {
456f1ae32a1SGerd Hoffmann         s->tx_intr &= mask & 0xffff;
457f1ae32a1SGerd Hoffmann         if (!s->tx_intr)
458f1ae32a1SGerd Hoffmann             qemu_irq_lower(s->irqs[musb_irq_tx]);
459f1ae32a1SGerd Hoffmann     }
460f1ae32a1SGerd Hoffmann }
461f1ae32a1SGerd Hoffmann 
462f1ae32a1SGerd Hoffmann void musb_set_size(MUSBState *s, int epnum, int size, int is_tx)
463f1ae32a1SGerd Hoffmann {
464f1ae32a1SGerd Hoffmann     s->ep[epnum].ext_size[!is_tx] = size;
465f1ae32a1SGerd Hoffmann     s->ep[epnum].fifostart[0] = 0;
466f1ae32a1SGerd Hoffmann     s->ep[epnum].fifostart[1] = 0;
467f1ae32a1SGerd Hoffmann     s->ep[epnum].fifolen[0] = 0;
468f1ae32a1SGerd Hoffmann     s->ep[epnum].fifolen[1] = 0;
469f1ae32a1SGerd Hoffmann }
470f1ae32a1SGerd Hoffmann 
471f1ae32a1SGerd Hoffmann static void musb_session_update(MUSBState *s, int prev_dev, int prev_sess)
472f1ae32a1SGerd Hoffmann {
473f1ae32a1SGerd Hoffmann     int detect_prev = prev_dev && prev_sess;
474f1ae32a1SGerd Hoffmann     int detect = !!s->port.dev && s->session;
475f1ae32a1SGerd Hoffmann 
476f1ae32a1SGerd Hoffmann     if (detect && !detect_prev) {
477f1ae32a1SGerd Hoffmann         /* Let's skip the ID pin sense and VBUS sense formalities and
478f1ae32a1SGerd Hoffmann          * and signal a successful SRP directly.  This should work at least
479f1ae32a1SGerd Hoffmann          * for the Linux driver stack.  */
480f1ae32a1SGerd Hoffmann         musb_intr_set(s, musb_irq_connect, 1);
481f1ae32a1SGerd Hoffmann 
482f1ae32a1SGerd Hoffmann         if (s->port.dev->speed == USB_SPEED_LOW) {
483f1ae32a1SGerd Hoffmann             s->devctl &= ~MGC_M_DEVCTL_FSDEV;
484f1ae32a1SGerd Hoffmann             s->devctl |= MGC_M_DEVCTL_LSDEV;
485f1ae32a1SGerd Hoffmann         } else {
486f1ae32a1SGerd Hoffmann             s->devctl |= MGC_M_DEVCTL_FSDEV;
487f1ae32a1SGerd Hoffmann             s->devctl &= ~MGC_M_DEVCTL_LSDEV;
488f1ae32a1SGerd Hoffmann         }
489f1ae32a1SGerd Hoffmann 
490f1ae32a1SGerd Hoffmann         /* A-mode?  */
491f1ae32a1SGerd Hoffmann         s->devctl &= ~MGC_M_DEVCTL_BDEVICE;
492f1ae32a1SGerd Hoffmann 
493f1ae32a1SGerd Hoffmann         /* Host-mode bit?  */
494f1ae32a1SGerd Hoffmann         s->devctl |= MGC_M_DEVCTL_HM;
495f1ae32a1SGerd Hoffmann #if 1
496f1ae32a1SGerd Hoffmann         musb_vbus_set(s, 1);
497f1ae32a1SGerd Hoffmann #endif
498f1ae32a1SGerd Hoffmann     } else if (!detect && detect_prev) {
499f1ae32a1SGerd Hoffmann #if 1
500f1ae32a1SGerd Hoffmann         musb_vbus_set(s, 0);
501f1ae32a1SGerd Hoffmann #endif
502f1ae32a1SGerd Hoffmann     }
503f1ae32a1SGerd Hoffmann }
504f1ae32a1SGerd Hoffmann 
505f1ae32a1SGerd Hoffmann /* Attach or detach a device on our only port.  */
506f1ae32a1SGerd Hoffmann static void musb_attach(USBPort *port)
507f1ae32a1SGerd Hoffmann {
508f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) port->opaque;
509f1ae32a1SGerd Hoffmann 
510f1ae32a1SGerd Hoffmann     musb_intr_set(s, musb_irq_vbus_request, 1);
511f1ae32a1SGerd Hoffmann     musb_session_update(s, 0, s->session);
512f1ae32a1SGerd Hoffmann }
513f1ae32a1SGerd Hoffmann 
514f1ae32a1SGerd Hoffmann static void musb_detach(USBPort *port)
515f1ae32a1SGerd Hoffmann {
516f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) port->opaque;
517f1ae32a1SGerd Hoffmann 
518f1ae32a1SGerd Hoffmann     musb_async_cancel_device(s, port->dev);
519f1ae32a1SGerd Hoffmann 
520f1ae32a1SGerd Hoffmann     musb_intr_set(s, musb_irq_disconnect, 1);
521f1ae32a1SGerd Hoffmann     musb_session_update(s, 1, s->session);
522f1ae32a1SGerd Hoffmann }
523f1ae32a1SGerd Hoffmann 
524f1ae32a1SGerd Hoffmann static void musb_child_detach(USBPort *port, USBDevice *child)
525f1ae32a1SGerd Hoffmann {
526f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) port->opaque;
527f1ae32a1SGerd Hoffmann 
528f1ae32a1SGerd Hoffmann     musb_async_cancel_device(s, child);
529f1ae32a1SGerd Hoffmann }
530f1ae32a1SGerd Hoffmann 
531f1ae32a1SGerd Hoffmann static void musb_cb_tick0(void *opaque)
532f1ae32a1SGerd Hoffmann {
533f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
534f1ae32a1SGerd Hoffmann 
535f1ae32a1SGerd Hoffmann     ep->delayed_cb[0](&ep->packey[0].p, opaque);
536f1ae32a1SGerd Hoffmann }
537f1ae32a1SGerd Hoffmann 
538f1ae32a1SGerd Hoffmann static void musb_cb_tick1(void *opaque)
539f1ae32a1SGerd Hoffmann {
540f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
541f1ae32a1SGerd Hoffmann 
542f1ae32a1SGerd Hoffmann     ep->delayed_cb[1](&ep->packey[1].p, opaque);
543f1ae32a1SGerd Hoffmann }
544f1ae32a1SGerd Hoffmann 
545f1ae32a1SGerd Hoffmann #define musb_cb_tick	(dir ? musb_cb_tick1 : musb_cb_tick0)
546f1ae32a1SGerd Hoffmann 
547f1ae32a1SGerd Hoffmann static void musb_schedule_cb(USBPort *port, USBPacket *packey)
548f1ae32a1SGerd Hoffmann {
549f1ae32a1SGerd Hoffmann     MUSBPacket *p = container_of(packey, MUSBPacket, p);
550f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = p->ep;
551f1ae32a1SGerd Hoffmann     int dir = p->dir;
552f1ae32a1SGerd Hoffmann     int timeout = 0;
553f1ae32a1SGerd Hoffmann 
554f1ae32a1SGerd Hoffmann     if (ep->status[dir] == USB_RET_NAK)
555f1ae32a1SGerd Hoffmann         timeout = ep->timeout[dir];
556f1ae32a1SGerd Hoffmann     else if (ep->interrupt[dir])
557f1ae32a1SGerd Hoffmann         timeout = 8;
558e7ae771fSStefan Weil     else {
559e7ae771fSStefan Weil         musb_cb_tick(ep);
560e7ae771fSStefan Weil         return;
561e7ae771fSStefan Weil     }
562f1ae32a1SGerd Hoffmann 
563f1ae32a1SGerd Hoffmann     if (!ep->intv_timer[dir])
564bc72ad67SAlex Bligh         ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
565f1ae32a1SGerd Hoffmann 
566bc72ad67SAlex Bligh     timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
56773bcb24dSRutuja Shah                    muldiv64(timeout, NANOSECONDS_PER_SECOND, 8000));
568f1ae32a1SGerd Hoffmann }
569f1ae32a1SGerd Hoffmann 
570f1ae32a1SGerd Hoffmann static int musb_timeout(int ttype, int speed, int val)
571f1ae32a1SGerd Hoffmann {
572f1ae32a1SGerd Hoffmann #if 1
573f1ae32a1SGerd Hoffmann     return val << 3;
574f1ae32a1SGerd Hoffmann #endif
575f1ae32a1SGerd Hoffmann 
576f1ae32a1SGerd Hoffmann     switch (ttype) {
577f1ae32a1SGerd Hoffmann     case USB_ENDPOINT_XFER_CONTROL:
578f1ae32a1SGerd Hoffmann         if (val < 2)
579f1ae32a1SGerd Hoffmann             return 0;
580f1ae32a1SGerd Hoffmann         else if (speed == USB_SPEED_HIGH)
581f1ae32a1SGerd Hoffmann             return 1 << (val - 1);
582f1ae32a1SGerd Hoffmann         else
583f1ae32a1SGerd Hoffmann             return 8 << (val - 1);
584f1ae32a1SGerd Hoffmann 
585f1ae32a1SGerd Hoffmann     case USB_ENDPOINT_XFER_INT:
586f1ae32a1SGerd Hoffmann         if (speed == USB_SPEED_HIGH)
587f1ae32a1SGerd Hoffmann             if (val < 2)
588f1ae32a1SGerd Hoffmann                 return 0;
589f1ae32a1SGerd Hoffmann             else
590f1ae32a1SGerd Hoffmann                 return 1 << (val - 1);
591f1ae32a1SGerd Hoffmann         else
592f1ae32a1SGerd Hoffmann             return val << 3;
593f1ae32a1SGerd Hoffmann 
594f1ae32a1SGerd Hoffmann     case USB_ENDPOINT_XFER_BULK:
595f1ae32a1SGerd Hoffmann     case USB_ENDPOINT_XFER_ISOC:
596f1ae32a1SGerd Hoffmann         if (val < 2)
597f1ae32a1SGerd Hoffmann             return 0;
598f1ae32a1SGerd Hoffmann         else if (speed == USB_SPEED_HIGH)
599f1ae32a1SGerd Hoffmann             return 1 << (val - 1);
600f1ae32a1SGerd Hoffmann         else
601f1ae32a1SGerd Hoffmann             return 8 << (val - 1);
602f1ae32a1SGerd Hoffmann         /* TODO: what with low-speed Bulk and Isochronous?  */
603f1ae32a1SGerd Hoffmann     }
604f1ae32a1SGerd Hoffmann 
605f1ae32a1SGerd Hoffmann     hw_error("bad interval\n");
606f1ae32a1SGerd Hoffmann }
607f1ae32a1SGerd Hoffmann 
608f1ae32a1SGerd Hoffmann static void musb_packet(MUSBState *s, MUSBEndPoint *ep,
609f1ae32a1SGerd Hoffmann                 int epnum, int pid, int len, USBCallback cb, int dir)
610f1ae32a1SGerd Hoffmann {
611f1ae32a1SGerd Hoffmann     USBDevice *dev;
612f1ae32a1SGerd Hoffmann     USBEndpoint *uep;
613f1ae32a1SGerd Hoffmann     int idx = epnum && dir;
614a9be7657SPaolo Bonzini     int id;
615f1ae32a1SGerd Hoffmann     int ttype;
616f1ae32a1SGerd Hoffmann 
617f1ae32a1SGerd Hoffmann     /* ep->type[0,1] contains:
618f1ae32a1SGerd Hoffmann      * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
619f1ae32a1SGerd Hoffmann      * in bits 5:4 the transfer type (BULK / INT)
620f1ae32a1SGerd Hoffmann      * in bits 3:0 the EP num
621f1ae32a1SGerd Hoffmann      */
622f1ae32a1SGerd Hoffmann     ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
623f1ae32a1SGerd Hoffmann 
624f1ae32a1SGerd Hoffmann     ep->timeout[dir] = musb_timeout(ttype,
625f1ae32a1SGerd Hoffmann                     ep->type[idx] >> 6, ep->interval[idx]);
626f1ae32a1SGerd Hoffmann     ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
627f1ae32a1SGerd Hoffmann     ep->delayed_cb[dir] = cb;
628f1ae32a1SGerd Hoffmann 
629f1ae32a1SGerd Hoffmann     /* A wild guess on the FADDR semantics... */
630f1ae32a1SGerd Hoffmann     dev = usb_find_device(&s->port, ep->faddr[idx]);
631e87fd1e6SLiam Merwick     if (dev == NULL) {
632e87fd1e6SLiam Merwick         return;
633a9be7657SPaolo Bonzini     }
634e87fd1e6SLiam Merwick     uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
635e87fd1e6SLiam Merwick     id = pid | (dev->addr << 16) | (uep->nr << 8);
636a9be7657SPaolo Bonzini     usb_packet_setup(&ep->packey[dir].p, pid, uep, 0, id, false, true);
637f1ae32a1SGerd Hoffmann     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
638f1ae32a1SGerd Hoffmann     ep->packey[dir].ep = ep;
639f1ae32a1SGerd Hoffmann     ep->packey[dir].dir = dir;
640f1ae32a1SGerd Hoffmann 
6419a77a0f5SHans de Goede     usb_handle_packet(dev, &ep->packey[dir].p);
642f1ae32a1SGerd Hoffmann 
6439a77a0f5SHans de Goede     if (ep->packey[dir].p.status == USB_RET_ASYNC) {
64436dfe324SHans de Goede         usb_device_flush_ep_queue(dev, uep);
645f1ae32a1SGerd Hoffmann         ep->status[dir] = len;
646f1ae32a1SGerd Hoffmann         return;
647f1ae32a1SGerd Hoffmann     }
648f1ae32a1SGerd Hoffmann 
6499a77a0f5SHans de Goede     if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
6509a77a0f5SHans de Goede         ep->status[dir] = ep->packey[dir].p.actual_length;
6519a77a0f5SHans de Goede     } else {
6529a77a0f5SHans de Goede         ep->status[dir] = ep->packey[dir].p.status;
6539a77a0f5SHans de Goede     }
654f1ae32a1SGerd Hoffmann     musb_schedule_cb(&s->port, &ep->packey[dir].p);
655f1ae32a1SGerd Hoffmann }
656f1ae32a1SGerd Hoffmann 
657f1ae32a1SGerd Hoffmann static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
658f1ae32a1SGerd Hoffmann {
659f1ae32a1SGerd Hoffmann     /* Unfortunately we can't use packey->devep because that's the remote
660f1ae32a1SGerd Hoffmann      * endpoint number and may be different than our local.  */
661f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
662f1ae32a1SGerd Hoffmann     int epnum = ep->epnum;
663f1ae32a1SGerd Hoffmann     MUSBState *s = ep->musb;
664f1ae32a1SGerd Hoffmann 
665f1ae32a1SGerd Hoffmann     ep->fifostart[0] = 0;
666f1ae32a1SGerd Hoffmann     ep->fifolen[0] = 0;
667f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
668f1ae32a1SGerd Hoffmann     if (ep->status[0] != USB_RET_NAK) {
669f1ae32a1SGerd Hoffmann #endif
670f1ae32a1SGerd Hoffmann         if (epnum)
671f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
672f1ae32a1SGerd Hoffmann         else
673f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
674f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
675f1ae32a1SGerd Hoffmann     }
676f1ae32a1SGerd Hoffmann #endif
677f1ae32a1SGerd Hoffmann 
678f1ae32a1SGerd Hoffmann     /* Clear all of the error bits first */
679f1ae32a1SGerd Hoffmann     if (epnum)
680f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
681f1ae32a1SGerd Hoffmann                         MGC_M_TXCSR_H_NAKTIMEOUT);
682f1ae32a1SGerd Hoffmann     else
683f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
684f1ae32a1SGerd Hoffmann                         MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
685f1ae32a1SGerd Hoffmann 
686f1ae32a1SGerd Hoffmann     if (ep->status[0] == USB_RET_STALL) {
687f1ae32a1SGerd Hoffmann         /* Command not supported by target! */
688f1ae32a1SGerd Hoffmann         ep->status[0] = 0;
689f1ae32a1SGerd Hoffmann 
690f1ae32a1SGerd Hoffmann         if (epnum)
691f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
692f1ae32a1SGerd Hoffmann         else
693f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
694f1ae32a1SGerd Hoffmann     }
695f1ae32a1SGerd Hoffmann 
696f1ae32a1SGerd Hoffmann     if (ep->status[0] == USB_RET_NAK) {
697f1ae32a1SGerd Hoffmann         ep->status[0] = 0;
698f1ae32a1SGerd Hoffmann 
699f1ae32a1SGerd Hoffmann         /* NAK timeouts are only generated in Bulk transfers and
700f1ae32a1SGerd Hoffmann          * Data-errors in Isochronous.  */
701f1ae32a1SGerd Hoffmann         if (ep->interrupt[0]) {
702f1ae32a1SGerd Hoffmann             return;
703f1ae32a1SGerd Hoffmann         }
704f1ae32a1SGerd Hoffmann 
705f1ae32a1SGerd Hoffmann         if (epnum)
706f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
707f1ae32a1SGerd Hoffmann         else
708f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
709f1ae32a1SGerd Hoffmann     }
710f1ae32a1SGerd Hoffmann 
711f1ae32a1SGerd Hoffmann     if (ep->status[0] < 0) {
712f1ae32a1SGerd Hoffmann         if (ep->status[0] == USB_RET_BABBLE)
713f1ae32a1SGerd Hoffmann             musb_intr_set(s, musb_irq_rst_babble, 1);
714f1ae32a1SGerd Hoffmann 
715f1ae32a1SGerd Hoffmann         /* Pretend we've tried three times already and failed (in
716f1ae32a1SGerd Hoffmann          * case of USB_TOKEN_SETUP).  */
717f1ae32a1SGerd Hoffmann         if (epnum)
718f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
719f1ae32a1SGerd Hoffmann         else
720f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_ERROR;
721f1ae32a1SGerd Hoffmann 
722f1ae32a1SGerd Hoffmann         musb_tx_intr_set(s, epnum, 1);
723f1ae32a1SGerd Hoffmann         return;
724f1ae32a1SGerd Hoffmann     }
725f1ae32a1SGerd Hoffmann     /* TODO: check len for over/underruns of an OUT packet?  */
726f1ae32a1SGerd Hoffmann 
727f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK
728f1ae32a1SGerd Hoffmann     if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
729f1ae32a1SGerd Hoffmann         s->setup_len = ep->packey[0].data[6];
730f1ae32a1SGerd Hoffmann #endif
731f1ae32a1SGerd Hoffmann 
732f1ae32a1SGerd Hoffmann     /* In DMA mode: if no error, assert DMA request for this EP,
733f1ae32a1SGerd Hoffmann      * and skip the interrupt.  */
734f1ae32a1SGerd Hoffmann     musb_tx_intr_set(s, epnum, 1);
735f1ae32a1SGerd Hoffmann }
736f1ae32a1SGerd Hoffmann 
737f1ae32a1SGerd Hoffmann static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
738f1ae32a1SGerd Hoffmann {
739f1ae32a1SGerd Hoffmann     /* Unfortunately we can't use packey->devep because that's the remote
740f1ae32a1SGerd Hoffmann      * endpoint number and may be different than our local.  */
741f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
742f1ae32a1SGerd Hoffmann     int epnum = ep->epnum;
743f1ae32a1SGerd Hoffmann     MUSBState *s = ep->musb;
744f1ae32a1SGerd Hoffmann 
745f1ae32a1SGerd Hoffmann     ep->fifostart[1] = 0;
746f1ae32a1SGerd Hoffmann     ep->fifolen[1] = 0;
747f1ae32a1SGerd Hoffmann 
748f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
749f1ae32a1SGerd Hoffmann     if (ep->status[1] != USB_RET_NAK) {
750f1ae32a1SGerd Hoffmann #endif
751f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
752f1ae32a1SGerd Hoffmann         if (!epnum)
753f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
754f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
755f1ae32a1SGerd Hoffmann     }
756f1ae32a1SGerd Hoffmann #endif
757f1ae32a1SGerd Hoffmann 
758f1ae32a1SGerd Hoffmann     /* Clear all of the imaginable error bits first */
759f1ae32a1SGerd Hoffmann     ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
760f1ae32a1SGerd Hoffmann                     MGC_M_RXCSR_DATAERROR);
761f1ae32a1SGerd Hoffmann     if (!epnum)
762f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
763f1ae32a1SGerd Hoffmann                         MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
764f1ae32a1SGerd Hoffmann 
765f1ae32a1SGerd Hoffmann     if (ep->status[1] == USB_RET_STALL) {
766f1ae32a1SGerd Hoffmann         ep->status[1] = 0;
767f1ae32a1SGerd Hoffmann 
768f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
769f1ae32a1SGerd Hoffmann         if (!epnum)
770f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
771f1ae32a1SGerd Hoffmann     }
772f1ae32a1SGerd Hoffmann 
773f1ae32a1SGerd Hoffmann     if (ep->status[1] == USB_RET_NAK) {
774f1ae32a1SGerd Hoffmann         ep->status[1] = 0;
775f1ae32a1SGerd Hoffmann 
776f1ae32a1SGerd Hoffmann         /* NAK timeouts are only generated in Bulk transfers and
777f1ae32a1SGerd Hoffmann          * Data-errors in Isochronous.  */
778e7ae771fSStefan Weil         if (ep->interrupt[1]) {
779e7ae771fSStefan Weil             musb_packet(s, ep, epnum, USB_TOKEN_IN,
780f1ae32a1SGerd Hoffmann                         packey->iov.size, musb_rx_packet_complete, 1);
781e7ae771fSStefan Weil             return;
782e7ae771fSStefan Weil         }
783f1ae32a1SGerd Hoffmann 
784f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
785f1ae32a1SGerd Hoffmann         if (!epnum)
786f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
787f1ae32a1SGerd Hoffmann     }
788f1ae32a1SGerd Hoffmann 
789f1ae32a1SGerd Hoffmann     if (ep->status[1] < 0) {
790f1ae32a1SGerd Hoffmann         if (ep->status[1] == USB_RET_BABBLE) {
791f1ae32a1SGerd Hoffmann             musb_intr_set(s, musb_irq_rst_babble, 1);
792f1ae32a1SGerd Hoffmann             return;
793f1ae32a1SGerd Hoffmann         }
794f1ae32a1SGerd Hoffmann 
795f1ae32a1SGerd Hoffmann         /* Pretend we've tried three times already and failed (in
796f1ae32a1SGerd Hoffmann          * case of a control transfer).  */
797f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
798f1ae32a1SGerd Hoffmann         if (!epnum)
799f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_ERROR;
800f1ae32a1SGerd Hoffmann 
801f1ae32a1SGerd Hoffmann         musb_rx_intr_set(s, epnum, 1);
802f1ae32a1SGerd Hoffmann         return;
803f1ae32a1SGerd Hoffmann     }
804f1ae32a1SGerd Hoffmann     /* TODO: check len for over/underruns of an OUT packet?  */
805f1ae32a1SGerd Hoffmann     /* TODO: perhaps make use of e->ext_size[1] here.  */
806f1ae32a1SGerd Hoffmann 
807f1ae32a1SGerd Hoffmann     if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
808f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
809f1ae32a1SGerd Hoffmann         if (!epnum)
810f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
811f1ae32a1SGerd Hoffmann 
8129a77a0f5SHans de Goede         ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
813f1ae32a1SGerd Hoffmann         /* In DMA mode: assert DMA request for this EP */
814f1ae32a1SGerd Hoffmann     }
815f1ae32a1SGerd Hoffmann 
816f1ae32a1SGerd Hoffmann     /* Only if DMA has not been asserted */
817f1ae32a1SGerd Hoffmann     musb_rx_intr_set(s, epnum, 1);
818f1ae32a1SGerd Hoffmann }
819f1ae32a1SGerd Hoffmann 
820f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
821f1ae32a1SGerd Hoffmann {
822f1ae32a1SGerd Hoffmann     int ep, dir;
823f1ae32a1SGerd Hoffmann 
824f1ae32a1SGerd Hoffmann     for (ep = 0; ep < 16; ep++) {
825f1ae32a1SGerd Hoffmann         for (dir = 0; dir < 2; dir++) {
826f1ae32a1SGerd Hoffmann             if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
827f1ae32a1SGerd Hoffmann                 s->ep[ep].packey[dir].p.ep->dev != dev) {
828f1ae32a1SGerd Hoffmann                 continue;
829f1ae32a1SGerd Hoffmann             }
830f1ae32a1SGerd Hoffmann             usb_cancel_packet(&s->ep[ep].packey[dir].p);
831f1ae32a1SGerd Hoffmann             /* status updates needed here? */
832f1ae32a1SGerd Hoffmann         }
833f1ae32a1SGerd Hoffmann     }
834f1ae32a1SGerd Hoffmann }
835f1ae32a1SGerd Hoffmann 
836f1ae32a1SGerd Hoffmann static void musb_tx_rdy(MUSBState *s, int epnum)
837f1ae32a1SGerd Hoffmann {
838f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = s->ep + epnum;
839f1ae32a1SGerd Hoffmann     int pid;
840f1ae32a1SGerd Hoffmann     int total, valid = 0;
841f1ae32a1SGerd Hoffmann     TRACE("start %d, len %d",  ep->fifostart[0], ep->fifolen[0] );
842f1ae32a1SGerd Hoffmann     ep->fifostart[0] += ep->fifolen[0];
843f1ae32a1SGerd Hoffmann     ep->fifolen[0] = 0;
844f1ae32a1SGerd Hoffmann 
845f1ae32a1SGerd Hoffmann     /* XXX: how's the total size of the packet retrieved exactly in
846f1ae32a1SGerd Hoffmann      * the generic case?  */
847f1ae32a1SGerd Hoffmann     total = ep->maxp[0] & 0x3ff;
848f1ae32a1SGerd Hoffmann 
849f1ae32a1SGerd Hoffmann     if (ep->ext_size[0]) {
850f1ae32a1SGerd Hoffmann         total = ep->ext_size[0];
851f1ae32a1SGerd Hoffmann         ep->ext_size[0] = 0;
852f1ae32a1SGerd Hoffmann         valid = 1;
853f1ae32a1SGerd Hoffmann     }
854f1ae32a1SGerd Hoffmann 
855f1ae32a1SGerd Hoffmann     /* If the packet is not fully ready yet, wait for a next segment.  */
856f1ae32a1SGerd Hoffmann     if (epnum && (ep->fifostart[0]) < total)
857f1ae32a1SGerd Hoffmann         return;
858f1ae32a1SGerd Hoffmann 
859f1ae32a1SGerd Hoffmann     if (!valid)
860f1ae32a1SGerd Hoffmann         total = ep->fifostart[0];
861f1ae32a1SGerd Hoffmann 
862f1ae32a1SGerd Hoffmann     pid = USB_TOKEN_OUT;
863f1ae32a1SGerd Hoffmann     if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
864f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_SETUP;
865f1ae32a1SGerd Hoffmann         if (total != 8) {
866f1ae32a1SGerd Hoffmann             TRACE("illegal SETUPPKT length of %i bytes", total);
867f1ae32a1SGerd Hoffmann         }
868f1ae32a1SGerd Hoffmann         /* Controller should retry SETUP packets three times on errors
869f1ae32a1SGerd Hoffmann          * but it doesn't make sense for us to do that.  */
870f1ae32a1SGerd Hoffmann     }
871f1ae32a1SGerd Hoffmann 
872e7ae771fSStefan Weil     musb_packet(s, ep, epnum, pid, total, musb_tx_packet_complete, 0);
873f1ae32a1SGerd Hoffmann }
874f1ae32a1SGerd Hoffmann 
875f1ae32a1SGerd Hoffmann static void musb_rx_req(MUSBState *s, int epnum)
876f1ae32a1SGerd Hoffmann {
877f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = s->ep + epnum;
878f1ae32a1SGerd Hoffmann     int total;
879f1ae32a1SGerd Hoffmann 
880f1ae32a1SGerd Hoffmann     /* If we already have a packet, which didn't fit into the
881f1ae32a1SGerd Hoffmann      * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
882f1ae32a1SGerd Hoffmann     if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
883f1ae32a1SGerd Hoffmann                     (ep->fifostart[1]) + ep->rxcount <
884f1ae32a1SGerd Hoffmann                     ep->packey[1].p.iov.size) {
885f1ae32a1SGerd Hoffmann         TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
886f1ae32a1SGerd Hoffmann         ep->fifostart[1] += ep->rxcount;
887f1ae32a1SGerd Hoffmann         ep->fifolen[1] = 0;
888f1ae32a1SGerd Hoffmann 
889f1ae32a1SGerd Hoffmann         ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
890f1ae32a1SGerd Hoffmann                         ep->maxp[1]);
891f1ae32a1SGerd Hoffmann 
892f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
893f1ae32a1SGerd Hoffmann         if (!epnum)
894f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
895f1ae32a1SGerd Hoffmann 
896f1ae32a1SGerd Hoffmann         /* Clear all of the error bits first */
897f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
898f1ae32a1SGerd Hoffmann                         MGC_M_RXCSR_DATAERROR);
899f1ae32a1SGerd Hoffmann         if (!epnum)
900f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
901f1ae32a1SGerd Hoffmann                             MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
902f1ae32a1SGerd Hoffmann 
903f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
904f1ae32a1SGerd Hoffmann         if (!epnum)
905f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
906f1ae32a1SGerd Hoffmann         musb_rx_intr_set(s, epnum, 1);
907f1ae32a1SGerd Hoffmann         return;
908f1ae32a1SGerd Hoffmann     }
909f1ae32a1SGerd Hoffmann 
910f1ae32a1SGerd Hoffmann     /* The driver sets maxp[1] to 64 or less because it knows the hardware
911f1ae32a1SGerd Hoffmann      * FIFO is this deep.  Bigger packets get split in
912f1ae32a1SGerd Hoffmann      * usb_generic_handle_packet but we can also do the splitting locally
913f1ae32a1SGerd Hoffmann      * for performance.  It turns out we can also have a bigger FIFO and
914f1ae32a1SGerd Hoffmann      * ignore the limit set in ep->maxp[1].  The Linux MUSB driver deals
915f1ae32a1SGerd Hoffmann      * OK with single packets of even 32KB and we avoid splitting, however
916f1ae32a1SGerd Hoffmann      * usb_msd.c sometimes sends a packet bigger than what Linux expects
917f1ae32a1SGerd Hoffmann      * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN.  Splitting
918f1ae32a1SGerd Hoffmann      * hides this overrun from Linux.  Up to 4096 everything is fine
919f1ae32a1SGerd Hoffmann      * though.  Currently this is disabled.
920f1ae32a1SGerd Hoffmann      *
921f1ae32a1SGerd Hoffmann      * XXX: mind ep->fifosize.  */
922f1ae32a1SGerd Hoffmann     total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
923f1ae32a1SGerd Hoffmann 
924f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK
925f1ae32a1SGerd Hoffmann     /* Why should *we* do that instead of Linux?  */
926f1ae32a1SGerd Hoffmann     if (!epnum) {
927f1ae32a1SGerd Hoffmann         if (ep->packey[0].p.devaddr == 2) {
928f1ae32a1SGerd Hoffmann             total = MIN(s->setup_len, 8);
929f1ae32a1SGerd Hoffmann         } else {
930f1ae32a1SGerd Hoffmann             total = MIN(s->setup_len, 64);
931f1ae32a1SGerd Hoffmann         }
932f1ae32a1SGerd Hoffmann         s->setup_len -= total;
933f1ae32a1SGerd Hoffmann     }
934f1ae32a1SGerd Hoffmann #endif
935f1ae32a1SGerd Hoffmann 
936e7ae771fSStefan Weil     musb_packet(s, ep, epnum, USB_TOKEN_IN, total, musb_rx_packet_complete, 1);
937f1ae32a1SGerd Hoffmann }
938f1ae32a1SGerd Hoffmann 
939f1ae32a1SGerd Hoffmann static uint8_t musb_read_fifo(MUSBEndPoint *ep)
940f1ae32a1SGerd Hoffmann {
941f1ae32a1SGerd Hoffmann     uint8_t value;
942f1ae32a1SGerd Hoffmann     if (ep->fifolen[1] >= 64) {
943f1ae32a1SGerd Hoffmann         /* We have a FIFO underrun */
944f1ae32a1SGerd Hoffmann         TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
945f1ae32a1SGerd Hoffmann         return 0x00000000;
946f1ae32a1SGerd Hoffmann     }
947f1ae32a1SGerd Hoffmann     /* In DMA mode clear RXPKTRDY and set REQPKT automatically
948f1ae32a1SGerd Hoffmann      * (if AUTOREQ is set) */
949f1ae32a1SGerd Hoffmann 
950f1ae32a1SGerd Hoffmann     ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
951f1ae32a1SGerd Hoffmann     value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
952f1ae32a1SGerd Hoffmann     TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
953f1ae32a1SGerd Hoffmann     return value;
954f1ae32a1SGerd Hoffmann }
955f1ae32a1SGerd Hoffmann 
956f1ae32a1SGerd Hoffmann static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
957f1ae32a1SGerd Hoffmann {
958f1ae32a1SGerd Hoffmann     TRACE("EP%d = %02x", ep->epnum, value);
959f1ae32a1SGerd Hoffmann     if (ep->fifolen[0] >= 64) {
960f1ae32a1SGerd Hoffmann         /* We have a FIFO overrun */
961f1ae32a1SGerd Hoffmann         TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
962f1ae32a1SGerd Hoffmann         return;
963f1ae32a1SGerd Hoffmann      }
964f1ae32a1SGerd Hoffmann 
965f1ae32a1SGerd Hoffmann      ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
966f1ae32a1SGerd Hoffmann      ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
967f1ae32a1SGerd Hoffmann }
968f1ae32a1SGerd Hoffmann 
969f1ae32a1SGerd Hoffmann static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
970f1ae32a1SGerd Hoffmann {
971f1ae32a1SGerd Hoffmann     if (ep->intv_timer[dir])
972bc72ad67SAlex Bligh         timer_del(ep->intv_timer[dir]);
973f1ae32a1SGerd Hoffmann }
974f1ae32a1SGerd Hoffmann 
975f1ae32a1SGerd Hoffmann /* Bus control */
976f1ae32a1SGerd Hoffmann static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
977f1ae32a1SGerd Hoffmann {
978f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
979f1ae32a1SGerd Hoffmann 
980f1ae32a1SGerd Hoffmann     switch (addr) {
981f1ae32a1SGerd Hoffmann     /* For USB2.0 HS hubs only */
982f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBADDR:
983f1ae32a1SGerd Hoffmann         return s->ep[ep].haddr[0];
984f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBPORT:
985f1ae32a1SGerd Hoffmann         return s->ep[ep].hport[0];
986f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBADDR:
987f1ae32a1SGerd Hoffmann         return s->ep[ep].haddr[1];
988f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBPORT:
989f1ae32a1SGerd Hoffmann         return s->ep[ep].hport[1];
990f1ae32a1SGerd Hoffmann 
991f1ae32a1SGerd Hoffmann     default:
992f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
993f1ae32a1SGerd Hoffmann         return 0x00;
994f1ae32a1SGerd Hoffmann     };
995f1ae32a1SGerd Hoffmann }
996f1ae32a1SGerd Hoffmann 
997f1ae32a1SGerd Hoffmann static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
998f1ae32a1SGerd Hoffmann {
999f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1000f1ae32a1SGerd Hoffmann 
1001f1ae32a1SGerd Hoffmann     switch (addr) {
1002f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
1003f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[0] = value;
1004f1ae32a1SGerd Hoffmann         break;
1005f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
1006f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[1] = value;
1007f1ae32a1SGerd Hoffmann         break;
1008f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBADDR:
1009f1ae32a1SGerd Hoffmann         s->ep[ep].haddr[0] = value;
1010f1ae32a1SGerd Hoffmann         break;
1011f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBPORT:
1012f1ae32a1SGerd Hoffmann         s->ep[ep].hport[0] = value;
1013f1ae32a1SGerd Hoffmann         break;
1014f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBADDR:
1015f1ae32a1SGerd Hoffmann         s->ep[ep].haddr[1] = value;
1016f1ae32a1SGerd Hoffmann         break;
1017f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBPORT:
1018f1ae32a1SGerd Hoffmann         s->ep[ep].hport[1] = value;
1019f1ae32a1SGerd Hoffmann         break;
1020f1ae32a1SGerd Hoffmann 
1021f1ae32a1SGerd Hoffmann     default:
1022f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1023f1ae32a1SGerd Hoffmann         break;
1024f1ae32a1SGerd Hoffmann     };
1025f1ae32a1SGerd Hoffmann }
1026f1ae32a1SGerd Hoffmann 
1027f1ae32a1SGerd Hoffmann static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
1028f1ae32a1SGerd Hoffmann {
1029f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1030f1ae32a1SGerd Hoffmann 
1031f1ae32a1SGerd Hoffmann     switch (addr) {
1032f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
1033f1ae32a1SGerd Hoffmann         return s->ep[ep].faddr[0];
1034f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
1035f1ae32a1SGerd Hoffmann         return s->ep[ep].faddr[1];
1036f1ae32a1SGerd Hoffmann 
1037f1ae32a1SGerd Hoffmann     default:
1038f1ae32a1SGerd Hoffmann         return musb_busctl_readb(s, ep, addr) |
1039f1ae32a1SGerd Hoffmann                 (musb_busctl_readb(s, ep, addr | 1) << 8);
1040f1ae32a1SGerd Hoffmann     };
1041f1ae32a1SGerd Hoffmann }
1042f1ae32a1SGerd Hoffmann 
1043f1ae32a1SGerd Hoffmann static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
1044f1ae32a1SGerd Hoffmann {
1045f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1046f1ae32a1SGerd Hoffmann 
1047f1ae32a1SGerd Hoffmann     switch (addr) {
1048f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
1049f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[0] = value;
1050f1ae32a1SGerd Hoffmann         break;
1051f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
1052f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[1] = value;
1053f1ae32a1SGerd Hoffmann         break;
1054f1ae32a1SGerd Hoffmann 
1055f1ae32a1SGerd Hoffmann     default:
1056f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr, value & 0xff);
1057f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr | 1, value >> 8);
1058f1ae32a1SGerd Hoffmann     };
1059f1ae32a1SGerd Hoffmann }
1060f1ae32a1SGerd Hoffmann 
1061f1ae32a1SGerd Hoffmann /* Endpoint control */
1062f1ae32a1SGerd Hoffmann static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
1063f1ae32a1SGerd Hoffmann {
1064f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1065f1ae32a1SGerd Hoffmann 
1066f1ae32a1SGerd Hoffmann     switch (addr) {
1067f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXTYPE:
1068f1ae32a1SGerd Hoffmann         return s->ep[ep].type[0];
1069f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXINTERVAL:
1070f1ae32a1SGerd Hoffmann         return s->ep[ep].interval[0];
1071f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXTYPE:
1072f1ae32a1SGerd Hoffmann         return s->ep[ep].type[1];
1073f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXINTERVAL:
1074f1ae32a1SGerd Hoffmann         return s->ep[ep].interval[1];
1075f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_FIFOSIZE & ~1):
1076f1ae32a1SGerd Hoffmann         return 0x00;
1077f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFOSIZE:
1078f1ae32a1SGerd Hoffmann         return ep ? s->ep[ep].fifosize : s->ep[ep].config;
1079f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1080f1ae32a1SGerd Hoffmann         return s->ep[ep].rxcount;
1081f1ae32a1SGerd Hoffmann 
1082f1ae32a1SGerd Hoffmann     default:
1083f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1084f1ae32a1SGerd Hoffmann         return 0x00;
1085f1ae32a1SGerd Hoffmann     };
1086f1ae32a1SGerd Hoffmann }
1087f1ae32a1SGerd Hoffmann 
1088f1ae32a1SGerd Hoffmann static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
1089f1ae32a1SGerd Hoffmann {
1090f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1091f1ae32a1SGerd Hoffmann 
1092f1ae32a1SGerd Hoffmann     switch (addr) {
1093f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXTYPE:
1094f1ae32a1SGerd Hoffmann         s->ep[ep].type[0] = value;
1095f1ae32a1SGerd Hoffmann         break;
1096f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXINTERVAL:
1097f1ae32a1SGerd Hoffmann         s->ep[ep].interval[0] = value;
1098f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 0);
1099f1ae32a1SGerd Hoffmann         break;
1100f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXTYPE:
1101f1ae32a1SGerd Hoffmann         s->ep[ep].type[1] = value;
1102f1ae32a1SGerd Hoffmann         break;
1103f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXINTERVAL:
1104f1ae32a1SGerd Hoffmann         s->ep[ep].interval[1] = value;
1105f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 1);
1106f1ae32a1SGerd Hoffmann         break;
1107f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_FIFOSIZE & ~1):
1108f1ae32a1SGerd Hoffmann         break;
1109f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFOSIZE:
1110f1ae32a1SGerd Hoffmann         TRACE("somebody messes with fifosize (now %i bytes)", value);
1111f1ae32a1SGerd Hoffmann         s->ep[ep].fifosize = value;
1112f1ae32a1SGerd Hoffmann         break;
1113f1ae32a1SGerd Hoffmann     default:
1114f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1115f1ae32a1SGerd Hoffmann         break;
1116f1ae32a1SGerd Hoffmann     };
1117f1ae32a1SGerd Hoffmann }
1118f1ae32a1SGerd Hoffmann 
1119f1ae32a1SGerd Hoffmann static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
1120f1ae32a1SGerd Hoffmann {
1121f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1122f1ae32a1SGerd Hoffmann     uint16_t ret;
1123f1ae32a1SGerd Hoffmann 
1124f1ae32a1SGerd Hoffmann     switch (addr) {
1125f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXMAXP:
1126f1ae32a1SGerd Hoffmann         return s->ep[ep].maxp[0];
1127f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXCSR:
1128f1ae32a1SGerd Hoffmann         return s->ep[ep].csr[0];
1129f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXMAXP:
1130f1ae32a1SGerd Hoffmann         return s->ep[ep].maxp[1];
1131f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCSR:
1132f1ae32a1SGerd Hoffmann         ret = s->ep[ep].csr[1];
1133f1ae32a1SGerd Hoffmann 
1134f1ae32a1SGerd Hoffmann         /* TODO: This and other bits probably depend on
1135f1ae32a1SGerd Hoffmann          * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR.  */
1136f1ae32a1SGerd Hoffmann         if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
1137f1ae32a1SGerd Hoffmann             s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
1138f1ae32a1SGerd Hoffmann 
1139f1ae32a1SGerd Hoffmann         return ret;
1140f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1141f1ae32a1SGerd Hoffmann         return s->ep[ep].rxcount;
1142f1ae32a1SGerd Hoffmann 
1143f1ae32a1SGerd Hoffmann     default:
1144f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, ep, addr) |
1145f1ae32a1SGerd Hoffmann                 (musb_ep_readb(s, ep, addr | 1) << 8);
1146f1ae32a1SGerd Hoffmann     };
1147f1ae32a1SGerd Hoffmann }
1148f1ae32a1SGerd Hoffmann 
1149f1ae32a1SGerd Hoffmann static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
1150f1ae32a1SGerd Hoffmann {
1151f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1152f1ae32a1SGerd Hoffmann 
1153f1ae32a1SGerd Hoffmann     switch (addr) {
1154f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXMAXP:
1155f1ae32a1SGerd Hoffmann         s->ep[ep].maxp[0] = value;
1156f1ae32a1SGerd Hoffmann         break;
1157f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXCSR:
1158f1ae32a1SGerd Hoffmann         if (ep) {
1159f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] &= value & 0xa6;
1160f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] |= value & 0xff59;
1161f1ae32a1SGerd Hoffmann         } else {
1162f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] &= value & 0x85;
1163f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] |= value & 0xf7a;
1164f1ae32a1SGerd Hoffmann         }
1165f1ae32a1SGerd Hoffmann 
1166f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 0);
1167f1ae32a1SGerd Hoffmann 
1168f1ae32a1SGerd Hoffmann         if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
1169f1ae32a1SGerd Hoffmann                         (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
1170f1ae32a1SGerd Hoffmann             s->ep[ep].fifolen[0] = 0;
1171f1ae32a1SGerd Hoffmann             s->ep[ep].fifostart[0] = 0;
1172f1ae32a1SGerd Hoffmann             if (ep)
1173f1ae32a1SGerd Hoffmann                 s->ep[ep].csr[0] &=
1174f1ae32a1SGerd Hoffmann                         ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
1175f1ae32a1SGerd Hoffmann             else
1176f1ae32a1SGerd Hoffmann                 s->ep[ep].csr[0] &=
1177f1ae32a1SGerd Hoffmann                         ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
1178f1ae32a1SGerd Hoffmann         }
1179f1ae32a1SGerd Hoffmann         if (
1180f1ae32a1SGerd Hoffmann                         (ep &&
1181f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1182f1ae32a1SGerd Hoffmann                          (value & MGC_M_TXCSR_TXPKTRDY) &&
1183f1ae32a1SGerd Hoffmann                          !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
1184f1ae32a1SGerd Hoffmann #else
1185f1ae32a1SGerd Hoffmann                          (value & MGC_M_TXCSR_TXPKTRDY)) ||
1186f1ae32a1SGerd Hoffmann #endif
1187f1ae32a1SGerd Hoffmann                         (!ep &&
1188f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1189f1ae32a1SGerd Hoffmann                          (value & MGC_M_CSR0_TXPKTRDY) &&
1190f1ae32a1SGerd Hoffmann                          !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
1191f1ae32a1SGerd Hoffmann #else
1192f1ae32a1SGerd Hoffmann                          (value & MGC_M_CSR0_TXPKTRDY)))
1193f1ae32a1SGerd Hoffmann #endif
1194f1ae32a1SGerd Hoffmann             musb_tx_rdy(s, ep);
1195f1ae32a1SGerd Hoffmann         if (!ep &&
1196f1ae32a1SGerd Hoffmann                         (value & MGC_M_CSR0_H_REQPKT) &&
1197f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1198f1ae32a1SGerd Hoffmann                         !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
1199f1ae32a1SGerd Hoffmann                                         MGC_M_CSR0_RXPKTRDY)))
1200f1ae32a1SGerd Hoffmann #else
1201f1ae32a1SGerd Hoffmann                         !(value & MGC_M_CSR0_RXPKTRDY))
1202f1ae32a1SGerd Hoffmann #endif
1203f1ae32a1SGerd Hoffmann             musb_rx_req(s, ep);
1204f1ae32a1SGerd Hoffmann         break;
1205f1ae32a1SGerd Hoffmann 
1206f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXMAXP:
1207f1ae32a1SGerd Hoffmann         s->ep[ep].maxp[1] = value;
1208f1ae32a1SGerd Hoffmann         break;
1209f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCSR:
1210f1ae32a1SGerd Hoffmann         /* (DMA mode only) */
1211f1ae32a1SGerd Hoffmann         if (
1212f1ae32a1SGerd Hoffmann                 (value & MGC_M_RXCSR_H_AUTOREQ) &&
1213f1ae32a1SGerd Hoffmann                 !(value & MGC_M_RXCSR_RXPKTRDY) &&
1214f1ae32a1SGerd Hoffmann                 (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
1215f1ae32a1SGerd Hoffmann             value |= MGC_M_RXCSR_H_REQPKT;
1216f1ae32a1SGerd Hoffmann 
1217f1ae32a1SGerd Hoffmann         s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
1218f1ae32a1SGerd Hoffmann         s->ep[ep].csr[1] |= value & 0xfeb0;
1219f1ae32a1SGerd Hoffmann 
1220f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 1);
1221f1ae32a1SGerd Hoffmann 
1222f1ae32a1SGerd Hoffmann         if (value & MGC_M_RXCSR_FLUSHFIFO) {
1223f1ae32a1SGerd Hoffmann             s->ep[ep].fifolen[1] = 0;
1224f1ae32a1SGerd Hoffmann             s->ep[ep].fifostart[1] = 0;
1225f1ae32a1SGerd Hoffmann             s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
1226f1ae32a1SGerd Hoffmann             /* If double buffering and we have two packets ready, flush
1227f1ae32a1SGerd Hoffmann              * only the first one and set up the fifo at the second packet.  */
1228f1ae32a1SGerd Hoffmann         }
1229f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1230f1ae32a1SGerd Hoffmann         if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
1231f1ae32a1SGerd Hoffmann #else
1232f1ae32a1SGerd Hoffmann         if (value & MGC_M_RXCSR_H_REQPKT)
1233f1ae32a1SGerd Hoffmann #endif
1234f1ae32a1SGerd Hoffmann             musb_rx_req(s, ep);
1235f1ae32a1SGerd Hoffmann         break;
1236f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1237f1ae32a1SGerd Hoffmann         s->ep[ep].rxcount = value;
1238f1ae32a1SGerd Hoffmann         break;
1239f1ae32a1SGerd Hoffmann 
1240f1ae32a1SGerd Hoffmann     default:
1241f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr, value & 0xff);
1242f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr | 1, value >> 8);
1243f1ae32a1SGerd Hoffmann     };
1244f1ae32a1SGerd Hoffmann }
1245f1ae32a1SGerd Hoffmann 
1246f1ae32a1SGerd Hoffmann /* Generic control */
1247a8170e5eSAvi Kivity static uint32_t musb_readb(void *opaque, hwaddr addr)
1248f1ae32a1SGerd Hoffmann {
1249f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1250f1ae32a1SGerd Hoffmann     int ep, i;
1251f1ae32a1SGerd Hoffmann     uint8_t ret;
1252f1ae32a1SGerd Hoffmann 
1253f1ae32a1SGerd Hoffmann     switch (addr) {
1254f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FADDR:
1255f1ae32a1SGerd Hoffmann         return s->faddr;
1256f1ae32a1SGerd Hoffmann     case MUSB_HDRC_POWER:
1257f1ae32a1SGerd Hoffmann         return s->power;
1258f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSB:
1259f1ae32a1SGerd Hoffmann         ret = s->intr;
1260f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1261f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1262f1ae32a1SGerd Hoffmann                 musb_intr_set(s, i, 0);
1263f1ae32a1SGerd Hoffmann         return ret;
1264f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSBE:
1265f1ae32a1SGerd Hoffmann         return s->mask;
1266f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INDEX:
1267f1ae32a1SGerd Hoffmann         return s->idx;
1268f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TESTMODE:
1269f1ae32a1SGerd Hoffmann         return 0x00;
1270f1ae32a1SGerd Hoffmann 
1271f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1272f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, s->idx, addr & 0xf);
1273f1ae32a1SGerd Hoffmann 
1274f1ae32a1SGerd Hoffmann     case MUSB_HDRC_DEVCTL:
1275f1ae32a1SGerd Hoffmann         return s->devctl;
1276f1ae32a1SGerd Hoffmann 
1277f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOSZ:
1278f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOSZ:
1279f1ae32a1SGerd Hoffmann     case MUSB_HDRC_VCTRL:
1280f1ae32a1SGerd Hoffmann         /* TODO */
1281f1ae32a1SGerd Hoffmann         return 0x00;
1282f1ae32a1SGerd Hoffmann 
1283f1ae32a1SGerd Hoffmann     case MUSB_HDRC_HWVERS:
1284f1ae32a1SGerd Hoffmann         return (1 << 10) | 400;
1285f1ae32a1SGerd Hoffmann 
1286f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_VCTRL | 1):
1287f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_HWVERS | 1):
1288f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_DEVCTL | 1):
1289f1ae32a1SGerd Hoffmann         return 0x00;
1290f1ae32a1SGerd Hoffmann 
1291f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1292f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1293f1ae32a1SGerd Hoffmann         return musb_busctl_readb(s, ep, addr & 0x7);
1294f1ae32a1SGerd Hoffmann 
1295f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1296f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1297f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, ep, addr & 0xf);
1298f1ae32a1SGerd Hoffmann 
1299f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1300f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1301f1ae32a1SGerd Hoffmann         return musb_read_fifo(s->ep + ep);
1302f1ae32a1SGerd Hoffmann 
1303f1ae32a1SGerd Hoffmann     default:
1304f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1305f1ae32a1SGerd Hoffmann         return 0x00;
1306f1ae32a1SGerd Hoffmann     };
1307f1ae32a1SGerd Hoffmann }
1308f1ae32a1SGerd Hoffmann 
1309a8170e5eSAvi Kivity static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
1310f1ae32a1SGerd Hoffmann {
1311f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1312f1ae32a1SGerd Hoffmann     int ep;
1313f1ae32a1SGerd Hoffmann 
1314f1ae32a1SGerd Hoffmann     switch (addr) {
1315f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FADDR:
1316f1ae32a1SGerd Hoffmann         s->faddr = value & 0x7f;
1317f1ae32a1SGerd Hoffmann         break;
1318f1ae32a1SGerd Hoffmann     case MUSB_HDRC_POWER:
1319f1ae32a1SGerd Hoffmann         s->power = (value & 0xef) | (s->power & 0x10);
1320f1ae32a1SGerd Hoffmann         /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
1321f1ae32a1SGerd Hoffmann         if ((value & MGC_M_POWER_RESET) && s->port.dev) {
1322f1ae32a1SGerd Hoffmann             usb_device_reset(s->port.dev);
1323f1ae32a1SGerd Hoffmann             /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set.  */
1324f1ae32a1SGerd Hoffmann             if ((value & MGC_M_POWER_HSENAB) &&
1325f1ae32a1SGerd Hoffmann                             s->port.dev->speed == USB_SPEED_HIGH)
1326f1ae32a1SGerd Hoffmann                 s->power |= MGC_M_POWER_HSMODE;	/* Success */
1327f1ae32a1SGerd Hoffmann             /* Restart frame counting.  */
1328f1ae32a1SGerd Hoffmann         }
1329f1ae32a1SGerd Hoffmann         if (value & MGC_M_POWER_SUSPENDM) {
1330f1ae32a1SGerd Hoffmann             /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
1331f1ae32a1SGerd Hoffmann              * is set, also go into low power mode.  Frame counting stops.  */
1332f1ae32a1SGerd Hoffmann             /* XXX: Cleared when the interrupt register is read */
1333f1ae32a1SGerd Hoffmann         }
1334f1ae32a1SGerd Hoffmann         if (value & MGC_M_POWER_RESUME) {
1335f1ae32a1SGerd Hoffmann             /* Wait 20ms and signal resuming on the bus.  Frame counting
1336f1ae32a1SGerd Hoffmann              * restarts.  */
1337f1ae32a1SGerd Hoffmann         }
1338f1ae32a1SGerd Hoffmann         break;
1339f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSB:
1340f1ae32a1SGerd Hoffmann         break;
1341f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSBE:
1342f1ae32a1SGerd Hoffmann         s->mask = value & 0xff;
1343f1ae32a1SGerd Hoffmann         break;
1344f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INDEX:
1345f1ae32a1SGerd Hoffmann         s->idx = value & 0xf;
1346f1ae32a1SGerd Hoffmann         break;
1347f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TESTMODE:
1348f1ae32a1SGerd Hoffmann         break;
1349f1ae32a1SGerd Hoffmann 
1350f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1351f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, s->idx, addr & 0xf, value);
1352f1ae32a1SGerd Hoffmann         break;
1353f1ae32a1SGerd Hoffmann 
1354f1ae32a1SGerd Hoffmann     case MUSB_HDRC_DEVCTL:
1355f1ae32a1SGerd Hoffmann         s->session = !!(value & MGC_M_DEVCTL_SESSION);
1356f1ae32a1SGerd Hoffmann         musb_session_update(s,
1357f1ae32a1SGerd Hoffmann                         !!s->port.dev,
1358f1ae32a1SGerd Hoffmann                         !!(s->devctl & MGC_M_DEVCTL_SESSION));
1359f1ae32a1SGerd Hoffmann 
1360f1ae32a1SGerd Hoffmann         /* It seems this is the only R/W bit in this register?  */
1361f1ae32a1SGerd Hoffmann         s->devctl &= ~MGC_M_DEVCTL_SESSION;
1362f1ae32a1SGerd Hoffmann         s->devctl |= value & MGC_M_DEVCTL_SESSION;
1363f1ae32a1SGerd Hoffmann         break;
1364f1ae32a1SGerd Hoffmann 
1365f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOSZ:
1366f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOSZ:
1367f1ae32a1SGerd Hoffmann     case MUSB_HDRC_VCTRL:
1368f1ae32a1SGerd Hoffmann         /* TODO */
1369f1ae32a1SGerd Hoffmann         break;
1370f1ae32a1SGerd Hoffmann 
1371f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_VCTRL | 1):
1372f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_DEVCTL | 1):
1373f1ae32a1SGerd Hoffmann         break;
1374f1ae32a1SGerd Hoffmann 
1375f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1376f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1377f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr & 0x7, value);
1378f1ae32a1SGerd Hoffmann         break;
1379f1ae32a1SGerd Hoffmann 
1380f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1381f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1382f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr & 0xf, value);
1383f1ae32a1SGerd Hoffmann         break;
1384f1ae32a1SGerd Hoffmann 
1385f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1386f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1387f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1388f1ae32a1SGerd Hoffmann         break;
1389f1ae32a1SGerd Hoffmann 
1390f1ae32a1SGerd Hoffmann     default:
1391f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1392f1ae32a1SGerd Hoffmann         break;
1393f1ae32a1SGerd Hoffmann     };
1394f1ae32a1SGerd Hoffmann }
1395f1ae32a1SGerd Hoffmann 
1396a8170e5eSAvi Kivity static uint32_t musb_readh(void *opaque, hwaddr addr)
1397f1ae32a1SGerd Hoffmann {
1398f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1399f1ae32a1SGerd Hoffmann     int ep, i;
1400f1ae32a1SGerd Hoffmann     uint16_t ret;
1401f1ae32a1SGerd Hoffmann 
1402f1ae32a1SGerd Hoffmann     switch (addr) {
1403f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTX:
1404f1ae32a1SGerd Hoffmann         ret = s->tx_intr;
1405f1ae32a1SGerd Hoffmann         /* Auto clear */
1406f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1407f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1408f1ae32a1SGerd Hoffmann                 musb_tx_intr_set(s, i, 0);
1409f1ae32a1SGerd Hoffmann         return ret;
1410f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRX:
1411f1ae32a1SGerd Hoffmann         ret = s->rx_intr;
1412f1ae32a1SGerd Hoffmann         /* Auto clear */
1413f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1414f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1415f1ae32a1SGerd Hoffmann                 musb_rx_intr_set(s, i, 0);
1416f1ae32a1SGerd Hoffmann         return ret;
1417f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTXE:
1418f1ae32a1SGerd Hoffmann         return s->tx_mask;
1419f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRXE:
1420f1ae32a1SGerd Hoffmann         return s->rx_mask;
1421f1ae32a1SGerd Hoffmann 
1422f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FRAME:
1423f1ae32a1SGerd Hoffmann         /* TODO */
1424f1ae32a1SGerd Hoffmann         return 0x0000;
1425f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOADDR:
1426f1ae32a1SGerd Hoffmann         return s->ep[s->idx].fifoaddr[0];
1427f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOADDR:
1428f1ae32a1SGerd Hoffmann         return s->ep[s->idx].fifoaddr[1];
1429f1ae32a1SGerd Hoffmann 
1430f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1431f1ae32a1SGerd Hoffmann         return musb_ep_readh(s, s->idx, addr & 0xf);
1432f1ae32a1SGerd Hoffmann 
1433f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1434f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1435f1ae32a1SGerd Hoffmann         return musb_busctl_readh(s, ep, addr & 0x7);
1436f1ae32a1SGerd Hoffmann 
1437f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1438f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1439f1ae32a1SGerd Hoffmann         return musb_ep_readh(s, ep, addr & 0xf);
1440f1ae32a1SGerd Hoffmann 
1441f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1442f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1443f1ae32a1SGerd Hoffmann         return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
1444f1ae32a1SGerd Hoffmann 
1445f1ae32a1SGerd Hoffmann     default:
1446f1ae32a1SGerd Hoffmann         return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
1447f1ae32a1SGerd Hoffmann     };
1448f1ae32a1SGerd Hoffmann }
1449f1ae32a1SGerd Hoffmann 
1450a8170e5eSAvi Kivity static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
1451f1ae32a1SGerd Hoffmann {
1452f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1453f1ae32a1SGerd Hoffmann     int ep;
1454f1ae32a1SGerd Hoffmann 
1455f1ae32a1SGerd Hoffmann     switch (addr) {
1456f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTXE:
1457f1ae32a1SGerd Hoffmann         s->tx_mask = value;
1458f1ae32a1SGerd Hoffmann         /* XXX: the masks seem to apply on the raising edge like with
1459f1ae32a1SGerd Hoffmann          * edge-triggered interrupts, thus no need to update.  I may be
1460f1ae32a1SGerd Hoffmann          * wrong though.  */
1461f1ae32a1SGerd Hoffmann         break;
1462f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRXE:
1463f1ae32a1SGerd Hoffmann         s->rx_mask = value;
1464f1ae32a1SGerd Hoffmann         break;
1465f1ae32a1SGerd Hoffmann 
1466f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FRAME:
1467f1ae32a1SGerd Hoffmann         /* TODO */
1468f1ae32a1SGerd Hoffmann         break;
1469f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOADDR:
1470f1ae32a1SGerd Hoffmann         s->ep[s->idx].fifoaddr[0] = value;
1471f1ae32a1SGerd Hoffmann         s->ep[s->idx].buf[0] =
1472f1ae32a1SGerd Hoffmann                 s->buf + ((value << 3) & 0x7ff );
1473f1ae32a1SGerd Hoffmann         break;
1474f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOADDR:
1475f1ae32a1SGerd Hoffmann         s->ep[s->idx].fifoaddr[1] = value;
1476f1ae32a1SGerd Hoffmann         s->ep[s->idx].buf[1] =
1477f1ae32a1SGerd Hoffmann                 s->buf + ((value << 3) & 0x7ff);
1478f1ae32a1SGerd Hoffmann         break;
1479f1ae32a1SGerd Hoffmann 
1480f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1481f1ae32a1SGerd Hoffmann         musb_ep_writeh(s, s->idx, addr & 0xf, value);
1482f1ae32a1SGerd Hoffmann         break;
1483f1ae32a1SGerd Hoffmann 
1484f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1485f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1486f1ae32a1SGerd Hoffmann         musb_busctl_writeh(s, ep, addr & 0x7, value);
1487f1ae32a1SGerd Hoffmann         break;
1488f1ae32a1SGerd Hoffmann 
1489f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1490f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1491f1ae32a1SGerd Hoffmann         musb_ep_writeh(s, ep, addr & 0xf, value);
1492f1ae32a1SGerd Hoffmann         break;
1493f1ae32a1SGerd Hoffmann 
1494f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1495f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1496f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1497f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
1498f1ae32a1SGerd Hoffmann         break;
1499f1ae32a1SGerd Hoffmann 
1500f1ae32a1SGerd Hoffmann     default:
1501f1ae32a1SGerd Hoffmann         musb_writeb(s, addr, value & 0xff);
1502f1ae32a1SGerd Hoffmann         musb_writeb(s, addr | 1, value >> 8);
1503f1ae32a1SGerd Hoffmann     };
1504f1ae32a1SGerd Hoffmann }
1505f1ae32a1SGerd Hoffmann 
1506a8170e5eSAvi Kivity static uint32_t musb_readw(void *opaque, hwaddr addr)
1507f1ae32a1SGerd Hoffmann {
1508f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1509f1ae32a1SGerd Hoffmann     int ep;
1510f1ae32a1SGerd Hoffmann 
1511f1ae32a1SGerd Hoffmann     switch (addr) {
1512f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1513f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1514f1ae32a1SGerd Hoffmann         return ( musb_read_fifo(s->ep + ep)       |
1515f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 8  |
1516f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 16 |
1517f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 24 );
1518f1ae32a1SGerd Hoffmann     default:
1519f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1520f1ae32a1SGerd Hoffmann         return 0x00000000;
1521f1ae32a1SGerd Hoffmann     };
1522f1ae32a1SGerd Hoffmann }
1523f1ae32a1SGerd Hoffmann 
1524a8170e5eSAvi Kivity static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
1525f1ae32a1SGerd Hoffmann {
1526f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1527f1ae32a1SGerd Hoffmann     int ep;
1528f1ae32a1SGerd Hoffmann 
1529f1ae32a1SGerd Hoffmann     switch (addr) {
1530f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1531f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1532f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1533f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
1534f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
1535f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
1536f1ae32a1SGerd Hoffmann             break;
1537f1ae32a1SGerd Hoffmann     default:
1538f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1539f1ae32a1SGerd Hoffmann         break;
1540f1ae32a1SGerd Hoffmann     };
1541f1ae32a1SGerd Hoffmann }
1542f1ae32a1SGerd Hoffmann 
1543f1ae32a1SGerd Hoffmann CPUReadMemoryFunc * const musb_read[] = {
1544f1ae32a1SGerd Hoffmann     musb_readb,
1545f1ae32a1SGerd Hoffmann     musb_readh,
1546f1ae32a1SGerd Hoffmann     musb_readw,
1547f1ae32a1SGerd Hoffmann };
1548f1ae32a1SGerd Hoffmann 
1549f1ae32a1SGerd Hoffmann CPUWriteMemoryFunc * const musb_write[] = {
1550f1ae32a1SGerd Hoffmann     musb_writeb,
1551f1ae32a1SGerd Hoffmann     musb_writeh,
1552f1ae32a1SGerd Hoffmann     musb_writew,
1553f1ae32a1SGerd Hoffmann };
1554