summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-ti-staging/0001-Revert-usb-musb-musb_cppi41-Revert-the-Advisory-1.0..patch
blob: dcb3322617a9bf6cdff7073c64bb77f23a393777 (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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
From f576e148cd15f10224e4ce13b6773717682f9a5a Mon Sep 17 00:00:00 2001
From: Chase Maupin <Chase.Maupin@ti.com>
Date: Fri, 21 Feb 2014 09:05:48 -0600
Subject: [PATCH 1/4] Revert "usb: musb: musb_cppi41: Revert the Advisory 1.0.13 workaround"

This reverts commit c424ef3e2beb89488e7e597446b4c6bc8f1852c5.
---
 drivers/usb/musb/musb_cppi41.c |   96 +++++++++++++++++++++++++++++++++-------
 1 files changed, 79 insertions(+), 17 deletions(-)

diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index d02facc..01df8f9 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -31,6 +31,7 @@ struct cppi41_dma_channel {
 	u8 port_num;
 	u8 is_tx;
 	u8 is_allocated;
+	u8 usb_toggle;
 
 	dma_addr_t buf_addr;
 	u32 total_len;
@@ -55,6 +56,50 @@ struct cppi41_dma_controller {
 	u32 auto_req;
 };
 
+static void save_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+	u16 csr;
+	u8 toggle;
+
+	if (cppi41_channel->is_tx)
+		return;
+	if (!is_host_active(cppi41_channel->controller->musb))
+		return;
+
+	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+	cppi41_channel->usb_toggle = toggle;
+}
+
+static void update_rx_toggle(struct cppi41_dma_channel *cppi41_channel)
+{
+	u16 csr;
+	u8 toggle;
+
+	if (cppi41_channel->is_tx)
+		return;
+	if (!is_host_active(cppi41_channel->controller->musb))
+		return;
+
+	csr = musb_readw(cppi41_channel->hw_ep->regs, MUSB_RXCSR);
+	toggle = csr & MUSB_RXCSR_H_DATATOGGLE ? 1 : 0;
+
+	/*
+	 * AM335x Advisory 1.0.13: Due to internal synchronisation error the
+	 * data toggle may reset from DATA1 to DATA0 during receiving data from
+	 * more than one endpoint.
+	 */
+	if (!toggle && toggle == cppi41_channel->usb_toggle) {
+		csr |= MUSB_RXCSR_H_DATATOGGLE | MUSB_RXCSR_H_WR_DATATOGGLE;
+		musb_writew(cppi41_channel->hw_ep->regs, MUSB_RXCSR, csr);
+		dev_dbg(cppi41_channel->controller->musb->controller,
+				"Restoring DATA1 toggle.\n");
+	}
+
+	cppi41_channel->usb_toggle = toggle;
+}
+
 static bool musb_is_tx_fifo_empty(struct musb_hw_ep *hw_ep)
 {
 	u8		epnum = hw_ep->epnum;
@@ -217,6 +262,8 @@ static void cppi41_dma_callback(void *private_data)
 		hw_ep->epnum, cppi41_channel->transferred,
 		cppi41_channel->total_len);
 
+	update_rx_toggle(cppi41_channel);
+
 	if (cppi41_channel->transferred == cppi41_channel->total_len ||
 			transferred < cppi41_channel->packet_sz)
 		cppi41_channel->prog_len = 0;
@@ -347,6 +394,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
 	struct dma_async_tx_descriptor *dma_desc;
 	enum dma_transfer_direction direction;
 	struct musb *musb = cppi41_channel->controller->musb;
+	unsigned use_gen_rndis = 0;
 
 	dev_dbg(musb->controller,
 		"configure ep%d/%x packet_sz=%d, mode=%d, dma_addr=0x%llx, len=%d is_tx=%d\n",
@@ -359,26 +407,39 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
 	cppi41_channel->transferred = 0;
 	cppi41_channel->packet_sz = packet_sz;
 
-	/* RNDIS mode */
-	if (len > packet_sz) {
-		musb_writel(musb->ctrl_base,
-			    RNDIS_REG(cppi41_channel->port_num), len);
-		/* gen rndis */
-		cppi41_set_dma_mode(cppi41_channel,
-				    EP_MODE_DMA_GEN_RNDIS);
-
-		/* auto req */
-		cppi41_set_autoreq_mode(cppi41_channel,
+	/*
+	 * Due to AM335x' Advisory 1.0.13 we are not allowed to transfer more
+	 * than max packet size at a time.
+	 */
+	if (cppi41_channel->is_tx)
+		use_gen_rndis = 1;
+
+	if (use_gen_rndis) {
+		/* RNDIS mode */
+		if (len > packet_sz) {
+			musb_writel(musb->ctrl_base,
+				RNDIS_REG(cppi41_channel->port_num), len);
+			/* gen rndis */
+			cppi41_set_dma_mode(cppi41_channel,
+					EP_MODE_DMA_GEN_RNDIS);
+
+			/* auto req */
+			cppi41_set_autoreq_mode(cppi41_channel,
 					EP_MODE_AUTOREG_ALL_NEOP);
-	} else {
-		musb_writel(musb->ctrl_base,
-			    RNDIS_REG(cppi41_channel->port_num), 0);
-		cppi41_set_dma_mode(cppi41_channel,
-				    EP_MODE_DMA_TRANSPARENT);
-		cppi41_set_autoreq_mode(cppi41_channel,
+		} else {
+			musb_writel(musb->ctrl_base,
+					RNDIS_REG(cppi41_channel->port_num), 0);
+			cppi41_set_dma_mode(cppi41_channel,
+					EP_MODE_DMA_TRANSPARENT);
+			cppi41_set_autoreq_mode(cppi41_channel,
 					EP_MODE_AUTOREG_NONE);
+		}
+	} else {
+		/* fallback mode */
+		cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
+		cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+		len = min_t(u32, packet_sz, len);
 	}
-
 	cppi41_channel->prog_len = len;
 	direction = cppi41_channel->is_tx ? DMA_MEM_TO_DEV : DMA_DEV_TO_MEM;
 	dma_desc = dmaengine_prep_slave_single(dc, dma_addr, len, direction,
@@ -390,6 +451,7 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
 	dma_desc->callback_param = channel;
 	cppi41_channel->cookie = dma_desc->tx_submit(dma_desc);
 
+	save_rx_toggle(cppi41_channel);
 	dma_async_issue_pending(dc);
 	return true;
 }
-- 
1.7.0.4