xref: /OK3568_Linux_fs/u-boot/drivers/usb/musb/musb_udc.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  * Copyright (c) 2009 Wind River Systems, Inc.
3*4882a593Smuzhiyun  * Tom Rix <Tom.Rix@windriver.com>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * This file is a rewrite of the usb device part of
6*4882a593Smuzhiyun  * repository git.omapzoom.org/repo/u-boot.git, branch master,
7*4882a593Smuzhiyun  * file cpu/omap3/fastboot.c
8*4882a593Smuzhiyun  *
9*4882a593Smuzhiyun  * This is the unique part of its copyright :
10*4882a593Smuzhiyun  *
11*4882a593Smuzhiyun  * -------------------------------------------------------------------------
12*4882a593Smuzhiyun  *
13*4882a593Smuzhiyun  * (C) Copyright 2008 - 2009
14*4882a593Smuzhiyun  * Windriver, <www.windriver.com>
15*4882a593Smuzhiyun  * Tom Rix <Tom.Rix@windriver.com>
16*4882a593Smuzhiyun  *
17*4882a593Smuzhiyun  * -------------------------------------------------------------------------
18*4882a593Smuzhiyun  *
19*4882a593Smuzhiyun  * The details of connecting the device to the uboot usb device subsystem
20*4882a593Smuzhiyun  * came from the old omap3 repository www.sakoman.net/u-boot-omap3.git,
21*4882a593Smuzhiyun  * branch omap3-dev-usb, file drivers/usb/usbdcore_musb.c
22*4882a593Smuzhiyun  *
23*4882a593Smuzhiyun  * This is the unique part of its copyright :
24*4882a593Smuzhiyun  *
25*4882a593Smuzhiyun  * -------------------------------------------------------------------------
26*4882a593Smuzhiyun  *
27*4882a593Smuzhiyun  * (C) Copyright 2008 Texas Instruments Incorporated.
28*4882a593Smuzhiyun  *
29*4882a593Smuzhiyun  * Based on
30*4882a593Smuzhiyun  * u-boot OMAP1510 USB drivers (drivers/usbdcore_omap1510.c)
31*4882a593Smuzhiyun  * twl4030 init based on linux (drivers/i2c/chips/twl4030_usb.c)
32*4882a593Smuzhiyun  *
33*4882a593Smuzhiyun  * Author: Diego Dompe (diego.dompe@ridgerun.com)
34*4882a593Smuzhiyun  *         Atin Malaviya (atin.malaviya@gmail.com)
35*4882a593Smuzhiyun  *
36*4882a593Smuzhiyun  * -------------------------------------------------------------------------
37*4882a593Smuzhiyun  *
38*4882a593Smuzhiyun  * SPDX-License-Identifier:	GPL-2.0+
39*4882a593Smuzhiyun  */
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun #include <common.h>
42*4882a593Smuzhiyun #include <usbdevice.h>
43*4882a593Smuzhiyun #include <usb/udc.h>
44*4882a593Smuzhiyun #include "../gadget/ep0.h"
45*4882a593Smuzhiyun #include "musb_core.h"
46*4882a593Smuzhiyun #if defined(CONFIG_USB_OMAP3)
47*4882a593Smuzhiyun #include "omap3.h"
48*4882a593Smuzhiyun #elif defined(CONFIG_USB_AM35X)
49*4882a593Smuzhiyun #include "am35x.h"
50*4882a593Smuzhiyun #elif defined(CONFIG_USB_DAVINCI)
51*4882a593Smuzhiyun #include "davinci.h"
52*4882a593Smuzhiyun #endif
53*4882a593Smuzhiyun 
54*4882a593Smuzhiyun /* Define MUSB_DEBUG for debugging */
55*4882a593Smuzhiyun /* #define MUSB_DEBUG */
56*4882a593Smuzhiyun #include "musb_debug.h"
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun #define MAX_ENDPOINT 15
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun #define GET_ENDPOINT(dev,ep)						\
61*4882a593Smuzhiyun (((struct usb_device_instance *)(dev))->bus->endpoint_array + ep)
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #define SET_EP0_STATE(s)						\
64*4882a593Smuzhiyun do {									\
65*4882a593Smuzhiyun 	if ((0 <= (s)) && (SET_ADDRESS >= (s))) {			\
66*4882a593Smuzhiyun 		if ((s) != ep0_state) {					\
67*4882a593Smuzhiyun 			if ((debug_setup) && (debug_level > 1))		\
68*4882a593Smuzhiyun 				serial_printf("INFO : Changing state "  \
69*4882a593Smuzhiyun 					      "from %s to %s in %s at " \
70*4882a593Smuzhiyun 					      "line %d\n",		\
71*4882a593Smuzhiyun 					      ep0_state_strings[ep0_state],\
72*4882a593Smuzhiyun 					      ep0_state_strings[s],	\
73*4882a593Smuzhiyun 					      __PRETTY_FUNCTION__,	\
74*4882a593Smuzhiyun 					      __LINE__);		\
75*4882a593Smuzhiyun 			ep0_state = s;					\
76*4882a593Smuzhiyun 		}							\
77*4882a593Smuzhiyun 	} else {							\
78*4882a593Smuzhiyun 		if (debug_level > 0)					\
79*4882a593Smuzhiyun 			serial_printf("Error at %s %d with setting "	\
80*4882a593Smuzhiyun 				      "state %d is invalid\n",		\
81*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, __LINE__, s); \
82*4882a593Smuzhiyun 	}								\
83*4882a593Smuzhiyun } while (0)
84*4882a593Smuzhiyun 
85*4882a593Smuzhiyun /* static implies these initialized to 0 or NULL */
86*4882a593Smuzhiyun static int debug_setup;
87*4882a593Smuzhiyun static int debug_level;
88*4882a593Smuzhiyun static struct musb_epinfo epinfo[MAX_ENDPOINT * 2 + 2];
89*4882a593Smuzhiyun static enum ep0_state_enum {
90*4882a593Smuzhiyun 	IDLE = 0,
91*4882a593Smuzhiyun 	TX,
92*4882a593Smuzhiyun 	RX,
93*4882a593Smuzhiyun 	SET_ADDRESS
94*4882a593Smuzhiyun } ep0_state = IDLE;
95*4882a593Smuzhiyun static char *ep0_state_strings[4] = {
96*4882a593Smuzhiyun 	"IDLE",
97*4882a593Smuzhiyun 	"TX",
98*4882a593Smuzhiyun 	"RX",
99*4882a593Smuzhiyun 	"SET_ADDRESS",
100*4882a593Smuzhiyun };
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun static struct urb *ep0_urb;
103*4882a593Smuzhiyun struct usb_endpoint_instance *ep0_endpoint;
104*4882a593Smuzhiyun static struct usb_device_instance *udc_device;
105*4882a593Smuzhiyun static int enabled;
106*4882a593Smuzhiyun 
107*4882a593Smuzhiyun #ifdef MUSB_DEBUG
musb_db_regs(void)108*4882a593Smuzhiyun static void musb_db_regs(void)
109*4882a593Smuzhiyun {
110*4882a593Smuzhiyun 	u8 b;
111*4882a593Smuzhiyun 	u16 w;
112*4882a593Smuzhiyun 
113*4882a593Smuzhiyun 	b = readb(&musbr->faddr);
114*4882a593Smuzhiyun 	serial_printf("\tfaddr   0x%2.2x\n", b);
115*4882a593Smuzhiyun 
116*4882a593Smuzhiyun 	b = readb(&musbr->power);
117*4882a593Smuzhiyun 	musb_print_pwr(b);
118*4882a593Smuzhiyun 
119*4882a593Smuzhiyun 	w = readw(&musbr->ep[0].ep0.csr0);
120*4882a593Smuzhiyun 	musb_print_csr0(w);
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	b = readb(&musbr->devctl);
123*4882a593Smuzhiyun 	musb_print_devctl(b);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	b = readb(&musbr->ep[0].ep0.configdata);
126*4882a593Smuzhiyun 	musb_print_config(b);
127*4882a593Smuzhiyun 
128*4882a593Smuzhiyun 	w = readw(&musbr->frame);
129*4882a593Smuzhiyun 	serial_printf("\tframe   0x%4.4x\n", w);
130*4882a593Smuzhiyun 
131*4882a593Smuzhiyun 	b = readb(&musbr->index);
132*4882a593Smuzhiyun 	serial_printf("\tindex   0x%2.2x\n", b);
133*4882a593Smuzhiyun 
134*4882a593Smuzhiyun 	w = readw(&musbr->ep[1].epN.rxmaxp);
135*4882a593Smuzhiyun 	musb_print_rxmaxp(w);
136*4882a593Smuzhiyun 
137*4882a593Smuzhiyun 	w = readw(&musbr->ep[1].epN.rxcsr);
138*4882a593Smuzhiyun 	musb_print_rxcsr(w);
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	w = readw(&musbr->ep[1].epN.txmaxp);
141*4882a593Smuzhiyun 	musb_print_txmaxp(w);
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun 	w = readw(&musbr->ep[1].epN.txcsr);
144*4882a593Smuzhiyun 	musb_print_txcsr(w);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun #else
147*4882a593Smuzhiyun #define musb_db_regs()
148*4882a593Smuzhiyun #endif /* DEBUG_MUSB */
149*4882a593Smuzhiyun 
musb_peri_softconnect(void)150*4882a593Smuzhiyun static void musb_peri_softconnect(void)
151*4882a593Smuzhiyun {
152*4882a593Smuzhiyun 	u8 power, devctl;
153*4882a593Smuzhiyun 
154*4882a593Smuzhiyun 	/* Power off MUSB */
155*4882a593Smuzhiyun 	power = readb(&musbr->power);
156*4882a593Smuzhiyun 	power &= ~MUSB_POWER_SOFTCONN;
157*4882a593Smuzhiyun 	writeb(power, &musbr->power);
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	/* Read intr to clear */
160*4882a593Smuzhiyun 	readb(&musbr->intrusb);
161*4882a593Smuzhiyun 	readw(&musbr->intrrx);
162*4882a593Smuzhiyun 	readw(&musbr->intrtx);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	udelay(1000 * 1000); /* 1 sec */
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	/* Power on MUSB */
167*4882a593Smuzhiyun 	power = readb(&musbr->power);
168*4882a593Smuzhiyun 	power |= MUSB_POWER_SOFTCONN;
169*4882a593Smuzhiyun 	/*
170*4882a593Smuzhiyun 	 * The usb device interface is usb 1.1
171*4882a593Smuzhiyun 	 * Disable 2.0 high speed by clearring the hsenable bit.
172*4882a593Smuzhiyun 	 */
173*4882a593Smuzhiyun 	power &= ~MUSB_POWER_HSENAB;
174*4882a593Smuzhiyun 	writeb(power, &musbr->power);
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	/* Check if device is in b-peripheral mode */
177*4882a593Smuzhiyun 	devctl = readb(&musbr->devctl);
178*4882a593Smuzhiyun 	if (!(devctl & MUSB_DEVCTL_BDEVICE) ||
179*4882a593Smuzhiyun 	    (devctl & MUSB_DEVCTL_HM)) {
180*4882a593Smuzhiyun 		serial_printf("ERROR : Unsupport USB mode\n");
181*4882a593Smuzhiyun 		serial_printf("Check that mini-B USB cable is attached "
182*4882a593Smuzhiyun 			      "to the device\n");
183*4882a593Smuzhiyun 	}
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	if (debug_setup && (debug_level > 1))
186*4882a593Smuzhiyun 		musb_db_regs();
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
musb_peri_reset(void)189*4882a593Smuzhiyun static void musb_peri_reset(void)
190*4882a593Smuzhiyun {
191*4882a593Smuzhiyun 	if ((debug_setup) && (debug_level > 1))
192*4882a593Smuzhiyun 		serial_printf("INFO : %s reset\n", __PRETTY_FUNCTION__);
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun 	if (ep0_endpoint)
195*4882a593Smuzhiyun 		ep0_endpoint->endpoint_address = 0xff;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 	/* Sync sw and hw addresses */
198*4882a593Smuzhiyun 	writeb(udc_device->address, &musbr->faddr);
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 	SET_EP0_STATE(IDLE);
201*4882a593Smuzhiyun }
202*4882a593Smuzhiyun 
musb_peri_resume(void)203*4882a593Smuzhiyun static void musb_peri_resume(void)
204*4882a593Smuzhiyun {
205*4882a593Smuzhiyun 	/* noop */
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun 
musb_peri_ep0_stall(void)208*4882a593Smuzhiyun static void musb_peri_ep0_stall(void)
209*4882a593Smuzhiyun {
210*4882a593Smuzhiyun 	u16 csr0;
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
213*4882a593Smuzhiyun 	csr0 |= MUSB_CSR0_P_SENDSTALL;
214*4882a593Smuzhiyun 	writew(csr0, &musbr->ep[0].ep0.csr0);
215*4882a593Smuzhiyun 	if ((debug_setup) && (debug_level > 1))
216*4882a593Smuzhiyun 		serial_printf("INFO : %s stall\n", __PRETTY_FUNCTION__);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun 
musb_peri_ep0_ack_req(void)219*4882a593Smuzhiyun static void musb_peri_ep0_ack_req(void)
220*4882a593Smuzhiyun {
221*4882a593Smuzhiyun 	u16 csr0;
222*4882a593Smuzhiyun 
223*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
224*4882a593Smuzhiyun 	csr0 |= MUSB_CSR0_P_SVDRXPKTRDY;
225*4882a593Smuzhiyun 	writew(csr0, &musbr->ep[0].ep0.csr0);
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
musb_ep0_tx_ready(void)228*4882a593Smuzhiyun static void musb_ep0_tx_ready(void)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	u16 csr0;
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
233*4882a593Smuzhiyun 	csr0 |= MUSB_CSR0_TXPKTRDY;
234*4882a593Smuzhiyun 	writew(csr0, &musbr->ep[0].ep0.csr0);
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
musb_ep0_tx_ready_and_last(void)237*4882a593Smuzhiyun static void musb_ep0_tx_ready_and_last(void)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	u16 csr0;
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
242*4882a593Smuzhiyun 	csr0 |= (MUSB_CSR0_TXPKTRDY | MUSB_CSR0_P_DATAEND);
243*4882a593Smuzhiyun 	writew(csr0, &musbr->ep[0].ep0.csr0);
244*4882a593Smuzhiyun }
245*4882a593Smuzhiyun 
musb_peri_ep0_last(void)246*4882a593Smuzhiyun static void musb_peri_ep0_last(void)
247*4882a593Smuzhiyun {
248*4882a593Smuzhiyun 	u16 csr0;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
251*4882a593Smuzhiyun 	csr0 |= MUSB_CSR0_P_DATAEND;
252*4882a593Smuzhiyun 	writew(csr0, &musbr->ep[0].ep0.csr0);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
musb_peri_ep0_set_address(void)255*4882a593Smuzhiyun static void musb_peri_ep0_set_address(void)
256*4882a593Smuzhiyun {
257*4882a593Smuzhiyun 	u8 faddr;
258*4882a593Smuzhiyun 	writeb(udc_device->address, &musbr->faddr);
259*4882a593Smuzhiyun 
260*4882a593Smuzhiyun 	/* Verify */
261*4882a593Smuzhiyun 	faddr = readb(&musbr->faddr);
262*4882a593Smuzhiyun 	if (udc_device->address == faddr) {
263*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
264*4882a593Smuzhiyun 		usbd_device_event_irq(udc_device, DEVICE_ADDRESS_ASSIGNED, 0);
265*4882a593Smuzhiyun 		if ((debug_setup) && (debug_level > 1))
266*4882a593Smuzhiyun 			serial_printf("INFO : %s Address set to %d\n",
267*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, udc_device->address);
268*4882a593Smuzhiyun 	} else {
269*4882a593Smuzhiyun 		if (debug_level > 0)
270*4882a593Smuzhiyun 			serial_printf("ERROR : %s Address missmatch "
271*4882a593Smuzhiyun 				      "sw %d vs hw %d\n",
272*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__,
273*4882a593Smuzhiyun 				      udc_device->address, faddr);
274*4882a593Smuzhiyun 	}
275*4882a593Smuzhiyun }
276*4882a593Smuzhiyun 
musb_peri_rx_ack(unsigned int ep)277*4882a593Smuzhiyun static void musb_peri_rx_ack(unsigned int ep)
278*4882a593Smuzhiyun {
279*4882a593Smuzhiyun 	u16 peri_rxcsr;
280*4882a593Smuzhiyun 
281*4882a593Smuzhiyun 	peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
282*4882a593Smuzhiyun 	peri_rxcsr &= ~MUSB_RXCSR_RXPKTRDY;
283*4882a593Smuzhiyun 	writew(peri_rxcsr, &musbr->ep[ep].epN.rxcsr);
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun 
musb_peri_tx_ready(unsigned int ep)286*4882a593Smuzhiyun static void musb_peri_tx_ready(unsigned int ep)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	u16 peri_txcsr;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
291*4882a593Smuzhiyun 	peri_txcsr |= MUSB_TXCSR_TXPKTRDY;
292*4882a593Smuzhiyun 	writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
293*4882a593Smuzhiyun }
294*4882a593Smuzhiyun 
musb_peri_ep0_zero_data_request(int err)295*4882a593Smuzhiyun static void musb_peri_ep0_zero_data_request(int err)
296*4882a593Smuzhiyun {
297*4882a593Smuzhiyun 	musb_peri_ep0_ack_req();
298*4882a593Smuzhiyun 
299*4882a593Smuzhiyun 	if (err) {
300*4882a593Smuzhiyun 		musb_peri_ep0_stall();
301*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
302*4882a593Smuzhiyun 	} else {
303*4882a593Smuzhiyun 
304*4882a593Smuzhiyun 		musb_peri_ep0_last();
305*4882a593Smuzhiyun 
306*4882a593Smuzhiyun 		/* USBD state */
307*4882a593Smuzhiyun 		switch (ep0_urb->device_request.bRequest) {
308*4882a593Smuzhiyun 		case USB_REQ_SET_ADDRESS:
309*4882a593Smuzhiyun 			if ((debug_setup) && (debug_level > 1))
310*4882a593Smuzhiyun 				serial_printf("INFO : %s received set "
311*4882a593Smuzhiyun 					      "address\n", __PRETTY_FUNCTION__);
312*4882a593Smuzhiyun 			break;
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 		case USB_REQ_SET_CONFIGURATION:
315*4882a593Smuzhiyun 			if ((debug_setup) && (debug_level > 1))
316*4882a593Smuzhiyun 				serial_printf("INFO : %s Configured\n",
317*4882a593Smuzhiyun 					      __PRETTY_FUNCTION__);
318*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device, DEVICE_CONFIGURED, 0);
319*4882a593Smuzhiyun 			break;
320*4882a593Smuzhiyun 		}
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 		/* EP0 state */
323*4882a593Smuzhiyun 		if (USB_REQ_SET_ADDRESS == ep0_urb->device_request.bRequest) {
324*4882a593Smuzhiyun 			SET_EP0_STATE(SET_ADDRESS);
325*4882a593Smuzhiyun 		} else {
326*4882a593Smuzhiyun 			SET_EP0_STATE(IDLE);
327*4882a593Smuzhiyun 		}
328*4882a593Smuzhiyun 	}
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
musb_peri_ep0_rx_data_request(void)331*4882a593Smuzhiyun static void musb_peri_ep0_rx_data_request(void)
332*4882a593Smuzhiyun {
333*4882a593Smuzhiyun 	/*
334*4882a593Smuzhiyun 	 * This is the completion of the data OUT / RX
335*4882a593Smuzhiyun 	 *
336*4882a593Smuzhiyun 	 * Host is sending data to ep0 that is not
337*4882a593Smuzhiyun 	 * part of setup.  This comes from the cdc_recv_setup
338*4882a593Smuzhiyun 	 * op that is device specific.
339*4882a593Smuzhiyun 	 *
340*4882a593Smuzhiyun 	 */
341*4882a593Smuzhiyun 	musb_peri_ep0_ack_req();
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	ep0_endpoint->rcv_urb = ep0_urb;
344*4882a593Smuzhiyun 	ep0_urb->actual_length = 0;
345*4882a593Smuzhiyun 	SET_EP0_STATE(RX);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun 
musb_peri_ep0_tx_data_request(int err)348*4882a593Smuzhiyun static void musb_peri_ep0_tx_data_request(int err)
349*4882a593Smuzhiyun {
350*4882a593Smuzhiyun 	if (err) {
351*4882a593Smuzhiyun 		musb_peri_ep0_stall();
352*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
353*4882a593Smuzhiyun 	} else {
354*4882a593Smuzhiyun 		musb_peri_ep0_ack_req();
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		ep0_endpoint->tx_urb = ep0_urb;
357*4882a593Smuzhiyun 		ep0_endpoint->sent = 0;
358*4882a593Smuzhiyun 		SET_EP0_STATE(TX);
359*4882a593Smuzhiyun 	}
360*4882a593Smuzhiyun }
361*4882a593Smuzhiyun 
musb_peri_ep0_idle(void)362*4882a593Smuzhiyun static void musb_peri_ep0_idle(void)
363*4882a593Smuzhiyun {
364*4882a593Smuzhiyun 	u16 count0;
365*4882a593Smuzhiyun 	int err;
366*4882a593Smuzhiyun 	u16 csr0;
367*4882a593Smuzhiyun 
368*4882a593Smuzhiyun 	/*
369*4882a593Smuzhiyun 	 * Verify addresses
370*4882a593Smuzhiyun 	 * A lot of confusion can be caused if the address
371*4882a593Smuzhiyun 	 * in software, udc layer, does not agree with the
372*4882a593Smuzhiyun 	 * hardware.  Since the setting of the hardware address
373*4882a593Smuzhiyun 	 * must be set after the set address request, the
374*4882a593Smuzhiyun 	 * usb state machine is out of sync for a few frame.
375*4882a593Smuzhiyun 	 * It is a good idea to run this check when changes
376*4882a593Smuzhiyun 	 * are made to the state machine.
377*4882a593Smuzhiyun 	 */
378*4882a593Smuzhiyun 	if ((debug_level > 0) &&
379*4882a593Smuzhiyun 	    (ep0_state != SET_ADDRESS)) {
380*4882a593Smuzhiyun 		u8 faddr;
381*4882a593Smuzhiyun 
382*4882a593Smuzhiyun 		faddr = readb(&musbr->faddr);
383*4882a593Smuzhiyun 		if (udc_device->address != faddr) {
384*4882a593Smuzhiyun 			serial_printf("ERROR : %s addresses do not"
385*4882a593Smuzhiyun 				      "match sw %d vs hw %d\n",
386*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__,
387*4882a593Smuzhiyun 				      udc_device->address, faddr);
388*4882a593Smuzhiyun 			udelay(1000 * 1000);
389*4882a593Smuzhiyun 			hang();
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
394*4882a593Smuzhiyun 
395*4882a593Smuzhiyun 	if (!(MUSB_CSR0_RXPKTRDY & csr0))
396*4882a593Smuzhiyun 		goto end;
397*4882a593Smuzhiyun 
398*4882a593Smuzhiyun 	count0 = readw(&musbr->ep[0].ep0.count0);
399*4882a593Smuzhiyun 	if (count0 == 0)
400*4882a593Smuzhiyun 		goto end;
401*4882a593Smuzhiyun 
402*4882a593Smuzhiyun 	if (count0 != 8) {
403*4882a593Smuzhiyun 		if ((debug_setup) && (debug_level > 1))
404*4882a593Smuzhiyun 			serial_printf("WARN : %s SETUP incorrect size %d\n",
405*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, count0);
406*4882a593Smuzhiyun 		musb_peri_ep0_stall();
407*4882a593Smuzhiyun 		goto end;
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	read_fifo(0, count0, &ep0_urb->device_request);
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 	if (debug_level > 2)
413*4882a593Smuzhiyun 		print_usb_device_request(&ep0_urb->device_request);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (ep0_urb->device_request.wLength == 0) {
416*4882a593Smuzhiyun 		err = ep0_recv_setup(ep0_urb);
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 		/* Zero data request */
419*4882a593Smuzhiyun 		musb_peri_ep0_zero_data_request(err);
420*4882a593Smuzhiyun 	} else {
421*4882a593Smuzhiyun 		/* Is data coming or going ? */
422*4882a593Smuzhiyun 		u8 reqType = ep0_urb->device_request.bmRequestType;
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 		if (USB_REQ_DEVICE2HOST == (reqType & USB_REQ_DIRECTION_MASK)) {
425*4882a593Smuzhiyun 			err = ep0_recv_setup(ep0_urb);
426*4882a593Smuzhiyun 			/* Device to host */
427*4882a593Smuzhiyun 			musb_peri_ep0_tx_data_request(err);
428*4882a593Smuzhiyun 		} else {
429*4882a593Smuzhiyun 			/*
430*4882a593Smuzhiyun 			 * Host to device
431*4882a593Smuzhiyun 			 *
432*4882a593Smuzhiyun 			 * The RX routine will call ep0_recv_setup
433*4882a593Smuzhiyun 			 * when the data packet has arrived.
434*4882a593Smuzhiyun 			 */
435*4882a593Smuzhiyun 			musb_peri_ep0_rx_data_request();
436*4882a593Smuzhiyun 		}
437*4882a593Smuzhiyun 	}
438*4882a593Smuzhiyun 
439*4882a593Smuzhiyun end:
440*4882a593Smuzhiyun 	return;
441*4882a593Smuzhiyun }
442*4882a593Smuzhiyun 
musb_peri_ep0_rx(void)443*4882a593Smuzhiyun static void musb_peri_ep0_rx(void)
444*4882a593Smuzhiyun {
445*4882a593Smuzhiyun 	/*
446*4882a593Smuzhiyun 	 * This is the completion of the data OUT / RX
447*4882a593Smuzhiyun 	 *
448*4882a593Smuzhiyun 	 * Host is sending data to ep0 that is not
449*4882a593Smuzhiyun 	 * part of setup.  This comes from the cdc_recv_setup
450*4882a593Smuzhiyun 	 * op that is device specific.
451*4882a593Smuzhiyun 	 *
452*4882a593Smuzhiyun 	 * Pass the data back to driver ep0_recv_setup which
453*4882a593Smuzhiyun 	 * should give the cdc_recv_setup the chance to handle
454*4882a593Smuzhiyun 	 * the rx
455*4882a593Smuzhiyun 	 */
456*4882a593Smuzhiyun 	u16 csr0;
457*4882a593Smuzhiyun 	u16 count0;
458*4882a593Smuzhiyun 
459*4882a593Smuzhiyun 	if (debug_level > 3) {
460*4882a593Smuzhiyun 		if (0 != ep0_urb->actual_length) {
461*4882a593Smuzhiyun 			serial_printf("%s finished ? %d of %d\n",
462*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__,
463*4882a593Smuzhiyun 				      ep0_urb->actual_length,
464*4882a593Smuzhiyun 				      ep0_urb->device_request.wLength);
465*4882a593Smuzhiyun 		}
466*4882a593Smuzhiyun 	}
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	if (ep0_urb->device_request.wLength == ep0_urb->actual_length) {
469*4882a593Smuzhiyun 		musb_peri_ep0_last();
470*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
471*4882a593Smuzhiyun 		ep0_recv_setup(ep0_urb);
472*4882a593Smuzhiyun 		return;
473*4882a593Smuzhiyun 	}
474*4882a593Smuzhiyun 
475*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
476*4882a593Smuzhiyun 	if (!(MUSB_CSR0_RXPKTRDY & csr0))
477*4882a593Smuzhiyun 		return;
478*4882a593Smuzhiyun 
479*4882a593Smuzhiyun 	count0 = readw(&musbr->ep[0].ep0.count0);
480*4882a593Smuzhiyun 
481*4882a593Smuzhiyun 	if (count0) {
482*4882a593Smuzhiyun 		struct usb_endpoint_instance *endpoint;
483*4882a593Smuzhiyun 		u32 length;
484*4882a593Smuzhiyun 		u8 *data;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 		endpoint = ep0_endpoint;
487*4882a593Smuzhiyun 		if (endpoint && endpoint->rcv_urb) {
488*4882a593Smuzhiyun 			struct urb *urb = endpoint->rcv_urb;
489*4882a593Smuzhiyun 			unsigned int remaining_space = urb->buffer_length -
490*4882a593Smuzhiyun 				urb->actual_length;
491*4882a593Smuzhiyun 
492*4882a593Smuzhiyun 			if (remaining_space) {
493*4882a593Smuzhiyun 				int urb_bad = 0; /* urb is good */
494*4882a593Smuzhiyun 
495*4882a593Smuzhiyun 				if (count0 > remaining_space)
496*4882a593Smuzhiyun 					length = remaining_space;
497*4882a593Smuzhiyun 				else
498*4882a593Smuzhiyun 					length = count0;
499*4882a593Smuzhiyun 
500*4882a593Smuzhiyun 				data = (u8 *) urb->buffer_data;
501*4882a593Smuzhiyun 				data += urb->actual_length;
502*4882a593Smuzhiyun 
503*4882a593Smuzhiyun 				/* The common musb fifo reader */
504*4882a593Smuzhiyun 				read_fifo(0, length, data);
505*4882a593Smuzhiyun 
506*4882a593Smuzhiyun 				musb_peri_ep0_ack_req();
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 				/*
509*4882a593Smuzhiyun 				 * urb's actual_length is updated in
510*4882a593Smuzhiyun 				 * usbd_rcv_complete
511*4882a593Smuzhiyun 				 */
512*4882a593Smuzhiyun 				usbd_rcv_complete(endpoint, length, urb_bad);
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 			} else {
515*4882a593Smuzhiyun 				if (debug_level > 0)
516*4882a593Smuzhiyun 					serial_printf("ERROR : %s no space in "
517*4882a593Smuzhiyun 						      "rcv buffer\n",
518*4882a593Smuzhiyun 						      __PRETTY_FUNCTION__);
519*4882a593Smuzhiyun 			}
520*4882a593Smuzhiyun 		} else {
521*4882a593Smuzhiyun 			if (debug_level > 0)
522*4882a593Smuzhiyun 				serial_printf("ERROR : %s problem with "
523*4882a593Smuzhiyun 					      "endpoint\n",
524*4882a593Smuzhiyun 					      __PRETTY_FUNCTION__);
525*4882a593Smuzhiyun 		}
526*4882a593Smuzhiyun 	} else {
527*4882a593Smuzhiyun 		if (debug_level > 0)
528*4882a593Smuzhiyun 			serial_printf("ERROR : %s with nothing to do\n",
529*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__);
530*4882a593Smuzhiyun 	}
531*4882a593Smuzhiyun }
532*4882a593Smuzhiyun 
musb_peri_ep0_tx(void)533*4882a593Smuzhiyun static void musb_peri_ep0_tx(void)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	u16 csr0;
536*4882a593Smuzhiyun 	int transfer_size = 0;
537*4882a593Smuzhiyun 	unsigned int p, pm;
538*4882a593Smuzhiyun 
539*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	/* Check for pending tx */
542*4882a593Smuzhiyun 	if (csr0 & MUSB_CSR0_TXPKTRDY)
543*4882a593Smuzhiyun 		goto end;
544*4882a593Smuzhiyun 
545*4882a593Smuzhiyun 	/* Check if this is the last packet sent */
546*4882a593Smuzhiyun 	if (ep0_endpoint->sent >= ep0_urb->actual_length) {
547*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
548*4882a593Smuzhiyun 		goto end;
549*4882a593Smuzhiyun 	}
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	transfer_size = ep0_urb->actual_length - ep0_endpoint->sent;
552*4882a593Smuzhiyun 	/* Is the transfer size negative ? */
553*4882a593Smuzhiyun 	if (transfer_size <= 0) {
554*4882a593Smuzhiyun 		if (debug_level > 0)
555*4882a593Smuzhiyun 			serial_printf("ERROR : %s problem with the"
556*4882a593Smuzhiyun 				      " transfer size %d\n",
557*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__,
558*4882a593Smuzhiyun 				      transfer_size);
559*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
560*4882a593Smuzhiyun 		goto end;
561*4882a593Smuzhiyun 	}
562*4882a593Smuzhiyun 
563*4882a593Smuzhiyun 	/* Truncate large transfers to the fifo size */
564*4882a593Smuzhiyun 	if (transfer_size > ep0_endpoint->tx_packetSize)
565*4882a593Smuzhiyun 		transfer_size = ep0_endpoint->tx_packetSize;
566*4882a593Smuzhiyun 
567*4882a593Smuzhiyun 	write_fifo(0, transfer_size, &ep0_urb->buffer[ep0_endpoint->sent]);
568*4882a593Smuzhiyun 	ep0_endpoint->sent += transfer_size;
569*4882a593Smuzhiyun 
570*4882a593Smuzhiyun 	/* Done or more to send ? */
571*4882a593Smuzhiyun 	if (ep0_endpoint->sent >= ep0_urb->actual_length)
572*4882a593Smuzhiyun 		musb_ep0_tx_ready_and_last();
573*4882a593Smuzhiyun 	else
574*4882a593Smuzhiyun 		musb_ep0_tx_ready();
575*4882a593Smuzhiyun 
576*4882a593Smuzhiyun 	/* Wait a bit */
577*4882a593Smuzhiyun 	pm = 10;
578*4882a593Smuzhiyun 	for (p = 0; p < pm; p++) {
579*4882a593Smuzhiyun 		csr0 = readw(&musbr->ep[0].ep0.csr0);
580*4882a593Smuzhiyun 		if (!(csr0 & MUSB_CSR0_TXPKTRDY))
581*4882a593Smuzhiyun 			break;
582*4882a593Smuzhiyun 
583*4882a593Smuzhiyun 		/* Double the delay. */
584*4882a593Smuzhiyun 		udelay(1 << pm);
585*4882a593Smuzhiyun 	}
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	if ((ep0_endpoint->sent >= ep0_urb->actual_length) && (p < pm))
588*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
589*4882a593Smuzhiyun 
590*4882a593Smuzhiyun end:
591*4882a593Smuzhiyun 	return;
592*4882a593Smuzhiyun }
593*4882a593Smuzhiyun 
musb_peri_ep0(void)594*4882a593Smuzhiyun static void musb_peri_ep0(void)
595*4882a593Smuzhiyun {
596*4882a593Smuzhiyun 	u16 csr0;
597*4882a593Smuzhiyun 
598*4882a593Smuzhiyun 	if (SET_ADDRESS == ep0_state)
599*4882a593Smuzhiyun 		return;
600*4882a593Smuzhiyun 
601*4882a593Smuzhiyun 	csr0 = readw(&musbr->ep[0].ep0.csr0);
602*4882a593Smuzhiyun 
603*4882a593Smuzhiyun 	/* Error conditions */
604*4882a593Smuzhiyun 	if (MUSB_CSR0_P_SENTSTALL & csr0) {
605*4882a593Smuzhiyun 		csr0 &= ~MUSB_CSR0_P_SENTSTALL;
606*4882a593Smuzhiyun 		writew(csr0, &musbr->ep[0].ep0.csr0);
607*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
608*4882a593Smuzhiyun 	}
609*4882a593Smuzhiyun 	if (MUSB_CSR0_P_SETUPEND & csr0) {
610*4882a593Smuzhiyun 		csr0 |= MUSB_CSR0_P_SVDSETUPEND;
611*4882a593Smuzhiyun 		writew(csr0, &musbr->ep[0].ep0.csr0);
612*4882a593Smuzhiyun 		SET_EP0_STATE(IDLE);
613*4882a593Smuzhiyun 		if ((debug_setup) && (debug_level > 1))
614*4882a593Smuzhiyun 			serial_printf("WARN: %s SETUPEND\n",
615*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__);
616*4882a593Smuzhiyun 	}
617*4882a593Smuzhiyun 
618*4882a593Smuzhiyun 	/* Normal states */
619*4882a593Smuzhiyun 	if (IDLE == ep0_state)
620*4882a593Smuzhiyun 		musb_peri_ep0_idle();
621*4882a593Smuzhiyun 
622*4882a593Smuzhiyun 	if (TX == ep0_state)
623*4882a593Smuzhiyun 		musb_peri_ep0_tx();
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	if (RX == ep0_state)
626*4882a593Smuzhiyun 		musb_peri_ep0_rx();
627*4882a593Smuzhiyun }
628*4882a593Smuzhiyun 
musb_peri_rx_ep(unsigned int ep)629*4882a593Smuzhiyun static void musb_peri_rx_ep(unsigned int ep)
630*4882a593Smuzhiyun {
631*4882a593Smuzhiyun 	u16 peri_rxcount;
632*4882a593Smuzhiyun 	u8 peri_rxcsr = readw(&musbr->ep[ep].epN.rxcsr);
633*4882a593Smuzhiyun 
634*4882a593Smuzhiyun 	if (!(peri_rxcsr & MUSB_RXCSR_RXPKTRDY)) {
635*4882a593Smuzhiyun 		if (debug_level > 0)
636*4882a593Smuzhiyun 			serial_printf("ERROR : %s %d without MUSB_RXCSR_RXPKTRDY set\n",
637*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, ep);
638*4882a593Smuzhiyun 		return;
639*4882a593Smuzhiyun 	}
640*4882a593Smuzhiyun 
641*4882a593Smuzhiyun 	peri_rxcount = readw(&musbr->ep[ep].epN.rxcount);
642*4882a593Smuzhiyun 	if (peri_rxcount) {
643*4882a593Smuzhiyun 		struct usb_endpoint_instance *endpoint;
644*4882a593Smuzhiyun 		u32 length;
645*4882a593Smuzhiyun 		u8 *data;
646*4882a593Smuzhiyun 
647*4882a593Smuzhiyun 		endpoint = GET_ENDPOINT(udc_device, ep);
648*4882a593Smuzhiyun 		if (endpoint && endpoint->rcv_urb) {
649*4882a593Smuzhiyun 			struct urb *urb = endpoint->rcv_urb;
650*4882a593Smuzhiyun 			unsigned int remaining_space = urb->buffer_length -
651*4882a593Smuzhiyun 				urb->actual_length;
652*4882a593Smuzhiyun 
653*4882a593Smuzhiyun 			if (remaining_space) {
654*4882a593Smuzhiyun 				int urb_bad = 0; /* urb is good */
655*4882a593Smuzhiyun 
656*4882a593Smuzhiyun 				if (peri_rxcount > remaining_space)
657*4882a593Smuzhiyun 					length = remaining_space;
658*4882a593Smuzhiyun 				else
659*4882a593Smuzhiyun 					length = peri_rxcount;
660*4882a593Smuzhiyun 
661*4882a593Smuzhiyun 				data = (u8 *) urb->buffer_data;
662*4882a593Smuzhiyun 				data += urb->actual_length;
663*4882a593Smuzhiyun 
664*4882a593Smuzhiyun 				/* The common musb fifo reader */
665*4882a593Smuzhiyun 				read_fifo(ep, length, data);
666*4882a593Smuzhiyun 
667*4882a593Smuzhiyun 				musb_peri_rx_ack(ep);
668*4882a593Smuzhiyun 
669*4882a593Smuzhiyun 				/*
670*4882a593Smuzhiyun 				 * urb's actual_length is updated in
671*4882a593Smuzhiyun 				 * usbd_rcv_complete
672*4882a593Smuzhiyun 				 */
673*4882a593Smuzhiyun 				usbd_rcv_complete(endpoint, length, urb_bad);
674*4882a593Smuzhiyun 
675*4882a593Smuzhiyun 			} else {
676*4882a593Smuzhiyun 				if (debug_level > 0)
677*4882a593Smuzhiyun 					serial_printf("ERROR : %s %d no space "
678*4882a593Smuzhiyun 						      "in rcv buffer\n",
679*4882a593Smuzhiyun 						      __PRETTY_FUNCTION__, ep);
680*4882a593Smuzhiyun 			}
681*4882a593Smuzhiyun 		} else {
682*4882a593Smuzhiyun 			if (debug_level > 0)
683*4882a593Smuzhiyun 				serial_printf("ERROR : %s %d problem with "
684*4882a593Smuzhiyun 					      "endpoint\n",
685*4882a593Smuzhiyun 					      __PRETTY_FUNCTION__, ep);
686*4882a593Smuzhiyun 		}
687*4882a593Smuzhiyun 
688*4882a593Smuzhiyun 	} else {
689*4882a593Smuzhiyun 		if (debug_level > 0)
690*4882a593Smuzhiyun 			serial_printf("ERROR : %s %d with nothing to do\n",
691*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, ep);
692*4882a593Smuzhiyun 	}
693*4882a593Smuzhiyun }
694*4882a593Smuzhiyun 
musb_peri_rx(u16 intr)695*4882a593Smuzhiyun static void musb_peri_rx(u16 intr)
696*4882a593Smuzhiyun {
697*4882a593Smuzhiyun 	unsigned int ep;
698*4882a593Smuzhiyun 
699*4882a593Smuzhiyun 	/* Check for EP0 */
700*4882a593Smuzhiyun 	if (0x01 & intr)
701*4882a593Smuzhiyun 		musb_peri_ep0();
702*4882a593Smuzhiyun 
703*4882a593Smuzhiyun 	for (ep = 1; ep < 16; ep++) {
704*4882a593Smuzhiyun 		if ((1 << ep) & intr)
705*4882a593Smuzhiyun 			musb_peri_rx_ep(ep);
706*4882a593Smuzhiyun 	}
707*4882a593Smuzhiyun }
708*4882a593Smuzhiyun 
musb_peri_tx(u16 intr)709*4882a593Smuzhiyun static void musb_peri_tx(u16 intr)
710*4882a593Smuzhiyun {
711*4882a593Smuzhiyun 	/* Check for EP0 */
712*4882a593Smuzhiyun 	if (0x01 & intr)
713*4882a593Smuzhiyun 		musb_peri_ep0_tx();
714*4882a593Smuzhiyun 
715*4882a593Smuzhiyun 	/*
716*4882a593Smuzhiyun 	 * Use this in the future when handling epN tx
717*4882a593Smuzhiyun 	 *
718*4882a593Smuzhiyun 	 * u8 ep;
719*4882a593Smuzhiyun 	 *
720*4882a593Smuzhiyun 	 * for (ep = 1; ep < 16; ep++) {
721*4882a593Smuzhiyun 	 *	if ((1 << ep) & intr) {
722*4882a593Smuzhiyun 	 *		/ * handle tx for this endpoint * /
723*4882a593Smuzhiyun 	 *	}
724*4882a593Smuzhiyun 	 * }
725*4882a593Smuzhiyun 	 */
726*4882a593Smuzhiyun }
727*4882a593Smuzhiyun 
udc_irq(void)728*4882a593Smuzhiyun void udc_irq(void)
729*4882a593Smuzhiyun {
730*4882a593Smuzhiyun 	/* This is a high freq called function */
731*4882a593Smuzhiyun 	if (enabled) {
732*4882a593Smuzhiyun 		u8 intrusb;
733*4882a593Smuzhiyun 
734*4882a593Smuzhiyun 		intrusb = readb(&musbr->intrusb);
735*4882a593Smuzhiyun 
736*4882a593Smuzhiyun 		/*
737*4882a593Smuzhiyun 		 * See drivers/usb/gadget/mpc8xx_udc.c for
738*4882a593Smuzhiyun 		 * state diagram going from detached through
739*4882a593Smuzhiyun 		 * configuration.
740*4882a593Smuzhiyun 		 */
741*4882a593Smuzhiyun 		if (MUSB_INTR_RESUME & intrusb) {
742*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device,
743*4882a593Smuzhiyun 					      DEVICE_BUS_ACTIVITY, 0);
744*4882a593Smuzhiyun 			musb_peri_resume();
745*4882a593Smuzhiyun 		}
746*4882a593Smuzhiyun 
747*4882a593Smuzhiyun 		musb_peri_ep0();
748*4882a593Smuzhiyun 
749*4882a593Smuzhiyun 		if (MUSB_INTR_RESET & intrusb) {
750*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
751*4882a593Smuzhiyun 			musb_peri_reset();
752*4882a593Smuzhiyun 		}
753*4882a593Smuzhiyun 
754*4882a593Smuzhiyun 		if (MUSB_INTR_DISCONNECT & intrusb) {
755*4882a593Smuzhiyun 			/* cable unplugged from hub/host */
756*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device, DEVICE_RESET, 0);
757*4882a593Smuzhiyun 			musb_peri_reset();
758*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device, DEVICE_HUB_RESET, 0);
759*4882a593Smuzhiyun 		}
760*4882a593Smuzhiyun 
761*4882a593Smuzhiyun 		if (MUSB_INTR_SOF & intrusb) {
762*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device,
763*4882a593Smuzhiyun 					      DEVICE_BUS_ACTIVITY, 0);
764*4882a593Smuzhiyun 			musb_peri_resume();
765*4882a593Smuzhiyun 		}
766*4882a593Smuzhiyun 
767*4882a593Smuzhiyun 		if (MUSB_INTR_SUSPEND & intrusb) {
768*4882a593Smuzhiyun 			usbd_device_event_irq(udc_device,
769*4882a593Smuzhiyun 					      DEVICE_BUS_INACTIVE, 0);
770*4882a593Smuzhiyun 		}
771*4882a593Smuzhiyun 
772*4882a593Smuzhiyun 		if (ep0_state != SET_ADDRESS) {
773*4882a593Smuzhiyun 			u16 intrrx, intrtx;
774*4882a593Smuzhiyun 
775*4882a593Smuzhiyun 			intrrx = readw(&musbr->intrrx);
776*4882a593Smuzhiyun 			intrtx = readw(&musbr->intrtx);
777*4882a593Smuzhiyun 
778*4882a593Smuzhiyun 			if (intrrx)
779*4882a593Smuzhiyun 				musb_peri_rx(intrrx);
780*4882a593Smuzhiyun 
781*4882a593Smuzhiyun 			if (intrtx)
782*4882a593Smuzhiyun 				musb_peri_tx(intrtx);
783*4882a593Smuzhiyun 		} else {
784*4882a593Smuzhiyun 			if (MUSB_INTR_SOF & intrusb) {
785*4882a593Smuzhiyun 				u8 faddr;
786*4882a593Smuzhiyun 				faddr = readb(&musbr->faddr);
787*4882a593Smuzhiyun 				/*
788*4882a593Smuzhiyun 				 * Setting of the address can fail.
789*4882a593Smuzhiyun 				 * Normally it succeeds the second time.
790*4882a593Smuzhiyun 				 */
791*4882a593Smuzhiyun 				if (udc_device->address != faddr)
792*4882a593Smuzhiyun 					musb_peri_ep0_set_address();
793*4882a593Smuzhiyun 			}
794*4882a593Smuzhiyun 		}
795*4882a593Smuzhiyun 	}
796*4882a593Smuzhiyun }
797*4882a593Smuzhiyun 
udc_set_nak(int ep_num)798*4882a593Smuzhiyun void udc_set_nak(int ep_num)
799*4882a593Smuzhiyun {
800*4882a593Smuzhiyun 	/* noop */
801*4882a593Smuzhiyun }
802*4882a593Smuzhiyun 
udc_unset_nak(int ep_num)803*4882a593Smuzhiyun void udc_unset_nak(int ep_num)
804*4882a593Smuzhiyun {
805*4882a593Smuzhiyun 	/* noop */
806*4882a593Smuzhiyun }
807*4882a593Smuzhiyun 
udc_endpoint_write(struct usb_endpoint_instance * endpoint)808*4882a593Smuzhiyun int udc_endpoint_write(struct usb_endpoint_instance *endpoint)
809*4882a593Smuzhiyun {
810*4882a593Smuzhiyun 	int ret = 0;
811*4882a593Smuzhiyun 
812*4882a593Smuzhiyun 	/* Transmit only if the hardware is available */
813*4882a593Smuzhiyun 	if (endpoint->tx_urb && endpoint->state == 0) {
814*4882a593Smuzhiyun 		unsigned int ep = endpoint->endpoint_address &
815*4882a593Smuzhiyun 			USB_ENDPOINT_NUMBER_MASK;
816*4882a593Smuzhiyun 
817*4882a593Smuzhiyun 		u16 peri_txcsr = readw(&musbr->ep[ep].epN.txcsr);
818*4882a593Smuzhiyun 
819*4882a593Smuzhiyun 		/* Error conditions */
820*4882a593Smuzhiyun 		if (peri_txcsr & MUSB_TXCSR_P_UNDERRUN) {
821*4882a593Smuzhiyun 			peri_txcsr &= ~MUSB_TXCSR_P_UNDERRUN;
822*4882a593Smuzhiyun 			writew(peri_txcsr, &musbr->ep[ep].epN.txcsr);
823*4882a593Smuzhiyun 		}
824*4882a593Smuzhiyun 
825*4882a593Smuzhiyun 		if (debug_level > 1)
826*4882a593Smuzhiyun 			musb_print_txcsr(peri_txcsr);
827*4882a593Smuzhiyun 
828*4882a593Smuzhiyun 		/* Check if a packet is waiting to be sent */
829*4882a593Smuzhiyun 		if (!(peri_txcsr & MUSB_TXCSR_TXPKTRDY)) {
830*4882a593Smuzhiyun 			u32 length;
831*4882a593Smuzhiyun 			u8 *data;
832*4882a593Smuzhiyun 			struct urb *urb = endpoint->tx_urb;
833*4882a593Smuzhiyun 			unsigned int remaining_packet = urb->actual_length -
834*4882a593Smuzhiyun 				endpoint->sent;
835*4882a593Smuzhiyun 
836*4882a593Smuzhiyun 			if (endpoint->tx_packetSize < remaining_packet)
837*4882a593Smuzhiyun 				length = endpoint->tx_packetSize;
838*4882a593Smuzhiyun 			else
839*4882a593Smuzhiyun 				length = remaining_packet;
840*4882a593Smuzhiyun 
841*4882a593Smuzhiyun 			data = (u8 *) urb->buffer;
842*4882a593Smuzhiyun 			data += endpoint->sent;
843*4882a593Smuzhiyun 
844*4882a593Smuzhiyun 			/* common musb fifo function */
845*4882a593Smuzhiyun 			write_fifo(ep, length, data);
846*4882a593Smuzhiyun 
847*4882a593Smuzhiyun 			musb_peri_tx_ready(ep);
848*4882a593Smuzhiyun 
849*4882a593Smuzhiyun 			endpoint->last = length;
850*4882a593Smuzhiyun 			/* usbd_tx_complete will take care of updating 'sent' */
851*4882a593Smuzhiyun 			usbd_tx_complete(endpoint);
852*4882a593Smuzhiyun 		}
853*4882a593Smuzhiyun 	} else {
854*4882a593Smuzhiyun 		if (debug_level > 0)
855*4882a593Smuzhiyun 			serial_printf("ERROR : %s Problem with urb %p "
856*4882a593Smuzhiyun 				      "or ep state %d\n",
857*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__,
858*4882a593Smuzhiyun 				      endpoint->tx_urb, endpoint->state);
859*4882a593Smuzhiyun 	}
860*4882a593Smuzhiyun 
861*4882a593Smuzhiyun 	return ret;
862*4882a593Smuzhiyun }
863*4882a593Smuzhiyun 
udc_setup_ep(struct usb_device_instance * device,unsigned int id,struct usb_endpoint_instance * endpoint)864*4882a593Smuzhiyun void udc_setup_ep(struct usb_device_instance *device, unsigned int id,
865*4882a593Smuzhiyun 		  struct usb_endpoint_instance *endpoint)
866*4882a593Smuzhiyun {
867*4882a593Smuzhiyun 	if (0 == id) {
868*4882a593Smuzhiyun 		/* EP0 */
869*4882a593Smuzhiyun 		ep0_endpoint = endpoint;
870*4882a593Smuzhiyun 		ep0_endpoint->endpoint_address = 0xff;
871*4882a593Smuzhiyun 		ep0_urb = usbd_alloc_urb(device, endpoint);
872*4882a593Smuzhiyun 	} else if (MAX_ENDPOINT >= id) {
873*4882a593Smuzhiyun 		int ep_addr;
874*4882a593Smuzhiyun 
875*4882a593Smuzhiyun 		/* Check the direction */
876*4882a593Smuzhiyun 		ep_addr = endpoint->endpoint_address;
877*4882a593Smuzhiyun 		if (USB_DIR_IN == (ep_addr & USB_ENDPOINT_DIR_MASK)) {
878*4882a593Smuzhiyun 			/* IN */
879*4882a593Smuzhiyun 			epinfo[(id * 2) + 1].epsize = endpoint->tx_packetSize;
880*4882a593Smuzhiyun 		} else {
881*4882a593Smuzhiyun 			/* OUT */
882*4882a593Smuzhiyun 			epinfo[id * 2].epsize = endpoint->rcv_packetSize;
883*4882a593Smuzhiyun 		}
884*4882a593Smuzhiyun 
885*4882a593Smuzhiyun 		musb_configure_ep(&epinfo[0], ARRAY_SIZE(epinfo));
886*4882a593Smuzhiyun 	} else {
887*4882a593Smuzhiyun 		if (debug_level > 0)
888*4882a593Smuzhiyun 			serial_printf("ERROR : %s endpoint request %d "
889*4882a593Smuzhiyun 				      "exceeds maximum %d\n",
890*4882a593Smuzhiyun 				      __PRETTY_FUNCTION__, id, MAX_ENDPOINT);
891*4882a593Smuzhiyun 	}
892*4882a593Smuzhiyun }
893*4882a593Smuzhiyun 
udc_connect(void)894*4882a593Smuzhiyun void udc_connect(void)
895*4882a593Smuzhiyun {
896*4882a593Smuzhiyun 	/* noop */
897*4882a593Smuzhiyun }
898*4882a593Smuzhiyun 
udc_disconnect(void)899*4882a593Smuzhiyun void udc_disconnect(void)
900*4882a593Smuzhiyun {
901*4882a593Smuzhiyun 	/* noop */
902*4882a593Smuzhiyun }
903*4882a593Smuzhiyun 
udc_enable(struct usb_device_instance * device)904*4882a593Smuzhiyun void udc_enable(struct usb_device_instance *device)
905*4882a593Smuzhiyun {
906*4882a593Smuzhiyun 	/* Save the device structure pointer */
907*4882a593Smuzhiyun 	udc_device = device;
908*4882a593Smuzhiyun 
909*4882a593Smuzhiyun 	enabled = 1;
910*4882a593Smuzhiyun }
911*4882a593Smuzhiyun 
udc_disable(void)912*4882a593Smuzhiyun void udc_disable(void)
913*4882a593Smuzhiyun {
914*4882a593Smuzhiyun 	enabled = 0;
915*4882a593Smuzhiyun }
916*4882a593Smuzhiyun 
udc_startup_events(struct usb_device_instance * device)917*4882a593Smuzhiyun void udc_startup_events(struct usb_device_instance *device)
918*4882a593Smuzhiyun {
919*4882a593Smuzhiyun 	/* The DEVICE_INIT event puts the USB device in the state STATE_INIT. */
920*4882a593Smuzhiyun 	usbd_device_event_irq(device, DEVICE_INIT, 0);
921*4882a593Smuzhiyun 
922*4882a593Smuzhiyun 	/*
923*4882a593Smuzhiyun 	 * The DEVICE_CREATE event puts the USB device in the state
924*4882a593Smuzhiyun 	 * STATE_ATTACHED.
925*4882a593Smuzhiyun 	 */
926*4882a593Smuzhiyun 	usbd_device_event_irq(device, DEVICE_CREATE, 0);
927*4882a593Smuzhiyun 
928*4882a593Smuzhiyun 	/* Resets the address to 0 */
929*4882a593Smuzhiyun 	usbd_device_event_irq(device, DEVICE_RESET, 0);
930*4882a593Smuzhiyun 
931*4882a593Smuzhiyun 	udc_enable(device);
932*4882a593Smuzhiyun }
933*4882a593Smuzhiyun 
udc_init(void)934*4882a593Smuzhiyun int udc_init(void)
935*4882a593Smuzhiyun {
936*4882a593Smuzhiyun 	int ret;
937*4882a593Smuzhiyun 	int ep_loop;
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun 	ret = musb_platform_init();
940*4882a593Smuzhiyun 	if (ret < 0)
941*4882a593Smuzhiyun 		goto end;
942*4882a593Smuzhiyun 
943*4882a593Smuzhiyun 	/* Configure all the endpoint FIFO's and start usb controller */
944*4882a593Smuzhiyun 	musbr = musb_cfg.regs;
945*4882a593Smuzhiyun 
946*4882a593Smuzhiyun 	/* Initialize the endpoints */
947*4882a593Smuzhiyun 	for (ep_loop = 0; ep_loop <= MAX_ENDPOINT * 2; ep_loop++) {
948*4882a593Smuzhiyun 		epinfo[ep_loop].epnum = (ep_loop / 2) + 1;
949*4882a593Smuzhiyun 		epinfo[ep_loop].epdir = ep_loop % 2; /* OUT, IN */
950*4882a593Smuzhiyun 		epinfo[ep_loop].epsize = 0;
951*4882a593Smuzhiyun 	}
952*4882a593Smuzhiyun 
953*4882a593Smuzhiyun 	musb_peri_softconnect();
954*4882a593Smuzhiyun 
955*4882a593Smuzhiyun 	ret = 0;
956*4882a593Smuzhiyun end:
957*4882a593Smuzhiyun 
958*4882a593Smuzhiyun 	return ret;
959*4882a593Smuzhiyun }
960