summaryrefslogtreecommitdiffstats
path: root/drivers/dma
diff options
context:
space:
mode:
authorTomasz Figa <tomasz.figa@gmail.com>2013-08-11 13:59:17 -0400
committerVinod Koul <vinod.koul@intel.com>2013-09-02 02:19:56 -0400
commitda1b6c05b8b5bd9af060acb319360604a0890c2e (patch)
treecae3c392c375500b663ccffcbbdcee498769c924 /drivers/dma
parent48924e4224540b249e56d82e58dee5bcaabfe52b (diff)
dmaengine: PL08x: Add support for PL080S variant
PL080S is a modified version of PL080 that can be found on Samsung SoCs, such as S3C6400 and S3C6410. It has different offset of CONFIG register, separate CONTROL1 register that holds transfer size and larger maximum transfer size. Signed-off-by: Tomasz Figa <tomasz.figa@gmail.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Signed-off-by: Vinod Koul <vinod.koul@intel.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/amba-pl08x.c145
1 files changed, 118 insertions, 27 deletions
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 1fa05d618141..75915be252f5 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -24,6 +24,7 @@
24 * 24 *
25 * Documentation: ARM DDI 0196G == PL080 25 * Documentation: ARM DDI 0196G == PL080
26 * Documentation: ARM DDI 0218E == PL081 26 * Documentation: ARM DDI 0218E == PL081
27 * Documentation: S3C6410 User's Manual == PL080S
27 * 28 *
28 * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any 29 * PL080 & PL081 both have 16 sets of DMA signals that can be routed to any
29 * channel. 30 * channel.
@@ -36,6 +37,14 @@
36 * 37 *
37 * The PL080 has a dual bus master, PL081 has a single master. 38 * The PL080 has a dual bus master, PL081 has a single master.
38 * 39 *
40 * PL080S is a version modified by Samsung and used in S3C64xx SoCs.
41 * It differs in following aspects:
42 * - CH_CONFIG register at different offset,
43 * - separate CH_CONTROL2 register for transfer size,
44 * - bigger maximum transfer size,
45 * - 8-word aligned LLI, instead of 4-word, due to extra CCTL2 word,
46 * - no support for peripheral flow control.
47 *
39 * Memory to peripheral transfer may be visualized as 48 * Memory to peripheral transfer may be visualized as
40 * Get data from memory to DMAC 49 * Get data from memory to DMAC
41 * Until no data left 50 * Until no data left
@@ -64,10 +73,7 @@
64 * - Peripheral flow control: the transfer size is ignored (and should be 73 * - Peripheral flow control: the transfer size is ignored (and should be
65 * zero). The data is transferred from the current LLI entry, until 74 * zero). The data is transferred from the current LLI entry, until
66 * after the final transfer signalled by LBREQ or LSREQ. The DMAC 75 * after the final transfer signalled by LBREQ or LSREQ. The DMAC
67 * will then move to the next LLI entry. 76 * will then move to the next LLI entry. Unsupported by PL080S.
68 *
69 * Global TODO:
70 * - Break out common code from arch/arm/mach-s3c64xx and share
71 */ 77 */
72#include <linux/amba/bus.h> 78#include <linux/amba/bus.h>
73#include <linux/amba/pl08x.h> 79#include <linux/amba/pl08x.h>
@@ -100,12 +106,15 @@ struct pl08x_driver_data;
100 * @nomadik: whether the channels have Nomadik security extension bits 106 * @nomadik: whether the channels have Nomadik security extension bits
101 * that need to be checked for permission before use and some registers are 107 * that need to be checked for permission before use and some registers are
102 * missing 108 * missing
109 * @pl080s: whether this version is a PL080S, which has separate register and
110 * LLI word for transfer size.
103 */ 111 */
104struct vendor_data { 112struct vendor_data {
105 u8 config_offset; 113 u8 config_offset;
106 u8 channels; 114 u8 channels;
107 bool dualmaster; 115 bool dualmaster;
108 bool nomadik; 116 bool nomadik;
117 bool pl080s;
109}; 118};
110 119
111/** 120/**
@@ -264,9 +273,11 @@ struct pl08x_driver_data {
264#define PL080_LLI_DST 1 273#define PL080_LLI_DST 1
265#define PL080_LLI_LLI 2 274#define PL080_LLI_LLI 2
266#define PL080_LLI_CCTL 3 275#define PL080_LLI_CCTL 3
276#define PL080S_LLI_CCTL2 4
267 277
268/* Total words in an LLI. */ 278/* Total words in an LLI. */
269#define PL080_LLI_WORDS 4 279#define PL080_LLI_WORDS 4
280#define PL080S_LLI_WORDS 8
270 281
271/* 282/*
272 * Number of LLIs in each LLI buffer allocated for one transfer 283 * Number of LLIs in each LLI buffer allocated for one transfer
@@ -340,17 +351,29 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
340static void pl08x_write_lli(struct pl08x_driver_data *pl08x, 351static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
341 struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg) 352 struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg)
342{ 353{
343 dev_vdbg(&pl08x->adev->dev, 354 if (pl08x->vd->pl080s)
344 "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, " 355 dev_vdbg(&pl08x->adev->dev,
345 "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n", 356 "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
346 phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST], 357 "clli=0x%08x, cctl=0x%08x, cctl2=0x%08x, ccfg=0x%08x\n",
347 lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg); 358 phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
359 lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL],
360 lli[PL080S_LLI_CCTL2], ccfg);
361 else
362 dev_vdbg(&pl08x->adev->dev,
363 "WRITE channel %d: csrc=0x%08x, cdst=0x%08x, "
364 "clli=0x%08x, cctl=0x%08x, ccfg=0x%08x\n",
365 phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
366 lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
348 367
349 writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR); 368 writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR);
350 writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR); 369 writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR);
351 writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI); 370 writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI);
352 writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL); 371 writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL);
353 372
373 if (pl08x->vd->pl080s)
374 writel_relaxed(lli[PL080S_LLI_CCTL2],
375 phychan->base + PL080S_CH_CONTROL2);
376
354 writel(ccfg, phychan->reg_config); 377 writel(ccfg, phychan->reg_config);
355} 378}
356 379
@@ -469,6 +492,24 @@ static inline u32 get_bytes_in_cctl(u32 cctl)
469 return bytes; 492 return bytes;
470} 493}
471 494
495static inline u32 get_bytes_in_cctl_pl080s(u32 cctl, u32 cctl1)
496{
497 /* The source width defines the number of bytes */
498 u32 bytes = cctl1 & PL080S_CONTROL_TRANSFER_SIZE_MASK;
499
500 switch (cctl >> PL080_CONTROL_SWIDTH_SHIFT) {
501 case PL080_WIDTH_8BIT:
502 break;
503 case PL080_WIDTH_16BIT:
504 bytes *= 2;
505 break;
506 case PL080_WIDTH_32BIT:
507 bytes *= 4;
508 break;
509 }
510 return bytes;
511}
512
472/* The channel should be paused when calling this */ 513/* The channel should be paused when calling this */
473static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan) 514static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
474{ 515{
@@ -494,7 +535,12 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
494 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2; 535 clli = readl(ch->base + PL080_CH_LLI) & ~PL080_LLI_LM_AHB2;
495 536
496 /* First get the remaining bytes in the active transfer */ 537 /* First get the remaining bytes in the active transfer */
497 bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL)); 538 if (pl08x->vd->pl080s)
539 bytes = get_bytes_in_cctl_pl080s(
540 readl(ch->base + PL080_CH_CONTROL),
541 readl(ch->base + PL080S_CH_CONTROL2));
542 else
543 bytes = get_bytes_in_cctl(readl(ch->base + PL080_CH_CONTROL));
498 544
499 if (!clli) 545 if (!clli)
500 return bytes; 546 return bytes;
@@ -515,7 +561,12 @@ static u32 pl08x_getbytes_chan(struct pl08x_dma_chan *plchan)
515 llis_va_limit = llis_va + llis_max_words; 561 llis_va_limit = llis_va + llis_max_words;
516 562
517 for (; llis_va < llis_va_limit; llis_va += pl08x->lli_words) { 563 for (; llis_va < llis_va_limit; llis_va += pl08x->lli_words) {
518 bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]); 564 if (pl08x->vd->pl080s)
565 bytes += get_bytes_in_cctl_pl080s(
566 llis_va[PL080_LLI_CCTL],
567 llis_va[PL080S_LLI_CCTL2]);
568 else
569 bytes += get_bytes_in_cctl(llis_va[PL080_LLI_CCTL]);
519 570
520 /* 571 /*
521 * A LLI pointer of 0 terminates the LLI list 572 * A LLI pointer of 0 terminates the LLI list
@@ -778,7 +829,7 @@ static void pl08x_choose_master_bus(struct pl08x_lli_build_data *bd,
778 */ 829 */
779static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x, 830static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
780 struct pl08x_lli_build_data *bd, 831 struct pl08x_lli_build_data *bd,
781 int num_llis, int len, u32 cctl) 832 int num_llis, int len, u32 cctl, u32 cctl2)
782{ 833{
783 u32 offset = num_llis * pl08x->lli_words; 834 u32 offset = num_llis * pl08x->lli_words;
784 u32 *llis_va = bd->txd->llis_va + offset; 835 u32 *llis_va = bd->txd->llis_va + offset;
@@ -794,6 +845,8 @@ static void pl08x_fill_lli_for_desc(struct pl08x_driver_data *pl08x,
794 llis_va[PL080_LLI_LLI] = (llis_bus + sizeof(u32) * offset); 845 llis_va[PL080_LLI_LLI] = (llis_bus + sizeof(u32) * offset);
795 llis_va[PL080_LLI_LLI] |= bd->lli_bus; 846 llis_va[PL080_LLI_LLI] |= bd->lli_bus;
796 llis_va[PL080_LLI_CCTL] = cctl; 847 llis_va[PL080_LLI_CCTL] = cctl;
848 if (pl08x->vd->pl080s)
849 llis_va[PL080S_LLI_CCTL2] = cctl2;
797 850
798 if (cctl & PL080_CONTROL_SRC_INCR) 851 if (cctl & PL080_CONTROL_SRC_INCR)
799 bd->srcbus.addr += len; 852 bd->srcbus.addr += len;
@@ -810,7 +863,7 @@ static inline void prep_byte_width_lli(struct pl08x_driver_data *pl08x,
810 int num_llis, size_t *total_bytes) 863 int num_llis, size_t *total_bytes)
811{ 864{
812 *cctl = pl08x_cctl_bits(*cctl, 1, 1, len); 865 *cctl = pl08x_cctl_bits(*cctl, 1, 1, len);
813 pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl); 866 pl08x_fill_lli_for_desc(pl08x, bd, num_llis, len, *cctl, len);
814 (*total_bytes) += len; 867 (*total_bytes) += len;
815} 868}
816 869
@@ -820,16 +873,31 @@ static void pl08x_dump_lli(struct pl08x_driver_data *pl08x,
820{ 873{
821 int i; 874 int i;
822 875
823 dev_vdbg(&pl08x->adev->dev, 876 if (pl08x->vd->pl080s) {
824 "%-3s %-9s %-10s %-10s %-10s %s\n",
825 "lli", "", "csrc", "cdst", "clli", "cctl");
826 for (i = 0; i < num_llis; i++) {
827 dev_vdbg(&pl08x->adev->dev, 877 dev_vdbg(&pl08x->adev->dev,
828 "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n", 878 "%-3s %-9s %-10s %-10s %-10s %-10s %s\n",
829 i, llis_va, llis_va[PL080_LLI_SRC], 879 "lli", "", "csrc", "cdst", "clli", "cctl", "cctl2");
830 llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI], 880 for (i = 0; i < num_llis; i++) {
831 llis_va[PL080_LLI_CCTL]); 881 dev_vdbg(&pl08x->adev->dev,
832 llis_va += pl08x->lli_words; 882 "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
883 i, llis_va, llis_va[PL080_LLI_SRC],
884 llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
885 llis_va[PL080_LLI_CCTL],
886 llis_va[PL080S_LLI_CCTL2]);
887 llis_va += pl08x->lli_words;
888 }
889 } else {
890 dev_vdbg(&pl08x->adev->dev,
891 "%-3s %-9s %-10s %-10s %-10s %s\n",
892 "lli", "", "csrc", "cdst", "clli", "cctl");
893 for (i = 0; i < num_llis; i++) {
894 dev_vdbg(&pl08x->adev->dev,
895 "%3d @%p: 0x%08x 0x%08x 0x%08x 0x%08x\n",
896 i, llis_va, llis_va[PL080_LLI_SRC],
897 llis_va[PL080_LLI_DST], llis_va[PL080_LLI_LLI],
898 llis_va[PL080_LLI_CCTL]);
899 llis_va += pl08x->lli_words;
900 }
833 } 901 }
834} 902}
835#else 903#else
@@ -938,7 +1006,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
938 cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, 1006 cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
939 bd.dstbus.buswidth, 0); 1007 bd.dstbus.buswidth, 0);
940 pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++, 1008 pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
941 0, cctl); 1009 0, cctl, 0);
942 break; 1010 break;
943 } 1011 }
944 1012
@@ -1018,7 +1086,7 @@ static int pl08x_fill_llis_for_desc(struct pl08x_driver_data *pl08x,
1018 cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth, 1086 cctl = pl08x_cctl_bits(cctl, bd.srcbus.buswidth,
1019 bd.dstbus.buswidth, tsize); 1087 bd.dstbus.buswidth, tsize);
1020 pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++, 1088 pl08x_fill_lli_for_desc(pl08x, &bd, num_llis++,
1021 lli_len, cctl); 1089 lli_len, cctl, tsize);
1022 total_bytes += lli_len; 1090 total_bytes += lli_len;
1023 } 1091 }
1024 1092
@@ -1332,6 +1400,7 @@ static int dma_set_runtime_config(struct dma_chan *chan,
1332 struct dma_slave_config *config) 1400 struct dma_slave_config *config)
1333{ 1401{
1334 struct pl08x_dma_chan *plchan = to_pl08x_chan(chan); 1402 struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
1403 struct pl08x_driver_data *pl08x = plchan->host;
1335 1404
1336 if (!plchan->slave) 1405 if (!plchan->slave)
1337 return -EINVAL; 1406 return -EINVAL;
@@ -1341,6 +1410,13 @@ static int dma_set_runtime_config(struct dma_chan *chan,
1341 config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) 1410 config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
1342 return -EINVAL; 1411 return -EINVAL;
1343 1412
1413 if (config->device_fc && pl08x->vd->pl080s) {
1414 dev_err(&pl08x->adev->dev,
1415 "%s: PL080S does not support peripheral flow control\n",
1416 __func__);
1417 return -EINVAL;
1418 }
1419
1344 plchan->cfg = *config; 1420 plchan->cfg = *config;
1345 1421
1346 return 0; 1422 return 0;
@@ -1930,7 +2006,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
1930 pl08x->mem_buses = pl08x->pd->mem_buses; 2006 pl08x->mem_buses = pl08x->pd->mem_buses;
1931 } 2007 }
1932 2008
1933 pl08x->lli_words = PL080_LLI_WORDS; 2009 if (vd->pl080s)
2010 pl08x->lli_words = PL080S_LLI_WORDS;
2011 else
2012 pl08x->lli_words = PL080_LLI_WORDS;
1934 tsfr_size = MAX_NUM_TSFR_LLIS * pl08x->lli_words * sizeof(u32); 2013 tsfr_size = MAX_NUM_TSFR_LLIS * pl08x->lli_words * sizeof(u32);
1935 2014
1936 /* A DMA memory pool for LLIs, align on 1-byte boundary */ 2015 /* A DMA memory pool for LLIs, align on 1-byte boundary */
@@ -2040,8 +2119,8 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
2040 2119
2041 amba_set_drvdata(adev, pl08x); 2120 amba_set_drvdata(adev, pl08x);
2042 init_pl08x_debugfs(pl08x); 2121 init_pl08x_debugfs(pl08x);
2043 dev_info(&pl08x->adev->dev, "DMA: PL%03x rev%u at 0x%08llx irq %d\n", 2122 dev_info(&pl08x->adev->dev, "DMA: PL%03x%s rev%u at 0x%08llx irq %d\n",
2044 amba_part(adev), amba_rev(adev), 2123 amba_part(adev), pl08x->vd->pl080s ? "s" : "", amba_rev(adev),
2045 (unsigned long long)adev->res.start, adev->irq[0]); 2124 (unsigned long long)adev->res.start, adev->irq[0]);
2046 2125
2047 return 0; 2126 return 0;
@@ -2082,6 +2161,12 @@ static struct vendor_data vendor_nomadik = {
2082 .nomadik = true, 2161 .nomadik = true,
2083}; 2162};
2084 2163
2164static struct vendor_data vendor_pl080s = {
2165 .config_offset = PL080S_CH_CONFIG,
2166 .channels = 8,
2167 .pl080s = true,
2168};
2169
2085static struct vendor_data vendor_pl081 = { 2170static struct vendor_data vendor_pl081 = {
2086 .config_offset = PL080_CH_CONFIG, 2171 .config_offset = PL080_CH_CONFIG,
2087 .channels = 2, 2172 .channels = 2,
@@ -2089,6 +2174,12 @@ static struct vendor_data vendor_pl081 = {
2089}; 2174};
2090 2175
2091static struct amba_id pl08x_ids[] = { 2176static struct amba_id pl08x_ids[] = {
2177 /* Samsung PL080S variant */
2178 {
2179 .id = 0x0a141080,
2180 .mask = 0xffffffff,
2181 .data = &vendor_pl080s,
2182 },
2092 /* PL080 */ 2183 /* PL080 */
2093 { 2184 {
2094 .id = 0x00041080, 2185 .id = 0x00041080,