xref: /openbmc/qemu/hw/usb/hcd-musb.c (revision c889b3a5)
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"
241de7afc9SPaolo Bonzini #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 
386*c889b3a5SAndreas Färber     usb_bus_new(&s->bus, sizeof(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])
561bc72ad67SAlex Bligh         ep->intv_timer[dir] = timer_new_ns(QEMU_CLOCK_VIRTUAL, musb_cb_tick, ep);
562f1ae32a1SGerd Hoffmann 
563bc72ad67SAlex Bligh     timer_mod(ep->intv_timer[dir], qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) +
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 idx = epnum && dir;
611f1ae32a1SGerd Hoffmann     int ttype;
612f1ae32a1SGerd Hoffmann 
613f1ae32a1SGerd Hoffmann     /* ep->type[0,1] contains:
614f1ae32a1SGerd Hoffmann      * in bits 7:6 the speed (0 - invalid, 1 - high, 2 - full, 3 - slow)
615f1ae32a1SGerd Hoffmann      * in bits 5:4 the transfer type (BULK / INT)
616f1ae32a1SGerd Hoffmann      * in bits 3:0 the EP num
617f1ae32a1SGerd Hoffmann      */
618f1ae32a1SGerd Hoffmann     ttype = epnum ? (ep->type[idx] >> 4) & 3 : 0;
619f1ae32a1SGerd Hoffmann 
620f1ae32a1SGerd Hoffmann     ep->timeout[dir] = musb_timeout(ttype,
621f1ae32a1SGerd Hoffmann                     ep->type[idx] >> 6, ep->interval[idx]);
622f1ae32a1SGerd Hoffmann     ep->interrupt[dir] = ttype == USB_ENDPOINT_XFER_INT;
623f1ae32a1SGerd Hoffmann     ep->delayed_cb[dir] = cb;
624f1ae32a1SGerd Hoffmann 
625f1ae32a1SGerd Hoffmann     /* A wild guess on the FADDR semantics... */
626f1ae32a1SGerd Hoffmann     dev = usb_find_device(&s->port, ep->faddr[idx]);
627f1ae32a1SGerd Hoffmann     uep = usb_ep_get(dev, pid, ep->type[idx] & 0xf);
6288550a02dSGerd Hoffmann     usb_packet_setup(&ep->packey[dir].p, pid, uep, 0,
629a6fb2ddbSHans de Goede                      (dev->addr << 16) | (uep->nr << 8) | pid, false, true);
630f1ae32a1SGerd Hoffmann     usb_packet_addbuf(&ep->packey[dir].p, ep->buf[idx], len);
631f1ae32a1SGerd Hoffmann     ep->packey[dir].ep = ep;
632f1ae32a1SGerd Hoffmann     ep->packey[dir].dir = dir;
633f1ae32a1SGerd Hoffmann 
6349a77a0f5SHans de Goede     usb_handle_packet(dev, &ep->packey[dir].p);
635f1ae32a1SGerd Hoffmann 
6369a77a0f5SHans de Goede     if (ep->packey[dir].p.status == USB_RET_ASYNC) {
63736dfe324SHans de Goede         usb_device_flush_ep_queue(dev, uep);
638f1ae32a1SGerd Hoffmann         ep->status[dir] = len;
639f1ae32a1SGerd Hoffmann         return;
640f1ae32a1SGerd Hoffmann     }
641f1ae32a1SGerd Hoffmann 
6429a77a0f5SHans de Goede     if (ep->packey[dir].p.status == USB_RET_SUCCESS) {
6439a77a0f5SHans de Goede         ep->status[dir] = ep->packey[dir].p.actual_length;
6449a77a0f5SHans de Goede     } else {
6459a77a0f5SHans de Goede         ep->status[dir] = ep->packey[dir].p.status;
6469a77a0f5SHans de Goede     }
647f1ae32a1SGerd Hoffmann     musb_schedule_cb(&s->port, &ep->packey[dir].p);
648f1ae32a1SGerd Hoffmann }
649f1ae32a1SGerd Hoffmann 
650f1ae32a1SGerd Hoffmann static void musb_tx_packet_complete(USBPacket *packey, void *opaque)
651f1ae32a1SGerd Hoffmann {
652f1ae32a1SGerd Hoffmann     /* Unfortunately we can't use packey->devep because that's the remote
653f1ae32a1SGerd Hoffmann      * endpoint number and may be different than our local.  */
654f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
655f1ae32a1SGerd Hoffmann     int epnum = ep->epnum;
656f1ae32a1SGerd Hoffmann     MUSBState *s = ep->musb;
657f1ae32a1SGerd Hoffmann 
658f1ae32a1SGerd Hoffmann     ep->fifostart[0] = 0;
659f1ae32a1SGerd Hoffmann     ep->fifolen[0] = 0;
660f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
661f1ae32a1SGerd Hoffmann     if (ep->status[0] != USB_RET_NAK) {
662f1ae32a1SGerd Hoffmann #endif
663f1ae32a1SGerd Hoffmann         if (epnum)
664f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
665f1ae32a1SGerd Hoffmann         else
666f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_TXPKTRDY;
667f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
668f1ae32a1SGerd Hoffmann     }
669f1ae32a1SGerd Hoffmann #endif
670f1ae32a1SGerd Hoffmann 
671f1ae32a1SGerd Hoffmann     /* Clear all of the error bits first */
672f1ae32a1SGerd Hoffmann     if (epnum)
673f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_TXCSR_H_ERROR | MGC_M_TXCSR_H_RXSTALL |
674f1ae32a1SGerd Hoffmann                         MGC_M_TXCSR_H_NAKTIMEOUT);
675f1ae32a1SGerd Hoffmann     else
676f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
677f1ae32a1SGerd Hoffmann                         MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
678f1ae32a1SGerd Hoffmann 
679f1ae32a1SGerd Hoffmann     if (ep->status[0] == USB_RET_STALL) {
680f1ae32a1SGerd Hoffmann         /* Command not supported by target! */
681f1ae32a1SGerd Hoffmann         ep->status[0] = 0;
682f1ae32a1SGerd Hoffmann 
683f1ae32a1SGerd Hoffmann         if (epnum)
684f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_RXSTALL;
685f1ae32a1SGerd Hoffmann         else
686f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
687f1ae32a1SGerd Hoffmann     }
688f1ae32a1SGerd Hoffmann 
689f1ae32a1SGerd Hoffmann     if (ep->status[0] == USB_RET_NAK) {
690f1ae32a1SGerd Hoffmann         ep->status[0] = 0;
691f1ae32a1SGerd Hoffmann 
692f1ae32a1SGerd Hoffmann         /* NAK timeouts are only generated in Bulk transfers and
693f1ae32a1SGerd Hoffmann          * Data-errors in Isochronous.  */
694f1ae32a1SGerd Hoffmann         if (ep->interrupt[0]) {
695f1ae32a1SGerd Hoffmann             return;
696f1ae32a1SGerd Hoffmann         }
697f1ae32a1SGerd Hoffmann 
698f1ae32a1SGerd Hoffmann         if (epnum)
699f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_NAKTIMEOUT;
700f1ae32a1SGerd Hoffmann         else
701f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
702f1ae32a1SGerd Hoffmann     }
703f1ae32a1SGerd Hoffmann 
704f1ae32a1SGerd Hoffmann     if (ep->status[0] < 0) {
705f1ae32a1SGerd Hoffmann         if (ep->status[0] == USB_RET_BABBLE)
706f1ae32a1SGerd Hoffmann             musb_intr_set(s, musb_irq_rst_babble, 1);
707f1ae32a1SGerd Hoffmann 
708f1ae32a1SGerd Hoffmann         /* Pretend we've tried three times already and failed (in
709f1ae32a1SGerd Hoffmann          * case of USB_TOKEN_SETUP).  */
710f1ae32a1SGerd Hoffmann         if (epnum)
711f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_TXCSR_H_ERROR;
712f1ae32a1SGerd Hoffmann         else
713f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_ERROR;
714f1ae32a1SGerd Hoffmann 
715f1ae32a1SGerd Hoffmann         musb_tx_intr_set(s, epnum, 1);
716f1ae32a1SGerd Hoffmann         return;
717f1ae32a1SGerd Hoffmann     }
718f1ae32a1SGerd Hoffmann     /* TODO: check len for over/underruns of an OUT packet?  */
719f1ae32a1SGerd Hoffmann 
720f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK
721f1ae32a1SGerd Hoffmann     if (!epnum && ep->packey[0].pid == USB_TOKEN_SETUP)
722f1ae32a1SGerd Hoffmann         s->setup_len = ep->packey[0].data[6];
723f1ae32a1SGerd Hoffmann #endif
724f1ae32a1SGerd Hoffmann 
725f1ae32a1SGerd Hoffmann     /* In DMA mode: if no error, assert DMA request for this EP,
726f1ae32a1SGerd Hoffmann      * and skip the interrupt.  */
727f1ae32a1SGerd Hoffmann     musb_tx_intr_set(s, epnum, 1);
728f1ae32a1SGerd Hoffmann }
729f1ae32a1SGerd Hoffmann 
730f1ae32a1SGerd Hoffmann static void musb_rx_packet_complete(USBPacket *packey, void *opaque)
731f1ae32a1SGerd Hoffmann {
732f1ae32a1SGerd Hoffmann     /* Unfortunately we can't use packey->devep because that's the remote
733f1ae32a1SGerd Hoffmann      * endpoint number and may be different than our local.  */
734f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = (MUSBEndPoint *) opaque;
735f1ae32a1SGerd Hoffmann     int epnum = ep->epnum;
736f1ae32a1SGerd Hoffmann     MUSBState *s = ep->musb;
737f1ae32a1SGerd Hoffmann 
738f1ae32a1SGerd Hoffmann     ep->fifostart[1] = 0;
739f1ae32a1SGerd Hoffmann     ep->fifolen[1] = 0;
740f1ae32a1SGerd Hoffmann 
741f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
742f1ae32a1SGerd Hoffmann     if (ep->status[1] != USB_RET_NAK) {
743f1ae32a1SGerd Hoffmann #endif
744f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
745f1ae32a1SGerd Hoffmann         if (!epnum)
746f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
747f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
748f1ae32a1SGerd Hoffmann     }
749f1ae32a1SGerd Hoffmann #endif
750f1ae32a1SGerd Hoffmann 
751f1ae32a1SGerd Hoffmann     /* Clear all of the imaginable error bits first */
752f1ae32a1SGerd Hoffmann     ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
753f1ae32a1SGerd Hoffmann                     MGC_M_RXCSR_DATAERROR);
754f1ae32a1SGerd Hoffmann     if (!epnum)
755f1ae32a1SGerd Hoffmann         ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
756f1ae32a1SGerd Hoffmann                         MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
757f1ae32a1SGerd Hoffmann 
758f1ae32a1SGerd Hoffmann     if (ep->status[1] == USB_RET_STALL) {
759f1ae32a1SGerd Hoffmann         ep->status[1] = 0;
760f1ae32a1SGerd Hoffmann 
761f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_H_RXSTALL;
762f1ae32a1SGerd Hoffmann         if (!epnum)
763f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_RXSTALL;
764f1ae32a1SGerd Hoffmann     }
765f1ae32a1SGerd Hoffmann 
766f1ae32a1SGerd Hoffmann     if (ep->status[1] == USB_RET_NAK) {
767f1ae32a1SGerd Hoffmann         ep->status[1] = 0;
768f1ae32a1SGerd Hoffmann 
769f1ae32a1SGerd Hoffmann         /* NAK timeouts are only generated in Bulk transfers and
770f1ae32a1SGerd Hoffmann          * Data-errors in Isochronous.  */
771f1ae32a1SGerd Hoffmann         if (ep->interrupt[1])
772f1ae32a1SGerd Hoffmann             return musb_packet(s, ep, epnum, USB_TOKEN_IN,
773f1ae32a1SGerd Hoffmann                             packey->iov.size, musb_rx_packet_complete, 1);
774f1ae32a1SGerd Hoffmann 
775f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_DATAERROR;
776f1ae32a1SGerd Hoffmann         if (!epnum)
777f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_NAKTIMEOUT;
778f1ae32a1SGerd Hoffmann     }
779f1ae32a1SGerd Hoffmann 
780f1ae32a1SGerd Hoffmann     if (ep->status[1] < 0) {
781f1ae32a1SGerd Hoffmann         if (ep->status[1] == USB_RET_BABBLE) {
782f1ae32a1SGerd Hoffmann             musb_intr_set(s, musb_irq_rst_babble, 1);
783f1ae32a1SGerd Hoffmann             return;
784f1ae32a1SGerd Hoffmann         }
785f1ae32a1SGerd Hoffmann 
786f1ae32a1SGerd Hoffmann         /* Pretend we've tried three times already and failed (in
787f1ae32a1SGerd Hoffmann          * case of a control transfer).  */
788f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_H_ERROR;
789f1ae32a1SGerd Hoffmann         if (!epnum)
790f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_H_ERROR;
791f1ae32a1SGerd Hoffmann 
792f1ae32a1SGerd Hoffmann         musb_rx_intr_set(s, epnum, 1);
793f1ae32a1SGerd Hoffmann         return;
794f1ae32a1SGerd Hoffmann     }
795f1ae32a1SGerd Hoffmann     /* TODO: check len for over/underruns of an OUT packet?  */
796f1ae32a1SGerd Hoffmann     /* TODO: perhaps make use of e->ext_size[1] here.  */
797f1ae32a1SGerd Hoffmann 
798f1ae32a1SGerd Hoffmann     if (!(ep->csr[1] & (MGC_M_RXCSR_H_RXSTALL | MGC_M_RXCSR_DATAERROR))) {
799f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
800f1ae32a1SGerd Hoffmann         if (!epnum)
801f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
802f1ae32a1SGerd Hoffmann 
8039a77a0f5SHans de Goede         ep->rxcount = ep->status[1]; /* XXX: MIN(packey->len, ep->maxp[1]); */
804f1ae32a1SGerd Hoffmann         /* In DMA mode: assert DMA request for this EP */
805f1ae32a1SGerd Hoffmann     }
806f1ae32a1SGerd Hoffmann 
807f1ae32a1SGerd Hoffmann     /* Only if DMA has not been asserted */
808f1ae32a1SGerd Hoffmann     musb_rx_intr_set(s, epnum, 1);
809f1ae32a1SGerd Hoffmann }
810f1ae32a1SGerd Hoffmann 
811f1ae32a1SGerd Hoffmann static void musb_async_cancel_device(MUSBState *s, USBDevice *dev)
812f1ae32a1SGerd Hoffmann {
813f1ae32a1SGerd Hoffmann     int ep, dir;
814f1ae32a1SGerd Hoffmann 
815f1ae32a1SGerd Hoffmann     for (ep = 0; ep < 16; ep++) {
816f1ae32a1SGerd Hoffmann         for (dir = 0; dir < 2; dir++) {
817f1ae32a1SGerd Hoffmann             if (!usb_packet_is_inflight(&s->ep[ep].packey[dir].p) ||
818f1ae32a1SGerd Hoffmann                 s->ep[ep].packey[dir].p.ep->dev != dev) {
819f1ae32a1SGerd Hoffmann                 continue;
820f1ae32a1SGerd Hoffmann             }
821f1ae32a1SGerd Hoffmann             usb_cancel_packet(&s->ep[ep].packey[dir].p);
822f1ae32a1SGerd Hoffmann             /* status updates needed here? */
823f1ae32a1SGerd Hoffmann         }
824f1ae32a1SGerd Hoffmann     }
825f1ae32a1SGerd Hoffmann }
826f1ae32a1SGerd Hoffmann 
827f1ae32a1SGerd Hoffmann static void musb_tx_rdy(MUSBState *s, int epnum)
828f1ae32a1SGerd Hoffmann {
829f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = s->ep + epnum;
830f1ae32a1SGerd Hoffmann     int pid;
831f1ae32a1SGerd Hoffmann     int total, valid = 0;
832f1ae32a1SGerd Hoffmann     TRACE("start %d, len %d",  ep->fifostart[0], ep->fifolen[0] );
833f1ae32a1SGerd Hoffmann     ep->fifostart[0] += ep->fifolen[0];
834f1ae32a1SGerd Hoffmann     ep->fifolen[0] = 0;
835f1ae32a1SGerd Hoffmann 
836f1ae32a1SGerd Hoffmann     /* XXX: how's the total size of the packet retrieved exactly in
837f1ae32a1SGerd Hoffmann      * the generic case?  */
838f1ae32a1SGerd Hoffmann     total = ep->maxp[0] & 0x3ff;
839f1ae32a1SGerd Hoffmann 
840f1ae32a1SGerd Hoffmann     if (ep->ext_size[0]) {
841f1ae32a1SGerd Hoffmann         total = ep->ext_size[0];
842f1ae32a1SGerd Hoffmann         ep->ext_size[0] = 0;
843f1ae32a1SGerd Hoffmann         valid = 1;
844f1ae32a1SGerd Hoffmann     }
845f1ae32a1SGerd Hoffmann 
846f1ae32a1SGerd Hoffmann     /* If the packet is not fully ready yet, wait for a next segment.  */
847f1ae32a1SGerd Hoffmann     if (epnum && (ep->fifostart[0]) < total)
848f1ae32a1SGerd Hoffmann         return;
849f1ae32a1SGerd Hoffmann 
850f1ae32a1SGerd Hoffmann     if (!valid)
851f1ae32a1SGerd Hoffmann         total = ep->fifostart[0];
852f1ae32a1SGerd Hoffmann 
853f1ae32a1SGerd Hoffmann     pid = USB_TOKEN_OUT;
854f1ae32a1SGerd Hoffmann     if (!epnum && (ep->csr[0] & MGC_M_CSR0_H_SETUPPKT)) {
855f1ae32a1SGerd Hoffmann         pid = USB_TOKEN_SETUP;
856f1ae32a1SGerd Hoffmann         if (total != 8) {
857f1ae32a1SGerd Hoffmann             TRACE("illegal SETUPPKT length of %i bytes", total);
858f1ae32a1SGerd Hoffmann         }
859f1ae32a1SGerd Hoffmann         /* Controller should retry SETUP packets three times on errors
860f1ae32a1SGerd Hoffmann          * but it doesn't make sense for us to do that.  */
861f1ae32a1SGerd Hoffmann     }
862f1ae32a1SGerd Hoffmann 
863f1ae32a1SGerd Hoffmann     return musb_packet(s, ep, epnum, pid,
864f1ae32a1SGerd Hoffmann                     total, musb_tx_packet_complete, 0);
865f1ae32a1SGerd Hoffmann }
866f1ae32a1SGerd Hoffmann 
867f1ae32a1SGerd Hoffmann static void musb_rx_req(MUSBState *s, int epnum)
868f1ae32a1SGerd Hoffmann {
869f1ae32a1SGerd Hoffmann     MUSBEndPoint *ep = s->ep + epnum;
870f1ae32a1SGerd Hoffmann     int total;
871f1ae32a1SGerd Hoffmann 
872f1ae32a1SGerd Hoffmann     /* If we already have a packet, which didn't fit into the
873f1ae32a1SGerd Hoffmann      * 64 bytes of the FIFO, only move the FIFO start and return. (Obsolete) */
874f1ae32a1SGerd Hoffmann     if (ep->packey[1].p.pid == USB_TOKEN_IN && ep->status[1] >= 0 &&
875f1ae32a1SGerd Hoffmann                     (ep->fifostart[1]) + ep->rxcount <
876f1ae32a1SGerd Hoffmann                     ep->packey[1].p.iov.size) {
877f1ae32a1SGerd Hoffmann         TRACE("0x%08x, %d",  ep->fifostart[1], ep->rxcount );
878f1ae32a1SGerd Hoffmann         ep->fifostart[1] += ep->rxcount;
879f1ae32a1SGerd Hoffmann         ep->fifolen[1] = 0;
880f1ae32a1SGerd Hoffmann 
881f1ae32a1SGerd Hoffmann         ep->rxcount = MIN(ep->packey[0].p.iov.size - (ep->fifostart[1]),
882f1ae32a1SGerd Hoffmann                         ep->maxp[1]);
883f1ae32a1SGerd Hoffmann 
884f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~MGC_M_RXCSR_H_REQPKT;
885f1ae32a1SGerd Hoffmann         if (!epnum)
886f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~MGC_M_CSR0_H_REQPKT;
887f1ae32a1SGerd Hoffmann 
888f1ae32a1SGerd Hoffmann         /* Clear all of the error bits first */
889f1ae32a1SGerd Hoffmann         ep->csr[1] &= ~(MGC_M_RXCSR_H_ERROR | MGC_M_RXCSR_H_RXSTALL |
890f1ae32a1SGerd Hoffmann                         MGC_M_RXCSR_DATAERROR);
891f1ae32a1SGerd Hoffmann         if (!epnum)
892f1ae32a1SGerd Hoffmann             ep->csr[0] &= ~(MGC_M_CSR0_H_ERROR | MGC_M_CSR0_H_RXSTALL |
893f1ae32a1SGerd Hoffmann                             MGC_M_CSR0_H_NAKTIMEOUT | MGC_M_CSR0_H_NO_PING);
894f1ae32a1SGerd Hoffmann 
895f1ae32a1SGerd Hoffmann         ep->csr[1] |= MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY;
896f1ae32a1SGerd Hoffmann         if (!epnum)
897f1ae32a1SGerd Hoffmann             ep->csr[0] |= MGC_M_CSR0_RXPKTRDY;
898f1ae32a1SGerd Hoffmann         musb_rx_intr_set(s, epnum, 1);
899f1ae32a1SGerd Hoffmann         return;
900f1ae32a1SGerd Hoffmann     }
901f1ae32a1SGerd Hoffmann 
902f1ae32a1SGerd Hoffmann     /* The driver sets maxp[1] to 64 or less because it knows the hardware
903f1ae32a1SGerd Hoffmann      * FIFO is this deep.  Bigger packets get split in
904f1ae32a1SGerd Hoffmann      * usb_generic_handle_packet but we can also do the splitting locally
905f1ae32a1SGerd Hoffmann      * for performance.  It turns out we can also have a bigger FIFO and
906f1ae32a1SGerd Hoffmann      * ignore the limit set in ep->maxp[1].  The Linux MUSB driver deals
907f1ae32a1SGerd Hoffmann      * OK with single packets of even 32KB and we avoid splitting, however
908f1ae32a1SGerd Hoffmann      * usb_msd.c sometimes sends a packet bigger than what Linux expects
909f1ae32a1SGerd Hoffmann      * (e.g. 8192 bytes instead of 4096) and we get an OVERRUN.  Splitting
910f1ae32a1SGerd Hoffmann      * hides this overrun from Linux.  Up to 4096 everything is fine
911f1ae32a1SGerd Hoffmann      * though.  Currently this is disabled.
912f1ae32a1SGerd Hoffmann      *
913f1ae32a1SGerd Hoffmann      * XXX: mind ep->fifosize.  */
914f1ae32a1SGerd Hoffmann     total = MIN(ep->maxp[1] & 0x3ff, sizeof(s->buf));
915f1ae32a1SGerd Hoffmann 
916f1ae32a1SGerd Hoffmann #ifdef SETUPLEN_HACK
917f1ae32a1SGerd Hoffmann     /* Why should *we* do that instead of Linux?  */
918f1ae32a1SGerd Hoffmann     if (!epnum) {
919f1ae32a1SGerd Hoffmann         if (ep->packey[0].p.devaddr == 2) {
920f1ae32a1SGerd Hoffmann             total = MIN(s->setup_len, 8);
921f1ae32a1SGerd Hoffmann         } else {
922f1ae32a1SGerd Hoffmann             total = MIN(s->setup_len, 64);
923f1ae32a1SGerd Hoffmann         }
924f1ae32a1SGerd Hoffmann         s->setup_len -= total;
925f1ae32a1SGerd Hoffmann     }
926f1ae32a1SGerd Hoffmann #endif
927f1ae32a1SGerd Hoffmann 
928f1ae32a1SGerd Hoffmann     return musb_packet(s, ep, epnum, USB_TOKEN_IN,
929f1ae32a1SGerd Hoffmann                     total, musb_rx_packet_complete, 1);
930f1ae32a1SGerd Hoffmann }
931f1ae32a1SGerd Hoffmann 
932f1ae32a1SGerd Hoffmann static uint8_t musb_read_fifo(MUSBEndPoint *ep)
933f1ae32a1SGerd Hoffmann {
934f1ae32a1SGerd Hoffmann     uint8_t value;
935f1ae32a1SGerd Hoffmann     if (ep->fifolen[1] >= 64) {
936f1ae32a1SGerd Hoffmann         /* We have a FIFO underrun */
937f1ae32a1SGerd Hoffmann         TRACE("EP%d FIFO is now empty, stop reading", ep->epnum);
938f1ae32a1SGerd Hoffmann         return 0x00000000;
939f1ae32a1SGerd Hoffmann     }
940f1ae32a1SGerd Hoffmann     /* In DMA mode clear RXPKTRDY and set REQPKT automatically
941f1ae32a1SGerd Hoffmann      * (if AUTOREQ is set) */
942f1ae32a1SGerd Hoffmann 
943f1ae32a1SGerd Hoffmann     ep->csr[1] &= ~MGC_M_RXCSR_FIFOFULL;
944f1ae32a1SGerd Hoffmann     value=ep->buf[1][ep->fifostart[1] + ep->fifolen[1] ++];
945f1ae32a1SGerd Hoffmann     TRACE("EP%d 0x%02x, %d", ep->epnum, value, ep->fifolen[1] );
946f1ae32a1SGerd Hoffmann     return value;
947f1ae32a1SGerd Hoffmann }
948f1ae32a1SGerd Hoffmann 
949f1ae32a1SGerd Hoffmann static void musb_write_fifo(MUSBEndPoint *ep, uint8_t value)
950f1ae32a1SGerd Hoffmann {
951f1ae32a1SGerd Hoffmann     TRACE("EP%d = %02x", ep->epnum, value);
952f1ae32a1SGerd Hoffmann     if (ep->fifolen[0] >= 64) {
953f1ae32a1SGerd Hoffmann         /* We have a FIFO overrun */
954f1ae32a1SGerd Hoffmann         TRACE("EP%d FIFO exceeded 64 bytes, stop feeding data", ep->epnum);
955f1ae32a1SGerd Hoffmann         return;
956f1ae32a1SGerd Hoffmann      }
957f1ae32a1SGerd Hoffmann 
958f1ae32a1SGerd Hoffmann      ep->buf[0][ep->fifostart[0] + ep->fifolen[0] ++] = value;
959f1ae32a1SGerd Hoffmann      ep->csr[0] |= MGC_M_TXCSR_FIFONOTEMPTY;
960f1ae32a1SGerd Hoffmann }
961f1ae32a1SGerd Hoffmann 
962f1ae32a1SGerd Hoffmann static void musb_ep_frame_cancel(MUSBEndPoint *ep, int dir)
963f1ae32a1SGerd Hoffmann {
964f1ae32a1SGerd Hoffmann     if (ep->intv_timer[dir])
965bc72ad67SAlex Bligh         timer_del(ep->intv_timer[dir]);
966f1ae32a1SGerd Hoffmann }
967f1ae32a1SGerd Hoffmann 
968f1ae32a1SGerd Hoffmann /* Bus control */
969f1ae32a1SGerd Hoffmann static uint8_t musb_busctl_readb(void *opaque, int ep, int addr)
970f1ae32a1SGerd Hoffmann {
971f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
972f1ae32a1SGerd Hoffmann 
973f1ae32a1SGerd Hoffmann     switch (addr) {
974f1ae32a1SGerd Hoffmann     /* For USB2.0 HS hubs only */
975f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBADDR:
976f1ae32a1SGerd Hoffmann         return s->ep[ep].haddr[0];
977f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBPORT:
978f1ae32a1SGerd Hoffmann         return s->ep[ep].hport[0];
979f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBADDR:
980f1ae32a1SGerd Hoffmann         return s->ep[ep].haddr[1];
981f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBPORT:
982f1ae32a1SGerd Hoffmann         return s->ep[ep].hport[1];
983f1ae32a1SGerd Hoffmann 
984f1ae32a1SGerd Hoffmann     default:
985f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
986f1ae32a1SGerd Hoffmann         return 0x00;
987f1ae32a1SGerd Hoffmann     };
988f1ae32a1SGerd Hoffmann }
989f1ae32a1SGerd Hoffmann 
990f1ae32a1SGerd Hoffmann static void musb_busctl_writeb(void *opaque, int ep, int addr, uint8_t value)
991f1ae32a1SGerd Hoffmann {
992f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
993f1ae32a1SGerd Hoffmann 
994f1ae32a1SGerd Hoffmann     switch (addr) {
995f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
996f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[0] = value;
997f1ae32a1SGerd Hoffmann         break;
998f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
999f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[1] = value;
1000f1ae32a1SGerd Hoffmann         break;
1001f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBADDR:
1002f1ae32a1SGerd Hoffmann         s->ep[ep].haddr[0] = value;
1003f1ae32a1SGerd Hoffmann         break;
1004f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXHUBPORT:
1005f1ae32a1SGerd Hoffmann         s->ep[ep].hport[0] = value;
1006f1ae32a1SGerd Hoffmann         break;
1007f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBADDR:
1008f1ae32a1SGerd Hoffmann         s->ep[ep].haddr[1] = value;
1009f1ae32a1SGerd Hoffmann         break;
1010f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXHUBPORT:
1011f1ae32a1SGerd Hoffmann         s->ep[ep].hport[1] = value;
1012f1ae32a1SGerd Hoffmann         break;
1013f1ae32a1SGerd Hoffmann 
1014f1ae32a1SGerd Hoffmann     default:
1015f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1016f1ae32a1SGerd Hoffmann         break;
1017f1ae32a1SGerd Hoffmann     };
1018f1ae32a1SGerd Hoffmann }
1019f1ae32a1SGerd Hoffmann 
1020f1ae32a1SGerd Hoffmann static uint16_t musb_busctl_readh(void *opaque, int ep, int addr)
1021f1ae32a1SGerd Hoffmann {
1022f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1023f1ae32a1SGerd Hoffmann 
1024f1ae32a1SGerd Hoffmann     switch (addr) {
1025f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
1026f1ae32a1SGerd Hoffmann         return s->ep[ep].faddr[0];
1027f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
1028f1ae32a1SGerd Hoffmann         return s->ep[ep].faddr[1];
1029f1ae32a1SGerd Hoffmann 
1030f1ae32a1SGerd Hoffmann     default:
1031f1ae32a1SGerd Hoffmann         return musb_busctl_readb(s, ep, addr) |
1032f1ae32a1SGerd Hoffmann                 (musb_busctl_readb(s, ep, addr | 1) << 8);
1033f1ae32a1SGerd Hoffmann     };
1034f1ae32a1SGerd Hoffmann }
1035f1ae32a1SGerd Hoffmann 
1036f1ae32a1SGerd Hoffmann static void musb_busctl_writeh(void *opaque, int ep, int addr, uint16_t value)
1037f1ae32a1SGerd Hoffmann {
1038f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1039f1ae32a1SGerd Hoffmann 
1040f1ae32a1SGerd Hoffmann     switch (addr) {
1041f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFUNCADDR:
1042f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[0] = value;
1043f1ae32a1SGerd Hoffmann         break;
1044f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFUNCADDR:
1045f1ae32a1SGerd Hoffmann         s->ep[ep].faddr[1] = value;
1046f1ae32a1SGerd Hoffmann         break;
1047f1ae32a1SGerd Hoffmann 
1048f1ae32a1SGerd Hoffmann     default:
1049f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr, value & 0xff);
1050f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr | 1, value >> 8);
1051f1ae32a1SGerd Hoffmann     };
1052f1ae32a1SGerd Hoffmann }
1053f1ae32a1SGerd Hoffmann 
1054f1ae32a1SGerd Hoffmann /* Endpoint control */
1055f1ae32a1SGerd Hoffmann static uint8_t musb_ep_readb(void *opaque, int ep, int addr)
1056f1ae32a1SGerd Hoffmann {
1057f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1058f1ae32a1SGerd Hoffmann 
1059f1ae32a1SGerd Hoffmann     switch (addr) {
1060f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXTYPE:
1061f1ae32a1SGerd Hoffmann         return s->ep[ep].type[0];
1062f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXINTERVAL:
1063f1ae32a1SGerd Hoffmann         return s->ep[ep].interval[0];
1064f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXTYPE:
1065f1ae32a1SGerd Hoffmann         return s->ep[ep].type[1];
1066f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXINTERVAL:
1067f1ae32a1SGerd Hoffmann         return s->ep[ep].interval[1];
1068f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_FIFOSIZE & ~1):
1069f1ae32a1SGerd Hoffmann         return 0x00;
1070f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFOSIZE:
1071f1ae32a1SGerd Hoffmann         return ep ? s->ep[ep].fifosize : s->ep[ep].config;
1072f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1073f1ae32a1SGerd Hoffmann         return s->ep[ep].rxcount;
1074f1ae32a1SGerd Hoffmann 
1075f1ae32a1SGerd Hoffmann     default:
1076f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1077f1ae32a1SGerd Hoffmann         return 0x00;
1078f1ae32a1SGerd Hoffmann     };
1079f1ae32a1SGerd Hoffmann }
1080f1ae32a1SGerd Hoffmann 
1081f1ae32a1SGerd Hoffmann static void musb_ep_writeb(void *opaque, int ep, int addr, uint8_t value)
1082f1ae32a1SGerd Hoffmann {
1083f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1084f1ae32a1SGerd Hoffmann 
1085f1ae32a1SGerd Hoffmann     switch (addr) {
1086f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXTYPE:
1087f1ae32a1SGerd Hoffmann         s->ep[ep].type[0] = value;
1088f1ae32a1SGerd Hoffmann         break;
1089f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXINTERVAL:
1090f1ae32a1SGerd Hoffmann         s->ep[ep].interval[0] = value;
1091f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 0);
1092f1ae32a1SGerd Hoffmann         break;
1093f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXTYPE:
1094f1ae32a1SGerd Hoffmann         s->ep[ep].type[1] = value;
1095f1ae32a1SGerd Hoffmann         break;
1096f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXINTERVAL:
1097f1ae32a1SGerd Hoffmann         s->ep[ep].interval[1] = value;
1098f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 1);
1099f1ae32a1SGerd Hoffmann         break;
1100f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_FIFOSIZE & ~1):
1101f1ae32a1SGerd Hoffmann         break;
1102f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFOSIZE:
1103f1ae32a1SGerd Hoffmann         TRACE("somebody messes with fifosize (now %i bytes)", value);
1104f1ae32a1SGerd Hoffmann         s->ep[ep].fifosize = value;
1105f1ae32a1SGerd Hoffmann         break;
1106f1ae32a1SGerd Hoffmann     default:
1107f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", addr);
1108f1ae32a1SGerd Hoffmann         break;
1109f1ae32a1SGerd Hoffmann     };
1110f1ae32a1SGerd Hoffmann }
1111f1ae32a1SGerd Hoffmann 
1112f1ae32a1SGerd Hoffmann static uint16_t musb_ep_readh(void *opaque, int ep, int addr)
1113f1ae32a1SGerd Hoffmann {
1114f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1115f1ae32a1SGerd Hoffmann     uint16_t ret;
1116f1ae32a1SGerd Hoffmann 
1117f1ae32a1SGerd Hoffmann     switch (addr) {
1118f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXMAXP:
1119f1ae32a1SGerd Hoffmann         return s->ep[ep].maxp[0];
1120f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXCSR:
1121f1ae32a1SGerd Hoffmann         return s->ep[ep].csr[0];
1122f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXMAXP:
1123f1ae32a1SGerd Hoffmann         return s->ep[ep].maxp[1];
1124f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCSR:
1125f1ae32a1SGerd Hoffmann         ret = s->ep[ep].csr[1];
1126f1ae32a1SGerd Hoffmann 
1127f1ae32a1SGerd Hoffmann         /* TODO: This and other bits probably depend on
1128f1ae32a1SGerd Hoffmann          * ep->csr[1] & MGC_M_RXCSR_AUTOCLEAR.  */
1129f1ae32a1SGerd Hoffmann         if (s->ep[ep].csr[1] & MGC_M_RXCSR_AUTOCLEAR)
1130f1ae32a1SGerd Hoffmann             s->ep[ep].csr[1] &= ~MGC_M_RXCSR_RXPKTRDY;
1131f1ae32a1SGerd Hoffmann 
1132f1ae32a1SGerd Hoffmann         return ret;
1133f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1134f1ae32a1SGerd Hoffmann         return s->ep[ep].rxcount;
1135f1ae32a1SGerd Hoffmann 
1136f1ae32a1SGerd Hoffmann     default:
1137f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, ep, addr) |
1138f1ae32a1SGerd Hoffmann                 (musb_ep_readb(s, ep, addr | 1) << 8);
1139f1ae32a1SGerd Hoffmann     };
1140f1ae32a1SGerd Hoffmann }
1141f1ae32a1SGerd Hoffmann 
1142f1ae32a1SGerd Hoffmann static void musb_ep_writeh(void *opaque, int ep, int addr, uint16_t value)
1143f1ae32a1SGerd Hoffmann {
1144f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1145f1ae32a1SGerd Hoffmann 
1146f1ae32a1SGerd Hoffmann     switch (addr) {
1147f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXMAXP:
1148f1ae32a1SGerd Hoffmann         s->ep[ep].maxp[0] = value;
1149f1ae32a1SGerd Hoffmann         break;
1150f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXCSR:
1151f1ae32a1SGerd Hoffmann         if (ep) {
1152f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] &= value & 0xa6;
1153f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] |= value & 0xff59;
1154f1ae32a1SGerd Hoffmann         } else {
1155f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] &= value & 0x85;
1156f1ae32a1SGerd Hoffmann             s->ep[ep].csr[0] |= value & 0xf7a;
1157f1ae32a1SGerd Hoffmann         }
1158f1ae32a1SGerd Hoffmann 
1159f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 0);
1160f1ae32a1SGerd Hoffmann 
1161f1ae32a1SGerd Hoffmann         if ((ep && (value & MGC_M_TXCSR_FLUSHFIFO)) ||
1162f1ae32a1SGerd Hoffmann                         (!ep && (value & MGC_M_CSR0_FLUSHFIFO))) {
1163f1ae32a1SGerd Hoffmann             s->ep[ep].fifolen[0] = 0;
1164f1ae32a1SGerd Hoffmann             s->ep[ep].fifostart[0] = 0;
1165f1ae32a1SGerd Hoffmann             if (ep)
1166f1ae32a1SGerd Hoffmann                 s->ep[ep].csr[0] &=
1167f1ae32a1SGerd Hoffmann                         ~(MGC_M_TXCSR_FIFONOTEMPTY | MGC_M_TXCSR_TXPKTRDY);
1168f1ae32a1SGerd Hoffmann             else
1169f1ae32a1SGerd Hoffmann                 s->ep[ep].csr[0] &=
1170f1ae32a1SGerd Hoffmann                         ~(MGC_M_CSR0_TXPKTRDY | MGC_M_CSR0_RXPKTRDY);
1171f1ae32a1SGerd Hoffmann         }
1172f1ae32a1SGerd Hoffmann         if (
1173f1ae32a1SGerd Hoffmann                         (ep &&
1174f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1175f1ae32a1SGerd Hoffmann                          (value & MGC_M_TXCSR_TXPKTRDY) &&
1176f1ae32a1SGerd Hoffmann                          !(value & MGC_M_TXCSR_H_NAKTIMEOUT)) ||
1177f1ae32a1SGerd Hoffmann #else
1178f1ae32a1SGerd Hoffmann                          (value & MGC_M_TXCSR_TXPKTRDY)) ||
1179f1ae32a1SGerd Hoffmann #endif
1180f1ae32a1SGerd Hoffmann                         (!ep &&
1181f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1182f1ae32a1SGerd Hoffmann                          (value & MGC_M_CSR0_TXPKTRDY) &&
1183f1ae32a1SGerd Hoffmann                          !(value & MGC_M_CSR0_H_NAKTIMEOUT)))
1184f1ae32a1SGerd Hoffmann #else
1185f1ae32a1SGerd Hoffmann                          (value & MGC_M_CSR0_TXPKTRDY)))
1186f1ae32a1SGerd Hoffmann #endif
1187f1ae32a1SGerd Hoffmann             musb_tx_rdy(s, ep);
1188f1ae32a1SGerd Hoffmann         if (!ep &&
1189f1ae32a1SGerd Hoffmann                         (value & MGC_M_CSR0_H_REQPKT) &&
1190f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1191f1ae32a1SGerd Hoffmann                         !(value & (MGC_M_CSR0_H_NAKTIMEOUT |
1192f1ae32a1SGerd Hoffmann                                         MGC_M_CSR0_RXPKTRDY)))
1193f1ae32a1SGerd Hoffmann #else
1194f1ae32a1SGerd Hoffmann                         !(value & MGC_M_CSR0_RXPKTRDY))
1195f1ae32a1SGerd Hoffmann #endif
1196f1ae32a1SGerd Hoffmann             musb_rx_req(s, ep);
1197f1ae32a1SGerd Hoffmann         break;
1198f1ae32a1SGerd Hoffmann 
1199f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXMAXP:
1200f1ae32a1SGerd Hoffmann         s->ep[ep].maxp[1] = value;
1201f1ae32a1SGerd Hoffmann         break;
1202f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCSR:
1203f1ae32a1SGerd Hoffmann         /* (DMA mode only) */
1204f1ae32a1SGerd Hoffmann         if (
1205f1ae32a1SGerd Hoffmann                 (value & MGC_M_RXCSR_H_AUTOREQ) &&
1206f1ae32a1SGerd Hoffmann                 !(value & MGC_M_RXCSR_RXPKTRDY) &&
1207f1ae32a1SGerd Hoffmann                 (s->ep[ep].csr[1] & MGC_M_RXCSR_RXPKTRDY))
1208f1ae32a1SGerd Hoffmann             value |= MGC_M_RXCSR_H_REQPKT;
1209f1ae32a1SGerd Hoffmann 
1210f1ae32a1SGerd Hoffmann         s->ep[ep].csr[1] &= 0x102 | (value & 0x4d);
1211f1ae32a1SGerd Hoffmann         s->ep[ep].csr[1] |= value & 0xfeb0;
1212f1ae32a1SGerd Hoffmann 
1213f1ae32a1SGerd Hoffmann         musb_ep_frame_cancel(&s->ep[ep], 1);
1214f1ae32a1SGerd Hoffmann 
1215f1ae32a1SGerd Hoffmann         if (value & MGC_M_RXCSR_FLUSHFIFO) {
1216f1ae32a1SGerd Hoffmann             s->ep[ep].fifolen[1] = 0;
1217f1ae32a1SGerd Hoffmann             s->ep[ep].fifostart[1] = 0;
1218f1ae32a1SGerd Hoffmann             s->ep[ep].csr[1] &= ~(MGC_M_RXCSR_FIFOFULL | MGC_M_RXCSR_RXPKTRDY);
1219f1ae32a1SGerd Hoffmann             /* If double buffering and we have two packets ready, flush
1220f1ae32a1SGerd Hoffmann              * only the first one and set up the fifo at the second packet.  */
1221f1ae32a1SGerd Hoffmann         }
1222f1ae32a1SGerd Hoffmann #ifdef CLEAR_NAK
1223f1ae32a1SGerd Hoffmann         if ((value & MGC_M_RXCSR_H_REQPKT) && !(value & MGC_M_RXCSR_DATAERROR))
1224f1ae32a1SGerd Hoffmann #else
1225f1ae32a1SGerd Hoffmann         if (value & MGC_M_RXCSR_H_REQPKT)
1226f1ae32a1SGerd Hoffmann #endif
1227f1ae32a1SGerd Hoffmann             musb_rx_req(s, ep);
1228f1ae32a1SGerd Hoffmann         break;
1229f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXCOUNT:
1230f1ae32a1SGerd Hoffmann         s->ep[ep].rxcount = value;
1231f1ae32a1SGerd Hoffmann         break;
1232f1ae32a1SGerd Hoffmann 
1233f1ae32a1SGerd Hoffmann     default:
1234f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr, value & 0xff);
1235f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr | 1, value >> 8);
1236f1ae32a1SGerd Hoffmann     };
1237f1ae32a1SGerd Hoffmann }
1238f1ae32a1SGerd Hoffmann 
1239f1ae32a1SGerd Hoffmann /* Generic control */
1240a8170e5eSAvi Kivity static uint32_t musb_readb(void *opaque, hwaddr addr)
1241f1ae32a1SGerd Hoffmann {
1242f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1243f1ae32a1SGerd Hoffmann     int ep, i;
1244f1ae32a1SGerd Hoffmann     uint8_t ret;
1245f1ae32a1SGerd Hoffmann 
1246f1ae32a1SGerd Hoffmann     switch (addr) {
1247f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FADDR:
1248f1ae32a1SGerd Hoffmann         return s->faddr;
1249f1ae32a1SGerd Hoffmann     case MUSB_HDRC_POWER:
1250f1ae32a1SGerd Hoffmann         return s->power;
1251f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSB:
1252f1ae32a1SGerd Hoffmann         ret = s->intr;
1253f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1254f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1255f1ae32a1SGerd Hoffmann                 musb_intr_set(s, i, 0);
1256f1ae32a1SGerd Hoffmann         return ret;
1257f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSBE:
1258f1ae32a1SGerd Hoffmann         return s->mask;
1259f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INDEX:
1260f1ae32a1SGerd Hoffmann         return s->idx;
1261f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TESTMODE:
1262f1ae32a1SGerd Hoffmann         return 0x00;
1263f1ae32a1SGerd Hoffmann 
1264f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1265f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, s->idx, addr & 0xf);
1266f1ae32a1SGerd Hoffmann 
1267f1ae32a1SGerd Hoffmann     case MUSB_HDRC_DEVCTL:
1268f1ae32a1SGerd Hoffmann         return s->devctl;
1269f1ae32a1SGerd Hoffmann 
1270f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOSZ:
1271f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOSZ:
1272f1ae32a1SGerd Hoffmann     case MUSB_HDRC_VCTRL:
1273f1ae32a1SGerd Hoffmann         /* TODO */
1274f1ae32a1SGerd Hoffmann         return 0x00;
1275f1ae32a1SGerd Hoffmann 
1276f1ae32a1SGerd Hoffmann     case MUSB_HDRC_HWVERS:
1277f1ae32a1SGerd Hoffmann         return (1 << 10) | 400;
1278f1ae32a1SGerd Hoffmann 
1279f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_VCTRL | 1):
1280f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_HWVERS | 1):
1281f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_DEVCTL | 1):
1282f1ae32a1SGerd Hoffmann         return 0x00;
1283f1ae32a1SGerd Hoffmann 
1284f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1285f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1286f1ae32a1SGerd Hoffmann         return musb_busctl_readb(s, ep, addr & 0x7);
1287f1ae32a1SGerd Hoffmann 
1288f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1289f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1290f1ae32a1SGerd Hoffmann         return musb_ep_readb(s, ep, addr & 0xf);
1291f1ae32a1SGerd Hoffmann 
1292f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1293f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1294f1ae32a1SGerd Hoffmann         return musb_read_fifo(s->ep + ep);
1295f1ae32a1SGerd Hoffmann 
1296f1ae32a1SGerd Hoffmann     default:
1297f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1298f1ae32a1SGerd Hoffmann         return 0x00;
1299f1ae32a1SGerd Hoffmann     };
1300f1ae32a1SGerd Hoffmann }
1301f1ae32a1SGerd Hoffmann 
1302a8170e5eSAvi Kivity static void musb_writeb(void *opaque, hwaddr addr, uint32_t value)
1303f1ae32a1SGerd Hoffmann {
1304f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1305f1ae32a1SGerd Hoffmann     int ep;
1306f1ae32a1SGerd Hoffmann 
1307f1ae32a1SGerd Hoffmann     switch (addr) {
1308f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FADDR:
1309f1ae32a1SGerd Hoffmann         s->faddr = value & 0x7f;
1310f1ae32a1SGerd Hoffmann         break;
1311f1ae32a1SGerd Hoffmann     case MUSB_HDRC_POWER:
1312f1ae32a1SGerd Hoffmann         s->power = (value & 0xef) | (s->power & 0x10);
1313f1ae32a1SGerd Hoffmann         /* MGC_M_POWER_RESET is also read-only in Peripheral Mode */
1314f1ae32a1SGerd Hoffmann         if ((value & MGC_M_POWER_RESET) && s->port.dev) {
1315f1ae32a1SGerd Hoffmann             usb_device_reset(s->port.dev);
1316f1ae32a1SGerd Hoffmann             /* Negotiate high-speed operation if MGC_M_POWER_HSENAB is set.  */
1317f1ae32a1SGerd Hoffmann             if ((value & MGC_M_POWER_HSENAB) &&
1318f1ae32a1SGerd Hoffmann                             s->port.dev->speed == USB_SPEED_HIGH)
1319f1ae32a1SGerd Hoffmann                 s->power |= MGC_M_POWER_HSMODE;	/* Success */
1320f1ae32a1SGerd Hoffmann             /* Restart frame counting.  */
1321f1ae32a1SGerd Hoffmann         }
1322f1ae32a1SGerd Hoffmann         if (value & MGC_M_POWER_SUSPENDM) {
1323f1ae32a1SGerd Hoffmann             /* When all transfers finish, suspend and if MGC_M_POWER_ENSUSPEND
1324f1ae32a1SGerd Hoffmann              * is set, also go into low power mode.  Frame counting stops.  */
1325f1ae32a1SGerd Hoffmann             /* XXX: Cleared when the interrupt register is read */
1326f1ae32a1SGerd Hoffmann         }
1327f1ae32a1SGerd Hoffmann         if (value & MGC_M_POWER_RESUME) {
1328f1ae32a1SGerd Hoffmann             /* Wait 20ms and signal resuming on the bus.  Frame counting
1329f1ae32a1SGerd Hoffmann              * restarts.  */
1330f1ae32a1SGerd Hoffmann         }
1331f1ae32a1SGerd Hoffmann         break;
1332f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSB:
1333f1ae32a1SGerd Hoffmann         break;
1334f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRUSBE:
1335f1ae32a1SGerd Hoffmann         s->mask = value & 0xff;
1336f1ae32a1SGerd Hoffmann         break;
1337f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INDEX:
1338f1ae32a1SGerd Hoffmann         s->idx = value & 0xf;
1339f1ae32a1SGerd Hoffmann         break;
1340f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TESTMODE:
1341f1ae32a1SGerd Hoffmann         break;
1342f1ae32a1SGerd Hoffmann 
1343f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1344f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, s->idx, addr & 0xf, value);
1345f1ae32a1SGerd Hoffmann         break;
1346f1ae32a1SGerd Hoffmann 
1347f1ae32a1SGerd Hoffmann     case MUSB_HDRC_DEVCTL:
1348f1ae32a1SGerd Hoffmann         s->session = !!(value & MGC_M_DEVCTL_SESSION);
1349f1ae32a1SGerd Hoffmann         musb_session_update(s,
1350f1ae32a1SGerd Hoffmann                         !!s->port.dev,
1351f1ae32a1SGerd Hoffmann                         !!(s->devctl & MGC_M_DEVCTL_SESSION));
1352f1ae32a1SGerd Hoffmann 
1353f1ae32a1SGerd Hoffmann         /* It seems this is the only R/W bit in this register?  */
1354f1ae32a1SGerd Hoffmann         s->devctl &= ~MGC_M_DEVCTL_SESSION;
1355f1ae32a1SGerd Hoffmann         s->devctl |= value & MGC_M_DEVCTL_SESSION;
1356f1ae32a1SGerd Hoffmann         break;
1357f1ae32a1SGerd Hoffmann 
1358f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOSZ:
1359f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOSZ:
1360f1ae32a1SGerd Hoffmann     case MUSB_HDRC_VCTRL:
1361f1ae32a1SGerd Hoffmann         /* TODO */
1362f1ae32a1SGerd Hoffmann         break;
1363f1ae32a1SGerd Hoffmann 
1364f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_VCTRL | 1):
1365f1ae32a1SGerd Hoffmann     case (MUSB_HDRC_DEVCTL | 1):
1366f1ae32a1SGerd Hoffmann         break;
1367f1ae32a1SGerd Hoffmann 
1368f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1369f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1370f1ae32a1SGerd Hoffmann         musb_busctl_writeb(s, ep, addr & 0x7, value);
1371f1ae32a1SGerd Hoffmann         break;
1372f1ae32a1SGerd Hoffmann 
1373f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1374f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1375f1ae32a1SGerd Hoffmann         musb_ep_writeb(s, ep, addr & 0xf, value);
1376f1ae32a1SGerd Hoffmann         break;
1377f1ae32a1SGerd Hoffmann 
1378f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1379f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1380f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1381f1ae32a1SGerd Hoffmann         break;
1382f1ae32a1SGerd Hoffmann 
1383f1ae32a1SGerd Hoffmann     default:
1384f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1385f1ae32a1SGerd Hoffmann         break;
1386f1ae32a1SGerd Hoffmann     };
1387f1ae32a1SGerd Hoffmann }
1388f1ae32a1SGerd Hoffmann 
1389a8170e5eSAvi Kivity static uint32_t musb_readh(void *opaque, hwaddr addr)
1390f1ae32a1SGerd Hoffmann {
1391f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1392f1ae32a1SGerd Hoffmann     int ep, i;
1393f1ae32a1SGerd Hoffmann     uint16_t ret;
1394f1ae32a1SGerd Hoffmann 
1395f1ae32a1SGerd Hoffmann     switch (addr) {
1396f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTX:
1397f1ae32a1SGerd Hoffmann         ret = s->tx_intr;
1398f1ae32a1SGerd Hoffmann         /* Auto clear */
1399f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1400f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1401f1ae32a1SGerd Hoffmann                 musb_tx_intr_set(s, i, 0);
1402f1ae32a1SGerd Hoffmann         return ret;
1403f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRX:
1404f1ae32a1SGerd Hoffmann         ret = s->rx_intr;
1405f1ae32a1SGerd Hoffmann         /* Auto clear */
1406f1ae32a1SGerd Hoffmann         for (i = 0; i < sizeof(ret) * 8; i ++)
1407f1ae32a1SGerd Hoffmann             if (ret & (1 << i))
1408f1ae32a1SGerd Hoffmann                 musb_rx_intr_set(s, i, 0);
1409f1ae32a1SGerd Hoffmann         return ret;
1410f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTXE:
1411f1ae32a1SGerd Hoffmann         return s->tx_mask;
1412f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRXE:
1413f1ae32a1SGerd Hoffmann         return s->rx_mask;
1414f1ae32a1SGerd Hoffmann 
1415f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FRAME:
1416f1ae32a1SGerd Hoffmann         /* TODO */
1417f1ae32a1SGerd Hoffmann         return 0x0000;
1418f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOADDR:
1419f1ae32a1SGerd Hoffmann         return s->ep[s->idx].fifoaddr[0];
1420f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOADDR:
1421f1ae32a1SGerd Hoffmann         return s->ep[s->idx].fifoaddr[1];
1422f1ae32a1SGerd Hoffmann 
1423f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1424f1ae32a1SGerd Hoffmann         return musb_ep_readh(s, s->idx, addr & 0xf);
1425f1ae32a1SGerd Hoffmann 
1426f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1427f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1428f1ae32a1SGerd Hoffmann         return musb_busctl_readh(s, ep, addr & 0x7);
1429f1ae32a1SGerd Hoffmann 
1430f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1431f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1432f1ae32a1SGerd Hoffmann         return musb_ep_readh(s, ep, addr & 0xf);
1433f1ae32a1SGerd Hoffmann 
1434f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1435f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1436f1ae32a1SGerd Hoffmann         return (musb_read_fifo(s->ep + ep) | musb_read_fifo(s->ep + ep) << 8);
1437f1ae32a1SGerd Hoffmann 
1438f1ae32a1SGerd Hoffmann     default:
1439f1ae32a1SGerd Hoffmann         return musb_readb(s, addr) | (musb_readb(s, addr | 1) << 8);
1440f1ae32a1SGerd Hoffmann     };
1441f1ae32a1SGerd Hoffmann }
1442f1ae32a1SGerd Hoffmann 
1443a8170e5eSAvi Kivity static void musb_writeh(void *opaque, hwaddr addr, uint32_t value)
1444f1ae32a1SGerd Hoffmann {
1445f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1446f1ae32a1SGerd Hoffmann     int ep;
1447f1ae32a1SGerd Hoffmann 
1448f1ae32a1SGerd Hoffmann     switch (addr) {
1449f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRTXE:
1450f1ae32a1SGerd Hoffmann         s->tx_mask = value;
1451f1ae32a1SGerd Hoffmann         /* XXX: the masks seem to apply on the raising edge like with
1452f1ae32a1SGerd Hoffmann          * edge-triggered interrupts, thus no need to update.  I may be
1453f1ae32a1SGerd Hoffmann          * wrong though.  */
1454f1ae32a1SGerd Hoffmann         break;
1455f1ae32a1SGerd Hoffmann     case MUSB_HDRC_INTRRXE:
1456f1ae32a1SGerd Hoffmann         s->rx_mask = value;
1457f1ae32a1SGerd Hoffmann         break;
1458f1ae32a1SGerd Hoffmann 
1459f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FRAME:
1460f1ae32a1SGerd Hoffmann         /* TODO */
1461f1ae32a1SGerd Hoffmann         break;
1462f1ae32a1SGerd Hoffmann     case MUSB_HDRC_TXFIFOADDR:
1463f1ae32a1SGerd Hoffmann         s->ep[s->idx].fifoaddr[0] = value;
1464f1ae32a1SGerd Hoffmann         s->ep[s->idx].buf[0] =
1465f1ae32a1SGerd Hoffmann                 s->buf + ((value << 3) & 0x7ff );
1466f1ae32a1SGerd Hoffmann         break;
1467f1ae32a1SGerd Hoffmann     case MUSB_HDRC_RXFIFOADDR:
1468f1ae32a1SGerd Hoffmann         s->ep[s->idx].fifoaddr[1] = value;
1469f1ae32a1SGerd Hoffmann         s->ep[s->idx].buf[1] =
1470f1ae32a1SGerd Hoffmann                 s->buf + ((value << 3) & 0x7ff);
1471f1ae32a1SGerd Hoffmann         break;
1472f1ae32a1SGerd Hoffmann 
1473f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP_IDX ... (MUSB_HDRC_EP_IDX + 0xf):
1474f1ae32a1SGerd Hoffmann         musb_ep_writeh(s, s->idx, addr & 0xf, value);
1475f1ae32a1SGerd Hoffmann         break;
1476f1ae32a1SGerd Hoffmann 
1477f1ae32a1SGerd Hoffmann     case MUSB_HDRC_BUSCTL ... (MUSB_HDRC_BUSCTL + 0x7f):
1478f1ae32a1SGerd Hoffmann         ep = (addr >> 3) & 0xf;
1479f1ae32a1SGerd Hoffmann         musb_busctl_writeh(s, ep, addr & 0x7, value);
1480f1ae32a1SGerd Hoffmann         break;
1481f1ae32a1SGerd Hoffmann 
1482f1ae32a1SGerd Hoffmann     case MUSB_HDRC_EP ... (MUSB_HDRC_EP + 0xff):
1483f1ae32a1SGerd Hoffmann         ep = (addr >> 4) & 0xf;
1484f1ae32a1SGerd Hoffmann         musb_ep_writeh(s, ep, addr & 0xf, value);
1485f1ae32a1SGerd Hoffmann         break;
1486f1ae32a1SGerd Hoffmann 
1487f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1488f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1489f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1490f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 8) & 0xff);
1491f1ae32a1SGerd Hoffmann         break;
1492f1ae32a1SGerd Hoffmann 
1493f1ae32a1SGerd Hoffmann     default:
1494f1ae32a1SGerd Hoffmann         musb_writeb(s, addr, value & 0xff);
1495f1ae32a1SGerd Hoffmann         musb_writeb(s, addr | 1, value >> 8);
1496f1ae32a1SGerd Hoffmann     };
1497f1ae32a1SGerd Hoffmann }
1498f1ae32a1SGerd Hoffmann 
1499a8170e5eSAvi Kivity static uint32_t musb_readw(void *opaque, hwaddr addr)
1500f1ae32a1SGerd Hoffmann {
1501f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1502f1ae32a1SGerd Hoffmann     int ep;
1503f1ae32a1SGerd Hoffmann 
1504f1ae32a1SGerd Hoffmann     switch (addr) {
1505f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1506f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1507f1ae32a1SGerd Hoffmann         return ( musb_read_fifo(s->ep + ep)       |
1508f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 8  |
1509f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 16 |
1510f1ae32a1SGerd Hoffmann                  musb_read_fifo(s->ep + ep) << 24 );
1511f1ae32a1SGerd Hoffmann     default:
1512f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1513f1ae32a1SGerd Hoffmann         return 0x00000000;
1514f1ae32a1SGerd Hoffmann     };
1515f1ae32a1SGerd Hoffmann }
1516f1ae32a1SGerd Hoffmann 
1517a8170e5eSAvi Kivity static void musb_writew(void *opaque, hwaddr addr, uint32_t value)
1518f1ae32a1SGerd Hoffmann {
1519f1ae32a1SGerd Hoffmann     MUSBState *s = (MUSBState *) opaque;
1520f1ae32a1SGerd Hoffmann     int ep;
1521f1ae32a1SGerd Hoffmann 
1522f1ae32a1SGerd Hoffmann     switch (addr) {
1523f1ae32a1SGerd Hoffmann     case MUSB_HDRC_FIFO ... (MUSB_HDRC_FIFO + 0x3f):
1524f1ae32a1SGerd Hoffmann         ep = ((addr - MUSB_HDRC_FIFO) >> 2) & 0xf;
1525f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, value & 0xff);
1526f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 8 ) & 0xff);
1527f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 16) & 0xff);
1528f1ae32a1SGerd Hoffmann         musb_write_fifo(s->ep + ep, (value >> 24) & 0xff);
1529f1ae32a1SGerd Hoffmann             break;
1530f1ae32a1SGerd Hoffmann     default:
1531f1ae32a1SGerd Hoffmann         TRACE("unknown register 0x%02x", (int) addr);
1532f1ae32a1SGerd Hoffmann         break;
1533f1ae32a1SGerd Hoffmann     };
1534f1ae32a1SGerd Hoffmann }
1535f1ae32a1SGerd Hoffmann 
1536f1ae32a1SGerd Hoffmann CPUReadMemoryFunc * const musb_read[] = {
1537f1ae32a1SGerd Hoffmann     musb_readb,
1538f1ae32a1SGerd Hoffmann     musb_readh,
1539f1ae32a1SGerd Hoffmann     musb_readw,
1540f1ae32a1SGerd Hoffmann };
1541f1ae32a1SGerd Hoffmann 
1542f1ae32a1SGerd Hoffmann CPUWriteMemoryFunc * const musb_write[] = {
1543f1ae32a1SGerd Hoffmann     musb_writeb,
1544f1ae32a1SGerd Hoffmann     musb_writeh,
1545f1ae32a1SGerd Hoffmann     musb_writew,
1546f1ae32a1SGerd Hoffmann };
1547