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