0397-dmaengine-bcm2835-add-slave_sg-support-to-bcm2835-dm.patch 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. From 9d449a908099a6dc0779bb1a9e87f5e224909a24 Mon Sep 17 00:00:00 2001
  2. From: Martin Sperl <kernel@martin.sperl.org>
  3. Date: Wed, 16 Mar 2016 12:25:01 -0700
  4. Subject: [PATCH] dmaengine: bcm2835: add slave_sg support to bcm2835-dma
  5. Add slave_sg support to bcm2835-dma using shared allocation
  6. code for bcm2835_desc and DMA-control blocks already used by
  7. dma_cyclic.
  8. Note that bcm2835_dma_callback had to get modified to support
  9. both modes of operation (cyclic and non-cyclic).
  10. Tested using:
  11. * Hifiberry I2S card (using cyclic DMA)
  12. * fb_st7735r SPI-framebuffer (using slave_sg DMA via spi-bcm2835)
  13. playing BigBuckBunny for audio and video.
  14. Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
  15. Reviewed-by: Eric Anholt <eric@anholt.net>
  16. Signed-off-by: Eric Anholt <eric@anholt.net>
  17. Signed-off-by: Vinod Koul <vinod.koul@intel.com>
  18. ---
  19. drivers/dma/bcm2835-dma.c | 113 ++++++++++++++++++++++++++++++++++++++++++++--
  20. 1 file changed, 108 insertions(+), 5 deletions(-)
  21. --- a/drivers/dma/bcm2835-dma.c
  22. +++ b/drivers/dma/bcm2835-dma.c
  23. @@ -260,6 +260,23 @@ static void bcm2835_dma_create_cb_set_le
  24. control_block->info |= finalextrainfo;
  25. }
  26. +static inline size_t bcm2835_dma_count_frames_for_sg(
  27. + struct bcm2835_chan *c,
  28. + struct scatterlist *sgl,
  29. + unsigned int sg_len)
  30. +{
  31. + size_t frames = 0;
  32. + struct scatterlist *sgent;
  33. + unsigned int i;
  34. + size_t plength = bcm2835_dma_max_frame_length(c);
  35. +
  36. + for_each_sg(sgl, sgent, sg_len, i)
  37. + frames += bcm2835_dma_frames_for_length(
  38. + sg_dma_len(sgent), plength);
  39. +
  40. + return frames;
  41. +}
  42. +
  43. /**
  44. * bcm2835_dma_create_cb_chain - create a control block and fills data in
  45. *
  46. @@ -361,6 +378,32 @@ error_cb:
  47. return NULL;
  48. }
  49. +static void bcm2835_dma_fill_cb_chain_with_sg(
  50. + struct dma_chan *chan,
  51. + enum dma_transfer_direction direction,
  52. + struct bcm2835_cb_entry *cb,
  53. + struct scatterlist *sgl,
  54. + unsigned int sg_len)
  55. +{
  56. + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
  57. + size_t max_len = bcm2835_dma_max_frame_length(c);
  58. + unsigned int i, len;
  59. + dma_addr_t addr;
  60. + struct scatterlist *sgent;
  61. +
  62. + for_each_sg(sgl, sgent, sg_len, i) {
  63. + for (addr = sg_dma_address(sgent), len = sg_dma_len(sgent);
  64. + len > 0;
  65. + addr += cb->cb->length, len -= cb->cb->length, cb++) {
  66. + if (direction == DMA_DEV_TO_MEM)
  67. + cb->cb->dst = addr;
  68. + else
  69. + cb->cb->src = addr;
  70. + cb->cb->length = min(len, max_len);
  71. + }
  72. + }
  73. +}
  74. +
  75. static int bcm2835_dma_abort(void __iomem *chan_base)
  76. {
  77. unsigned long cs;
  78. @@ -428,13 +471,19 @@ static irqreturn_t bcm2835_dma_callback(
  79. d = c->desc;
  80. if (d) {
  81. - /* TODO Only works for cyclic DMA */
  82. - vchan_cyclic_callback(&d->vd);
  83. + if (d->cyclic) {
  84. + /* call the cyclic callback */
  85. + vchan_cyclic_callback(&d->vd);
  86. +
  87. + /* Keep the DMA engine running */
  88. + writel(BCM2835_DMA_ACTIVE,
  89. + c->chan_base + BCM2835_DMA_CS);
  90. + } else {
  91. + vchan_cookie_complete(&c->desc->vd);
  92. + bcm2835_dma_start_desc(c);
  93. + }
  94. }
  95. - /* Keep the DMA engine running */
  96. - writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
  97. -
  98. spin_unlock_irqrestore(&c->vc.lock, flags);
  99. return IRQ_HANDLED;
  100. @@ -548,6 +597,58 @@ static void bcm2835_dma_issue_pending(st
  101. spin_unlock_irqrestore(&c->vc.lock, flags);
  102. }
  103. +static struct dma_async_tx_descriptor *bcm2835_dma_prep_slave_sg(
  104. + struct dma_chan *chan,
  105. + struct scatterlist *sgl, unsigned int sg_len,
  106. + enum dma_transfer_direction direction,
  107. + unsigned long flags, void *context)
  108. +{
  109. + struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
  110. + struct bcm2835_desc *d;
  111. + dma_addr_t src = 0, dst = 0;
  112. + u32 info = BCM2835_DMA_WAIT_RESP;
  113. + u32 extra = BCM2835_DMA_INT_EN;
  114. + size_t frames;
  115. +
  116. + if (!is_slave_direction(direction)) {
  117. + dev_err(chan->device->dev,
  118. + "%s: bad direction?\n", __func__);
  119. + return NULL;
  120. + }
  121. +
  122. + if (c->dreq != 0)
  123. + info |= BCM2835_DMA_PER_MAP(c->dreq);
  124. +
  125. + if (direction == DMA_DEV_TO_MEM) {
  126. + if (c->cfg.src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
  127. + return NULL;
  128. + src = c->cfg.src_addr;
  129. + info |= BCM2835_DMA_S_DREQ | BCM2835_DMA_D_INC;
  130. + } else {
  131. + if (c->cfg.dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES)
  132. + return NULL;
  133. + dst = c->cfg.dst_addr;
  134. + info |= BCM2835_DMA_D_DREQ | BCM2835_DMA_S_INC;
  135. + }
  136. +
  137. + /* count frames in sg list */
  138. + frames = bcm2835_dma_count_frames_for_sg(c, sgl, sg_len);
  139. +
  140. + /* allocate the CB chain */
  141. + d = bcm2835_dma_create_cb_chain(chan, direction, false,
  142. + info, extra,
  143. + frames, src, dst, 0, 0,
  144. + GFP_KERNEL);
  145. + if (!d)
  146. + return NULL;
  147. +
  148. + /* fill in frames with scatterlist pointers */
  149. + bcm2835_dma_fill_cb_chain_with_sg(chan, direction, d->cb_list,
  150. + sgl, sg_len);
  151. +
  152. + return vchan_tx_prep(&c->vc, &d->vd, flags);
  153. +}
  154. +
  155. static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
  156. struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
  157. size_t period_len, enum dma_transfer_direction direction,
  158. @@ -778,11 +879,13 @@ static int bcm2835_dma_probe(struct plat
  159. dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
  160. dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
  161. dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
  162. + dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
  163. od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources;
  164. od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
  165. od->ddev.device_tx_status = bcm2835_dma_tx_status;
  166. od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
  167. od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
  168. + od->ddev.device_prep_slave_sg = bcm2835_dma_prep_slave_sg;
  169. od->ddev.device_config = bcm2835_dma_slave_config;
  170. od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
  171. od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);