aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/dma/Kconfig6
-rw-r--r--drivers/dma/amba-pl08x.c767
-rw-r--r--include/linux/amba/pl080.h83
3 files changed, 698 insertions, 158 deletions
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index 24e8597b2c3e..67ab15aa98c3 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -62,8 +62,10 @@ config AMBA_PL08X
62 select DMA_ENGINE 62 select DMA_ENGINE
63 select DMA_VIRTUAL_CHANNELS 63 select DMA_VIRTUAL_CHANNELS
64 help 64 help
65 Platform has a PL08x DMAC device 65 Say yes if your platform has a PL08x DMAC device which can
66 which can provide DMA engine support 66 provide DMA engine support. This includes the original ARM
67 PL080 and PL081, Samsungs PL080 derivative and Faraday
68 Technology's FTDMAC020 PL080 derivative.
67 69
68config AMCC_PPC440SPE_ADMA 70config AMCC_PPC440SPE_ADMA
69 tristate "AMCC PPC440SPe ADMA support" 71 tristate "AMCC PPC440SPe ADMA support"
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 6ddb029dac50..13cc95c0474c 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1,9 +1,10 @@
1/* 1/*
2 * Copyright (c) 2006 ARM Ltd. 2 * Copyright (c) 2006 ARM Ltd.
3 * Copyright (c) 2010 ST-Ericsson SA 3 * Copyright (c) 2010 ST-Ericsson SA
4 * Copyirght (c) 2017 Linaro Ltd.
4 * 5 *
5 * Author: Peter Pearse <peter.pearse@arm.com> 6 * Author: Peter Pearse <peter.pearse@arm.com>
6 * Author: Linus Walleij <linus.walleij@stericsson.com> 7 * Author: Linus Walleij <linus.walleij@linaro.org>
7 * 8 *
8 * This program is free software; you can redistribute it and/or modify it 9 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free 10 * under the terms of the GNU General Public License as published by the Free
@@ -110,11 +111,12 @@ struct pl08x_driver_data;
110 * @channels: the number of channels available in this variant 111 * @channels: the number of channels available in this variant
111 * @signals: the number of request signals available from the hardware 112 * @signals: the number of request signals available from the hardware
112 * @dualmaster: whether this version supports dual AHB masters or not. 113 * @dualmaster: whether this version supports dual AHB masters or not.
113 * @nomadik: whether the channels have Nomadik security extension bits 114 * @nomadik: whether this variant is a ST Microelectronics Nomadik, where the
114 * that need to be checked for permission before use and some registers are 115 * channels have Nomadik security extension bits that need to be checked
115 * missing 116 * for permission before use and some registers are missing
116 * @pl080s: whether this version is a PL080S, which has separate register and 117 * @pl080s: whether this variant is a Samsung PL080S, which has separate
117 * LLI word for transfer size. 118 * register and LLI word for transfer size.
119 * @ftdmac020: whether this variant is a Faraday Technology FTDMAC020
118 * @max_transfer_size: the maximum single element transfer size for this 120 * @max_transfer_size: the maximum single element transfer size for this
119 * PL08x variant. 121 * PL08x variant.
120 */ 122 */
@@ -125,6 +127,7 @@ struct vendor_data {
125 bool dualmaster; 127 bool dualmaster;
126 bool nomadik; 128 bool nomadik;
127 bool pl080s; 129 bool pl080s;
130 bool ftdmac020;
128 u32 max_transfer_size; 131 u32 max_transfer_size;
129}; 132};
130 133
@@ -148,19 +151,34 @@ struct pl08x_bus_data {
148 * @id: physical index to this channel 151 * @id: physical index to this channel
149 * @base: memory base address for this physical channel 152 * @base: memory base address for this physical channel
150 * @reg_config: configuration address for this physical channel 153 * @reg_config: configuration address for this physical channel
154 * @reg_control: control address for this physical channel
155 * @reg_src: transfer source address register
156 * @reg_dst: transfer destination address register
157 * @reg_lli: transfer LLI address register
158 * @reg_busy: if the variant has a special per-channel busy register,
159 * this contains a pointer to it
151 * @lock: a lock to use when altering an instance of this struct 160 * @lock: a lock to use when altering an instance of this struct
152 * @serving: the virtual channel currently being served by this physical 161 * @serving: the virtual channel currently being served by this physical
153 * channel 162 * channel
154 * @locked: channel unavailable for the system, e.g. dedicated to secure 163 * @locked: channel unavailable for the system, e.g. dedicated to secure
155 * world 164 * world
165 * @ftdmac020: channel is on a FTDMAC020
166 * @pl080s: channel is on a PL08s
156 */ 167 */
157struct pl08x_phy_chan { 168struct pl08x_phy_chan {
158 unsigned int id; 169 unsigned int id;
159 void __iomem *base; 170 void __iomem *base;
160 void __iomem *reg_config; 171 void __iomem *reg_config;
172 void __iomem *reg_control;
173 void __iomem *reg_src;
174 void __iomem *reg_dst;
175 void __iomem *reg_lli;
176 void __iomem *reg_busy;
161 spinlock_t lock; 177 spinlock_t lock;
162 struct pl08x_dma_chan *serving; 178 struct pl08x_dma_chan *serving;
163 bool locked; 179 bool locked;
180 bool ftdmac020;
181 bool pl080s;
164}; 182};
165 183
166/** 184/**
@@ -362,10 +380,24 @@ static int pl08x_phy_channel_busy(struct pl08x_phy_chan *ch)
362{ 380{
363 unsigned int val; 381 unsigned int val;
364 382
383 /* If we have a special busy register, take a shortcut */
384 if (ch->reg_busy) {
385 val = readl(ch->reg_busy);
386 return !!(val & BIT(ch->id));
387 }
365 val = readl(ch->reg_config); 388 val = readl(ch->reg_config);
366 return val & PL080_CONFIG_ACTIVE; 389 return val & PL080_CONFIG_ACTIVE;
367} 390}
368 391
392/*
393 * pl08x_write_lli() - Write an LLI into the DMA controller.
394 *
395 * The PL08x derivatives support linked lists, but the first item of the
396 * list containing the source, destination, control word and next LLI is
397 * ignored. Instead the driver has to write those values directly into the
398 * SRC, DST, LLI and control registers. On FTDMAC020 also the SIZE
399 * register need to be set up for the first transfer.
400 */
369static void pl08x_write_lli(struct pl08x_driver_data *pl08x, 401static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
370 struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg) 402 struct pl08x_phy_chan *phychan, const u32 *lli, u32 ccfg)
371{ 403{
@@ -383,11 +415,112 @@ static void pl08x_write_lli(struct pl08x_driver_data *pl08x,
383 phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST], 415 phychan->id, lli[PL080_LLI_SRC], lli[PL080_LLI_DST],
384 lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg); 416 lli[PL080_LLI_LLI], lli[PL080_LLI_CCTL], ccfg);
385 417
386 writel_relaxed(lli[PL080_LLI_SRC], phychan->base + PL080_CH_SRC_ADDR); 418 writel_relaxed(lli[PL080_LLI_SRC], phychan->reg_src);
387 writel_relaxed(lli[PL080_LLI_DST], phychan->base + PL080_CH_DST_ADDR); 419 writel_relaxed(lli[PL080_LLI_DST], phychan->reg_dst);
388 writel_relaxed(lli[PL080_LLI_LLI], phychan->base + PL080_CH_LLI); 420 writel_relaxed(lli[PL080_LLI_LLI], phychan->reg_lli);
389 writel_relaxed(lli[PL080_LLI_CCTL], phychan->base + PL080_CH_CONTROL);
390 421
422 /*
423 * The FTMAC020 has a different layout in the CCTL word of the LLI
424 * and the CCTL register which is split in CSR and SIZE registers.
425 * Convert the LLI item CCTL into the proper values to write into
426 * the CSR and SIZE registers.
427 */
428 if (phychan->ftdmac020) {
429 u32 llictl = lli[PL080_LLI_CCTL];
430 u32 val = 0;
431
432 /* Write the transfer size (12 bits) to the size register */
433 writel_relaxed(llictl & FTDMAC020_LLI_TRANSFER_SIZE_MASK,
434 phychan->base + FTDMAC020_CH_SIZE);
435 /*
436 * Then write the control bits 28..16 to the control register
437 * by shuffleing the bits around to where they are in the
438 * main register. The mapping is as follows:
439 * Bit 28: TC_MSK - mask on all except last LLI
440 * Bit 27..25: SRC_WIDTH
441 * Bit 24..22: DST_WIDTH
442 * Bit 21..20: SRCAD_CTRL
443 * Bit 19..17: DSTAD_CTRL
444 * Bit 17: SRC_SEL
445 * Bit 16: DST_SEL
446 */
447 if (llictl & FTDMAC020_LLI_TC_MSK)
448 val |= FTDMAC020_CH_CSR_TC_MSK;
449 val |= ((llictl & FTDMAC020_LLI_SRC_WIDTH_MSK) >>
450 (FTDMAC020_LLI_SRC_WIDTH_SHIFT -
451 FTDMAC020_CH_CSR_SRC_WIDTH_SHIFT));
452 val |= ((llictl & FTDMAC020_LLI_DST_WIDTH_MSK) >>
453 (FTDMAC020_LLI_DST_WIDTH_SHIFT -
454 FTDMAC020_CH_CSR_DST_WIDTH_SHIFT));
455 val |= ((llictl & FTDMAC020_LLI_SRCAD_CTL_MSK) >>
456 (FTDMAC020_LLI_SRCAD_CTL_SHIFT -
457 FTDMAC020_CH_CSR_SRCAD_CTL_SHIFT));
458 val |= ((llictl & FTDMAC020_LLI_DSTAD_CTL_MSK) >>
459 (FTDMAC020_LLI_DSTAD_CTL_SHIFT -
460 FTDMAC020_CH_CSR_DSTAD_CTL_SHIFT));
461 if (llictl & FTDMAC020_LLI_SRC_SEL)
462 val |= FTDMAC020_CH_CSR_SRC_SEL;
463 if (llictl & FTDMAC020_LLI_DST_SEL)
464 val |= FTDMAC020_CH_CSR_DST_SEL;
465
466 /*
467 * Set up the bits that exist in the CSR but are not
468 * part the LLI, i.e. only gets written to the control
469 * register right here.
470 *
471 * FIXME: do not just handle memcpy, also handle slave DMA.
472 */
473 switch (pl08x->pd->memcpy_burst_size) {
474 default:
475 case PL08X_BURST_SZ_1:
476 val |= PL080_BSIZE_1 <<
477 FTDMAC020_CH_CSR_SRC_SIZE_SHIFT;
478 break;
479 case PL08X_BURST_SZ_4: