aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Walleij <linus.walleij@stericsson.com>2010-09-29 04:31:35 -0400
committerGrant Likely <grant.likely@secretlab.ca>2010-10-12 23:37:37 -0400
commitb1b6b9aa6fd32db97469e65d301ebc32dcd67992 (patch)
tree2a6f3f7d34a50a574854ea7495476f21fd6fcfce
parentcdbc8f042f4f2568bb58ba8bd50d0692f3059417 (diff)
spi/pl022: add PrimeCell generic DMA support
This extends the PL022 SSP/SPI driver with generic DMA engine support using the PrimeCell DMA engine interface. Also fix up the test code for the U300 platform. Signed-off-by: Linus Walleij <linus.walleij@stericsson.com> Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
-rw-r--r--drivers/spi/amba-pl022.c516
-rw-r--r--include/linux/amba/pl022.h6
2 files changed, 434 insertions, 88 deletions
diff --git a/drivers/spi/amba-pl022.c b/drivers/spi/amba-pl022.c
index 8cdddc97325..db0c67908d2 100644
--- a/drivers/spi/amba-pl022.c
+++ b/drivers/spi/amba-pl022.c
@@ -27,7 +27,6 @@
27/* 27/*
28 * TODO: 28 * TODO:
29 * - add timeout on polled transfers 29 * - add timeout on polled transfers
30 * - add generic DMA framework support
31 */ 30 */
32 31
33#include <linux/init.h> 32#include <linux/init.h>
@@ -45,6 +44,9 @@
45#include <linux/amba/pl022.h> 44#include <linux/amba/pl022.h>
46#include <linux/io.h> 45#include <linux/io.h>
47#include <linux/slab.h> 46#include <linux/slab.h>
47#include <linux/dmaengine.h>
48#include <linux/dma-mapping.h>
49#include <linux/scatterlist.h>
48 50
49/* 51/*
50 * This macro is used to define some register default values. 52 * This macro is used to define some register default values.
@@ -381,6 +383,14 @@ struct pl022 {
381 enum ssp_reading read; 383 enum ssp_reading read;
382 enum ssp_writing write; 384 enum ssp_writing write;
383 u32 exp_fifo_level; 385 u32 exp_fifo_level;
386 /* DMA settings */
387#ifdef CONFIG_DMA_ENGINE
388 struct dma_chan *dma_rx_channel;
389 struct dma_chan *dma_tx_channel;
390 struct sg_table sgt_rx;
391 struct sg_table sgt_tx;
392 char *dummypage;
393#endif
384}; 394};
385 395
386/** 396/**
@@ -406,7 +416,7 @@ struct chip_data {
406 u16 dmacr; 416 u16 dmacr;
407 u16 cpsr; 417 u16 cpsr;
408 u8 n_bytes; 418 u8 n_bytes;
409 u8 enable_dma:1; 419 bool enable_dma;
410 enum ssp_reading read; 420 enum ssp_reading read;
411 enum ssp_writing write; 421 enum ssp_writing write;
412 void (*cs_control) (u32 command); 422 void (*cs_control) (u32 command);
@@ -763,6 +773,371 @@ static void *next_transfer(struct pl022 *pl022)
763 } 773 }
764 return STATE_DONE; 774 return STATE_DONE;
765} 775}
776
777/*
778 * This DMA functionality is only compiled in if we have
779 * access to the generic DMA devices/DMA engine.
780 */
781#ifdef CONFIG_DMA_ENGINE
782static void unmap_free_dma_scatter(struct pl022 *pl022)
783{
784 /* Unmap and free the SG tables */
785 dma_unmap_sg(&pl022->adev->dev, pl022->sgt_tx.sgl,
786 pl022->sgt_tx.nents, DMA_TO_DEVICE);
787 dma_unmap_sg(&pl022->adev->dev, pl022->sgt_rx.sgl,
788 pl022->sgt_rx.nents, DMA_FROM_DEVICE);
789 sg_free_table(&pl022->sgt_rx);
790 sg_free_table(&pl022->sgt_tx);
791}
792
793static void dma_callback(void *data)
794{
795 struct pl022 *pl022 = data;
796 struct spi_message *msg = pl022->cur_msg;
797
798 BUG_ON(!pl022->sgt_rx.sgl);
799
800#ifdef VERBOSE_DEBUG
801 /*
802 * Optionally dump out buffers to inspect contents, this is
803 * good if you want to convince yourself that the loopback
804 * read/write contents are the same, when adopting to a new
805 * DMA engine.
806 */
807 {
808 struct scatterlist *sg;
809 unsigned int i;
810
811 dma_sync_sg_for_cpu(&pl022->adev->dev,
812 pl022->sgt_rx.sgl,
813 pl022->sgt_rx.nents,
814 DMA_FROM_DEVICE);
815
816 for_each_sg(pl022->sgt_rx.sgl, sg, pl022->sgt_rx.nents, i) {
817 dev_dbg(&pl022->adev->dev, "SPI RX SG ENTRY: %d", i);
818 print_hex_dump(KERN_ERR, "SPI RX: ",
819 DUMP_PREFIX_OFFSET,
820 16,
821 1,
822 sg_virt(sg),
823 sg_dma_len(sg),
824 1);
825 }
826 for_each_sg(pl022->sgt_tx.sgl, sg, pl022->sgt_tx.nents, i) {
827 dev_dbg(&pl022->adev->dev, "SPI TX SG ENTRY: %d", i);
828 print_hex_dump(KERN_ERR, "SPI TX: ",
829 DUMP_PREFIX_OFFSET,
830 16,
831 1,
832 sg_virt(sg),
833 sg_dma_len(sg),
834 1);
835 }
836 }
837#endif
838
839 unmap_free_dma_scatter(pl022);
840
841 /* Update total bytes transfered */
842 msg->actual_length += pl022->cur_transfer->len;
843 if (pl022->cur_transfer->cs_change)
844 pl022->cur_chip->
845 cs_control(SSP_CHIP_DESELECT);
846
847 /* Move to next transfer */
848 msg->state = next_transfer(pl022);
849 tasklet_schedule(&pl022->pump_transfers);
850}
851
852static void setup_dma_scatter(struct pl022 *pl022,
853 void *buffer,
854 unsigned int length,
855 struct sg_table *sgtab)
856{
857 struct scatterlist *sg;
858 int bytesleft = length;
859 void *bufp = buffer;
860 int mapbytes;
861 int i;
862
863 if (buffer) {
864 for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
865 /*
866 * If there are less bytes left than what fits
867 * in the current page (plus page alignment offset)
868 * we just feed in this, else we stuff in as much
869 * as we can.
870 */
871 if (bytesleft < (PAGE_SIZE - offset_in_page(bufp)))
872 mapbytes = bytesleft;
873 else
874 mapbytes = PAGE_SIZE - offset_in_page(bufp);
875 sg_set_page(sg, virt_to_page(bufp),
876 mapbytes, offset_in_page(bufp));
877 bufp += mapbytes;
878 bytesleft -= mapbytes;
879 dev_dbg(&pl022->adev->dev,
880 "set RX/TX target page @ %p, %d bytes, %d left\n",
881 bufp, mapbytes, bytesleft);
882 }
883 } else {
884 /* Map the dummy buffer on every page */
885 for_each_sg(sgtab->sgl, sg, sgtab->nents, i) {
886 if (bytesleft < PAGE_SIZE)
887 mapbytes = bytesleft;
888 else
889 mapbytes = PAGE_SIZE;
890 sg_set_page(sg, virt_to_page(pl022->dummypage),
891 mapbytes, 0);
892 bytesleft -= mapbytes;
893 dev_dbg(&pl022->adev->dev,
894 "set RX/TX to dummy page %d bytes, %d left\n",
895 mapbytes, bytesleft);
896
897 }
898 }
899 BUG_ON(bytesleft);
900}
901
902/**
903 * configure_dma - configures the channels for the next transfer
904 * @pl022: SSP driver's private data structure
905 */
906static int configure_dma(struct pl022 *pl022)
907{
908 struct dma_slave_config rx_conf = {
909 .src_addr = SSP_DR(pl022->phybase),
910 .direction = DMA_FROM_DEVICE,
911 .src_maxburst = pl022->vendor->fifodepth >> 1,
912 };
913 struct dma_slave_config tx_conf = {
914 .dst_addr = SSP_DR(pl022->phybase),
915 .direction = DMA_TO_DEVICE,
916 .dst_maxburst = pl022->vendor->fifodepth >> 1,
917 };
918 unsigned int pages;
919 int ret;
920 int sglen;
921 struct dma_chan *rxchan = pl022->dma_rx_channel;
922 struct dma_chan *txchan = pl022->dma_tx_channel;
923 struct dma_async_tx_descriptor *rxdesc;
924 struct dma_async_tx_descriptor *txdesc;
925 dma_cookie_t cookie;
926
927 /* Check that the channels are available */
928 if (!rxchan || !txchan)
929 return -ENODEV;
930