summaryrefslogtreecommitdiffstats
path: root/recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch
diff options
context:
space:
mode:
Diffstat (limited to 'recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch')
-rw-r--r--recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch425
1 files changed, 425 insertions, 0 deletions
diff --git a/recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch b/recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch
new file mode 100644
index 00000000..761f4d60
--- /dev/null
+++ b/recipes-kernel/linux/linux-ti33x-psp-3.2/psp/0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch
@@ -0,0 +1,425 @@
1From a4d99c3c1e01b91b69c6939ba3ee708611869402 Mon Sep 17 00:00:00 2001
2From: Ajay Kumar Gupta <ajay.gupta@ti.com>
3Date: Wed, 23 May 2012 15:25:32 +0530
4Subject: [PATCH 10/18] usb: musb: cppi41: enable txfifo empty interrupt logic
5
6Fixes the txdma early completion issue as the TxFIFO empty interrupt
7logic generates an interrupt when last byte from TxFIFO is
8transmitted out.
9
10The application issues fixed are -
111) The isochronous gap issue seen due to txdma early completion and
12 thus a delay caused in scheduling of txdma workthread which polls
13 for txfifo empty status.
14
152) The workthread is rescheduled once again when txfifo is empty to
16 make sure any miss of transfer of the data in internal cppififo.
17
183) For non-isochronous tx request uses workthread to poll for txfifo
19 empty status if there is possiblity of data in internal cppififo
20 other wise the request is completed directly in the tx-dma isr
21 function.
22
23Signed-off-by: Ravi B <ravibabu@ti.com>
24---
25 drivers/usb/musb/cppi41_dma.c | 101 ++++++++++++++++++++++++++++++++++++++--
26 drivers/usb/musb/cppi41_dma.h | 7 +++
27 drivers/usb/musb/musb_core.h | 16 ++++++
28 drivers/usb/musb/musb_gadget.c | 1 +
29 drivers/usb/musb/musb_host.c | 1 +
30 drivers/usb/musb/ti81xx.c | 51 ++++++++++++++++++++-
31 drivers/usb/musb/ti81xx.h | 3 +
32 7 files changed, 174 insertions(+), 6 deletions(-)
33
34diff --git a/drivers/usb/musb/cppi41_dma.c b/drivers/usb/musb/cppi41_dma.c
35index 4761acd..3665d0f 100644
36--- a/drivers/usb/musb/cppi41_dma.c
37+++ b/drivers/usb/musb/cppi41_dma.c
38@@ -101,6 +101,9 @@ struct cppi41_channel {
39 u8 inf_mode;
40 u8 tx_complete;
41 u8 hb_mult;
42+ u8 txf_complete;
43+ u8 txfifo_intr_enable;
44+ u8 count;
45 };
46
47 /**
48@@ -132,6 +135,7 @@ struct cppi41 {
49 u32 teardown_reg_offs; /* USB_TEARDOWN_REG offset */
50 u32 bd_size;
51 u8 inf_mode;
52+ u8 txfifo_intr_enable; /* txfifo empty interrupt logic */
53 };
54
55 struct usb_cppi41_info usb_cppi41_info[2];
56@@ -573,6 +577,9 @@ static unsigned cppi41_next_tx_segment(struct cppi41_channel *tx_ch)
57 u16 q_mgr = cppi_info->q_mgr;
58 u16 tx_comp_q = cppi_info->tx_comp_q[tx_ch->ch_num];
59 u8 en_bd_intr = cppi->en_bd_intr;
60+ u8 is_isoc = 0;
61+ struct musb_hw_ep *hw_ep = cppi->musb->endpoints + tx_ch->end_pt->epnum;
62+ int xfer_type = hw_ep->xfer_type;
63
64 /*
65 * Tx can use the generic RNDIS mode where we can probably fit this
66@@ -599,6 +606,12 @@ static unsigned cppi41_next_tx_segment(struct cppi41_channel *tx_ch)
67 tx_ch->ch_num, tx_ch->dma_mode ? "accelerated" : "transparent",
68 pkt_size, num_pds, tx_ch->start_addr + tx_ch->curr_offset, length);
69
70+ if (xfer_type == USB_ENDPOINT_XFER_ISOC)
71+ is_isoc = 1;
72+
73+ if (is_isoc && cppi->txfifo_intr_enable && (length <= tx_ch->pkt_size))
74+ tx_ch->txfifo_intr_enable = 1;
75+
76 for (n = 0; n < num_pds; n++) {
77 struct cppi41_host_pkt_desc *hw_desc;
78
79@@ -640,6 +653,14 @@ static unsigned cppi41_next_tx_segment(struct cppi41_channel *tx_ch)
80 dev_dbg(musb->controller, "TX PD %p: buf %08x, len %08x, pkt info %08x\n", curr_pd,
81 hw_desc->buf_ptr, hw_desc->buf_len, hw_desc->pkt_info);
82
83+ /* enable tx fifo empty interrupt */
84+ if (tx_ch->txfifo_intr_enable) {
85+ dev_dbg(musb->controller, "txs(%p %d) enable txFintr\n",
86+ curr_pd, hw_desc->orig_buf_len &
87+ ~CPPI41_PKT_INTR_FLAG);
88+ txfifoempty_int_enable(cppi->musb, curr_pd->ep_num);
89+ }
90+
91 cppi41_queue_push(&tx_ch->queue_obj, curr_pd->dma_addr,
92 USB_CPPI41_DESC_ALIGN, pkt_size);
93 }
94@@ -1211,6 +1232,8 @@ static int cppi41_channel_abort(struct dma_channel *channel)
95 csr &= ~MUSB_TXCSR_DMAENAB;
96 musb_writew(epio, MUSB_TXCSR, csr);
97
98+ cppi_ch->tx_complete = 0;
99+ cppi_ch->txf_complete = 0;
100 /* Tear down Tx DMA channel */
101 usb_tx_ch_teardown(cppi_ch);
102
103@@ -1224,7 +1247,6 @@ static int cppi41_channel_abort(struct dma_channel *channel)
104 csr |= MUSB_TXCSR_FLUSHFIFO | MUSB_TXCSR_H_WZC_BITS;
105 musb_writew(epio, MUSB_TXCSR, csr);
106 musb_writew(epio, MUSB_TXCSR, csr);
107- cppi_ch->tx_complete = 0;
108 } else { /* Rx */
109 dprintk("Rx channel teardown, cppi_ch = %p\n", cppi_ch);
110
111@@ -1331,16 +1353,23 @@ void txdma_completion_work(struct work_struct *data)
112 */
113 if (!tx_ch->end_pt) {
114 tx_ch->tx_complete = 0;
115+ tx_ch->count = 0;
116 continue;
117 }
118
119 epio = tx_ch->end_pt->regs;
120 csr = musb_readw(epio, MUSB_TXCSR);
121
122- if (csr & (MUSB_TXCSR_TXPKTRDY |
123- MUSB_TXCSR_FIFONOTEMPTY)) {
124+ if (!tx_ch->txfifo_intr_enable &&
125+ (csr & (MUSB_TXCSR_TXPKTRDY |
126+ MUSB_TXCSR_FIFONOTEMPTY))) {
127 resched = 1;
128 } else {
129+ if (tx_ch->count > 0) {
130+ tx_ch->count--;
131+ resched = 1;
132+ continue;
133+ }
134 tx_ch->channel.status =
135 MUSB_DMA_STATUS_FREE;
136 tx_ch->tx_complete = 0;
137@@ -1363,6 +1392,38 @@ void txdma_completion_work(struct work_struct *data)
138
139 }
140
141+void cppi41_handle_txfifo_intr(struct musb *musb, u16 usbintr)
142+{
143+ struct cppi41 *cppi;
144+ struct cppi41_channel *tx_ch;
145+ int index;
146+
147+ cppi = container_of(musb->dma_controller, struct cppi41, controller);
148+ for (index = 0; (index < USB_CPPI41_NUM_CH) && usbintr; index++) {
149+ if (usbintr & 1) {
150+ tx_ch = &cppi->tx_cppi_ch[index];
151+ if (tx_ch->txf_complete) {
152+ /* disable txfifo empty interupt */
153+ txfifoempty_int_disable(musb, index+1);
154+ tx_ch->txf_complete = 0;
155+ if (!tx_ch->txfifo_intr_enable)
156+ dev_dbg(musb->controller,
157+ "Bug, wrong TxFintr ep%d\n", index+1);
158+ tx_ch->txfifo_intr_enable = 0;
159+
160+ tx_ch->channel.status =
161+ MUSB_DMA_STATUS_FREE;
162+
163+ dev_dbg(musb->controller,
164+ "txc: givback ep%d\n", index+1);
165+ musb_dma_completion(musb, index+1, 1);
166+ }
167+ }
168+ usbintr = usbintr >> 1;
169+ }
170+}
171+EXPORT_SYMBOL(cppi41_handle_txfifo_intr);
172+
173 /**
174 * cppi41_dma_controller_create -
175 * instantiate an object representing DMA controller.
176@@ -1386,6 +1447,7 @@ cppi41_dma_controller_create(struct musb *musb, void __iomem *mregs)
177 cppi->controller.channel_abort = cppi41_channel_abort;
178 cppi->cppi_info = (struct usb_cppi41_info *)&usb_cppi41_info[musb->id];;
179 cppi->en_bd_intr = cppi->cppi_info->bd_intr_ctrl;
180+ cppi->txfifo_intr_enable = musb->txfifo_intr_enable;
181 INIT_WORK(&cppi->txdma_work, txdma_completion_work);
182
183 /*
184@@ -1472,6 +1534,9 @@ static void usb_process_tx_queue(struct cppi41 *cppi, unsigned index)
185 (tx_ch->transfer_mode && !tx_ch->zlp_queued))
186 cppi41_next_tx_segment(tx_ch);
187 else if (tx_ch->channel.actual_len >= tx_ch->length) {
188+ void __iomem *epio;
189+ u16 csr;
190+
191 /*
192 * We get Tx DMA completion interrupt even when
193 * data is still in FIFO and not moved out to
194@@ -1480,8 +1545,34 @@ static void usb_process_tx_queue(struct cppi41 *cppi, unsigned index)
195 * USB functionality. So far, we have obsered
196 * failure with iperf.
197 */
198- tx_ch->tx_complete = 1;
199- schedule_work(&cppi->txdma_work);
200+ /* wait for tx fifo empty completion interrupt
201+ * if enabled other wise use the workthread
202+ * to poll fifo empty status
203+ */
204+ epio = tx_ch->end_pt->regs;
205+ csr = musb_readw(epio, MUSB_TXCSR);
206+
207+ if (tx_ch->txfifo_intr_enable) {
208+ tx_ch->txf_complete = 1;
209+ dev_dbg(musb->controller,
210+ "wait for TxF-EmptyIntr ep%d\n", ep_num);
211+ } else {
212+ int residue;
213+
214+ residue = tx_ch->channel.actual_len %
215+ tx_ch->pkt_size;
216+
217+ if (tx_ch->pkt_size > 128 && !residue) {
218+ tx_ch->channel.status =
219+ MUSB_DMA_STATUS_FREE;
220+ musb_dma_completion(cppi->musb,
221+ ep_num, 1);
222+ } else {
223+ tx_ch->tx_complete = 1;
224+ tx_ch->count = 1;
225+ schedule_work(&cppi->txdma_work);
226+ }
227+ }
228 }
229 }
230 }
231diff --git a/drivers/usb/musb/cppi41_dma.h b/drivers/usb/musb/cppi41_dma.h
232index bedf3bb..053a135 100644
233--- a/drivers/usb/musb/cppi41_dma.h
234+++ b/drivers/usb/musb/cppi41_dma.h
235@@ -58,4 +58,11 @@ extern struct usb_cppi41_info usb_cppi41_info[];
236 */
237 void cppi41_completion(struct musb *musb, u32 rx, u32 tx);
238
239+/**
240+ * cppi41_handle_txfifo_intr - Handles tx fifo empty interupts
241+ * @musb: the controller
242+ */
243+void cppi41_handle_txfifo_intr(struct musb *musb, u16 usbintr);
244+void txfifoempty_int_enable(struct musb *musb, u8 ep_num);
245+void txfifoempty_int_disable(struct musb *musb, u8 ep_num);
246 #endif /* _CPPI41_DMA_H_ */
247diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
248index 184c043..40f02ae 100644
249--- a/drivers/usb/musb/musb_core.h
250+++ b/drivers/usb/musb/musb_core.h
251@@ -228,6 +228,8 @@ struct musb_platform_ops {
252 void __iomem *);
253 void (*dma_controller_destroy)(struct dma_controller *);
254 int (*simulate_babble_intr)(struct musb *musb);
255+ void (*txfifoempty_intr_enable)(struct musb *musb, u8 ep_num);
256+ void (*txfifoempty_intr_disable)(struct musb *musb, u8 ep_num);
257 };
258
259 /*
260@@ -278,6 +280,7 @@ struct musb_hw_ep {
261 struct musb_ep ep_out; /* RX */
262
263 u8 prev_toggle; /* Rx */
264+ u8 xfer_type;
265 };
266
267 static inline struct musb_request *next_in_request(struct musb_hw_ep *hw_ep)
268@@ -472,6 +475,7 @@ struct musb {
269 u64 *orig_dma_mask;
270 #endif
271 short fifo_mode;
272+ u8 txfifo_intr_enable;
273 };
274
275 static inline struct musb *gadget_to_musb(struct usb_gadget *g)
276@@ -562,6 +566,18 @@ extern irqreturn_t musb_interrupt(struct musb *);
277
278 extern void musb_hnp_stop(struct musb *musb);
279
280+static inline void txfifoempty_int_enable(struct musb *musb, u8 ep_num)
281+{
282+ if (musb->ops->txfifoempty_intr_enable)
283+ musb->ops->txfifoempty_intr_enable(musb, ep_num);
284+}
285+
286+static inline void txfifoempty_int_disable(struct musb *musb, u8 ep_num)
287+{
288+ if (musb->ops->txfifoempty_intr_disable)
289+ musb->ops->txfifoempty_intr_disable(musb, ep_num);
290+}
291+
292 static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
293 {
294 if (musb->ops->set_vbus)
295diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
296index 305d843..47349ca 100644
297--- a/drivers/usb/musb/musb_gadget.c
298+++ b/drivers/usb/musb/musb_gadget.c
299@@ -1020,6 +1020,7 @@ static int musb_gadget_enable(struct usb_ep *ep,
300 goto fail;
301 }
302 musb_ep->type = usb_endpoint_type(desc);
303+ hw_ep->xfer_type = musb_ep->type;
304
305 /* check direction and (later) maxpacket size against endpoint */
306 if (usb_endpoint_num(desc) != epnum)
307diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
308index 80d83bd..c3629bd 100644
309--- a/drivers/usb/musb/musb_host.c
310+++ b/drivers/usb/musb/musb_host.c
311@@ -246,6 +246,7 @@ musb_start_urb(struct musb *musb, int is_in, struct musb_qh *qh)
312 /* initialize software qh state */
313 qh->offset = 0;
314 qh->segsize = 0;
315+ hw_ep->xfer_type = qh->type;
316
317 /* gather right source of data */
318 switch (qh->type) {
319diff --git a/drivers/usb/musb/ti81xx.c b/drivers/usb/musb/ti81xx.c
320index f7b2f62..7e21c25 100644
321--- a/drivers/usb/musb/ti81xx.c
322+++ b/drivers/usb/musb/ti81xx.c
323@@ -568,7 +568,6 @@ int cppi41_enable_sched_rx(void)
324 cppi41_dma_sched_tbl_init(0, 0, dma_sched_table, 30);
325 return 0;
326 }
327-#endif /* CONFIG_USB_TI_CPPI41_DMA */
328
329 /*
330 * Because we don't set CTRL.UINT, it's "important" to:
331@@ -577,6 +576,33 @@ int cppi41_enable_sched_rx(void)
332 * - use INTSET/INTCLR instead.
333 */
334
335+void txfifoempty_intr_enable(struct musb *musb, u8 ep_num)
336+{
337+ void __iomem *reg_base = musb->ctrl_base;
338+ u32 coremask;
339+
340+ if (musb->txfifo_intr_enable) {
341+ coremask = musb_readl(reg_base, USB_CORE_INTR_SET_REG);
342+ coremask |= (1 << (ep_num + 16));
343+ musb_writel(reg_base, USB_CORE_INTR_SET_REG, coremask);
344+ dev_dbg(musb->controller, "enable txF intr ep%d coremask %x\n",
345+ ep_num, coremask);
346+ }
347+}
348+
349+void txfifoempty_intr_disable(struct musb *musb, u8 ep_num)
350+{
351+ void __iomem *reg_base = musb->ctrl_base;
352+ u32 coremask;
353+
354+ if (musb->txfifo_intr_enable) {
355+ coremask = (1 << (ep_num + 16));
356+ musb_writel(reg_base, USB_CORE_INTR_CLEAR_REG, coremask);
357+ }
358+}
359+
360+#endif /* CONFIG_USB_TI_CPPI41_DMA */
361+
362 /**
363 * ti81xx_musb_enable - enable interrupts
364 */
365@@ -889,6 +915,18 @@ static irqreturn_t ti81xx_interrupt(int irq, void *hci)
366 musb->int_usb = (usbintr & USB_INTR_USB_MASK) >> USB_INTR_USB_SHIFT;
367
368 dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", usbintr, epintr);
369+
370+ if (musb->txfifo_intr_enable && (usbintr & USB_INTR_TXFIFO_MASK)) {
371+#ifdef CONFIG_USB_TI_CPPI41_DMA
372+ dev_dbg(musb->controller,
373+ "TxFIFOIntr %x\n", usbintr >> USB_INTR_TXFIFO_EMPTY);
374+ cppi41_handle_txfifo_intr(musb,
375+ usbintr >> USB_INTR_TXFIFO_EMPTY);
376+ ret = IRQ_HANDLED;
377+#endif
378+ }
379+ usbintr &= ~USB_INTR_TXFIFO_MASK;
380+
381 /*
382 * DRVVBUS IRQs are the only proxy we have (a very poor one!) for
383 * AM3517's missing ID change IRQ. We need an ID change IRQ to
384@@ -1108,6 +1146,13 @@ int ti81xx_musb_init(struct musb *musb)
385 /* set musb controller to host mode */
386 musb_platform_set_mode(musb, mode);
387
388+#ifdef CONFIG_USB_TI_CPPI41_DMA
389+ musb->txfifo_intr_enable = 1;
390+ if (musb->txfifo_intr_enable)
391+ printk(KERN_DEBUG "TxFifo Empty intr enabled\n");
392+ else
393+ printk(KERN_DEBUG "TxFifo Empty intr disabled\n");
394+#endif
395 /* enable babble workaround */
396 INIT_WORK(&musb->work, evm_deferred_musb_restart);
397 musb->enable_babble_work = 0;
398@@ -1184,6 +1229,10 @@ static struct musb_platform_ops ti81xx_ops = {
399 .dma_controller_create = cppi41_dma_controller_create,
400 .dma_controller_destroy = cppi41_dma_controller_destroy,
401 .simulate_babble_intr = musb_simulate_babble,
402+#ifdef CONFIG_USB_TI_CPPI41_DMA
403+ .txfifoempty_intr_enable = txfifoempty_intr_enable,
404+ .txfifoempty_intr_disable = txfifoempty_intr_disable,
405+#endif
406 };
407
408 static void __devexit ti81xx_delete_musb_pdev(struct ti81xx_glue *glue, u8 id)
409diff --git a/drivers/usb/musb/ti81xx.h b/drivers/usb/musb/ti81xx.h
410index e0dbd3e..d173b55 100644
411--- a/drivers/usb/musb/ti81xx.h
412+++ b/drivers/usb/musb/ti81xx.h
413@@ -125,6 +125,9 @@
414 /* USB interrupt register bits */
415 #define USB_INTR_USB_SHIFT 0
416 #define USB_INTR_USB_MASK (0x1ff << USB_INTR_USB_SHIFT) /* 8 Mentor */
417+#define USB_INTR_TXFIFO_MASK (0xffff << 16)
418+#define USB_INTR_TXFIFO_EMPTY 17
419+
420 /* interrupts and DRVVBUS interrupt */
421 #define USB_INTR_DRVVBUS 0x100
422 #define USB_INTR_RX_SHIFT 16
423--
4241.7.7.6
425