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