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