summaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.35/rx1950/0002-s3c2410_udc-2440-dual-packet-workaround.patch
blob: bd9a8b12e7fd210ae5b13f34d03ac7a2fb8ffa93 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
From fc47d51f262ec6d0a4601fe37ac6478e30d68060 Mon Sep 17 00:00:00 2001
From: Vasily Khoruzhick <anarsoul@gmail.com>
Date: Thu, 24 Sep 2009 22:17:47 +0300
Subject: [PATCH 02/20] s3c2410_udc: 2440 dual packet workaround

This is a patch that seems to make the USB hangs on the S3C2440 go away.
At least a good amount of ping torture didn't make them come back so far.

The issue is that, if there are several back-to-back packets, sometimes no
interrupt is generated for one of them. This seems to be caused by the
mysterious dual packet mode, which the USB hardware enters automatically
if the endpoint size is half that of the FIFO. (On the 2440, this is the
normal situation for bulk data endpoints.)

There is also a timing factor in this. I think what happens is that the USB
hardware automatically sends an acknowledgement if there is only one packet
in the FIFO (the FIFO has space for two). If another packet arrives before
the host has retrieved and acknowledged the previous one, no interrupt is
generated for that second one.

However, there may be an indication. There is one undocumented bit (none
of the 244x manuals document it), OUT_CRS1_REG[1], that seems to be set
suspiciously often when this condition occurs. There is also
CLR_DATA_TOGGLE, OUT_CRS1_REG[7], which may have a function related to
this. (The Samsung manual is rather terse on that, as usual.)

This needs to be examined further. For now, the patch seems to do the
trick.

Signed-off-by: Vasily Khoruzhick <anarsoul@gmail.com>
---
 drivers/usb/gadget/s3c2410_udc.c |   16 +++++++++++++++-
 1 files changed, 15 insertions(+), 1 deletions(-)

diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index ea2b3c7..fed323c 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -902,7 +902,7 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
 	int pwr_reg;
 	int ep0csr;
 	int i;
-	u32 idx;
+	u32 idx, idx2;
 	unsigned long flags;
 
 	spin_lock_irqsave(&dev->lock, flags);
@@ -1017,6 +1017,20 @@ static irqreturn_t s3c2410_udc_irq(int dummy, void *_dev)
 		}
 	}
 
+	/* what else causes this interrupt? a receive! who is it? */
+	if (!usb_status && !usbd_status && !pwr_reg && !ep0csr) {
+		for (i = 1; i < S3C2410_ENDPOINTS; i++) {
+			idx2 = udc_read(S3C2410_UDC_INDEX_REG);
+			udc_write(i, S3C2410_UDC_INDEX_REG);
+
+			if (udc_read(S3C2410_UDC_OUT_CSR1_REG) & 0x1)
+				s3c2410_udc_handle_ep(&dev->ep[i]);
+
+			/* restore index */
+			udc_write(idx2, S3C2410_UDC_INDEX_REG);
+		}
+	}
+
 	dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", IRQ_USBD);
 
 	/* Restore old index */
-- 
1.7.2.2