linux-ti33x-psp 3.2: backport PM and USB fixes from PSP
[glsdk/meta-ti-glsdk.git] / recipes-kernel / linux / linux-ti33x-psp-3.2 / psp / 0010-usb-musb-cppi41-enable-txfifo-empty-interrupt-logic.patch
1 From a4d99c3c1e01b91b69c6939ba3ee708611869402 Mon Sep 17 00:00:00 2001
2 From: Ajay Kumar Gupta <ajay.gupta@ti.com>
3 Date: Wed, 23 May 2012 15:25:32 +0530
4 Subject: [PATCH 10/18] usb: musb: cppi41: enable txfifo empty interrupt logic
6 Fixes the txdma early completion issue as the TxFIFO empty interrupt
7 logic generates an interrupt when last byte from TxFIFO is
8 transmitted out.
10 The application issues fixed are -
11 1) 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.
15 2) The workthread is rescheduled once again when txfifo is empty to
16    make sure any miss of transfer of the data in internal cppififo.
18 3) 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.
23 Signed-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(-)
34 diff --git a/drivers/usb/musb/cppi41_dma.c b/drivers/usb/musb/cppi41_dma.c
35 index 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;
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;
160 +                               tx_ch->channel.status =
161 +                                       MUSB_DMA_STATUS_FREE;
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);
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;
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);
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;
214 +                               residue = tx_ch->channel.actual_len %
215 +                                               tx_ch->pkt_size;
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  }
231 diff --git a/drivers/usb/musb/cppi41_dma.h b/drivers/usb/musb/cppi41_dma.h
232 index 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_ */
247 diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
248 index 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 +}
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 +}
292  static inline void musb_platform_set_vbus(struct musb *musb, int is_on)
293  {
294         if (musb->ops->set_vbus)
295 diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
296 index 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)
307 diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
308 index 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) {
319 diff --git a/drivers/usb/musb/ti81xx.c b/drivers/usb/musb/ti81xx.c
320 index 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;
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 +}
349 +void txfifoempty_intr_disable(struct musb *musb, u8 ep_num)
350 +{
351 +       void __iomem *reg_base = musb->ctrl_base;
352 +       u32 coremask;
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 +}
360 +#endif /* CONFIG_USB_TI_CPPI41_DMA */
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);
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;
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)
409 diff --git a/drivers/usb/musb/ti81xx.h b/drivers/usb/musb/ti81xx.h
410 index 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
420                                 /* interrupts and DRVVBUS interrupt */
421  #define USB_INTR_DRVVBUS        0x100
422  #define USB_INTR_RX_SHIFT       16
423 -- 
424 1.7.7.6