summaryrefslogtreecommitdiff
path: root/drivers/dma
diff options
context:
space:
mode:
authorLaxman Dewangan <ldewangan@nvidia.com>2013-04-06 21:04:08 +0530
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:17:41 -0700
commit0184f29bdf2ee4a9658256ef81afdf0d51964ffe (patch)
tree0263ffcf91064faca331d714b4e7516cafca7e0b /drivers/dma
parent930099077848ffa494f397287bf3d407fc8a71c3 (diff)
dma: tegra: add support for t148
Add support for T148 APB DMA on dmaengine based DMA driver. Bug 1323171 Change-Id: I1df5812fb8e52019e5705778efc0d3b0356f9340 Signed-off-by: Laxman Dewangan <ldewangan@nvidia.com> (cherry picked from commit 39ae7d034fef443edc57452dafd4f6c24dadfe6c) Signed-off-by: Ajay Nandakumar <anandakumarm@nvidia.com> Reviewed-on: http://git-master/r/247132 Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Dan Willemsen <dwillemsen@nvidia.com> Tested-by: Dan Willemsen <dwillemsen@nvidia.com>
Diffstat (limited to 'drivers/dma')
-rw-r--r--drivers/dma/tegra20-apb-dma.c69
1 files changed, 62 insertions, 7 deletions
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index f6b7e356c1a3..f1a2dba11a64 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -100,6 +100,16 @@
#define TEGRA_APBDMA_APBSEQ_DATA_SWAP BIT(27)
#define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1 (1 << 16)
+
+/* T148 specific change */
+#define TEGRA_APBDMA_CHAN_WCOUNT 0x20
+#define TEGRA_APBDMA_WCOUNT_WCOUNT_SHIFT 2
+#define TEGRA_APBDMA_WCOUNT_WCOUNT_MASK 0xFFFFFFFC
+
+#define TEGRA_APBDMA_CHAN_WORD_TRANSFER 0x24
+#define TEGRA_APBDMA_WORD_TRANSFER_WXFER_SHIFT 2
+#define TEGRA_APBDMA_WORD_TRANSFER_WXFER_MASK 0xFFFC
+
/*
* If any burst is in flight and DMA paused then this is the time to complete
* on-flight burst and update DMA status register.
@@ -109,21 +119,22 @@
/* Channel base address offset from APBDMA base address */
#define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET 0x1000
-/* DMA channel register space size */
-#define TEGRA_APBDMA_CHANNEL_REGISTER_SIZE 0x20
-
struct tegra_dma;
/*
* tegra_dma_chip_data Tegra chip specific DMA data
* @nr_channels: Number of channels available in the controller.
+ * @channel_reg_size: Channel register size.
* @max_dma_count: Maximum DMA transfer count supported by DMA controller.
* @support_channel_pause: Support channel wise pause of dma.
+ * support_separate_wcount_reg: Support separate word count register.
*/
struct tegra_dma_chip_data {
int nr_channels;
+ int channel_reg_size;
int max_dma_count;
bool support_channel_pause;
+ bool support_separate_wcount_reg;
};
/* DMA channel registers */
@@ -133,6 +144,7 @@ struct tegra_dma_channel_regs {
unsigned long apb_ptr;
unsigned long ahb_seq;
unsigned long apb_seq;
+ unsigned long wcount;
};
/*
@@ -417,6 +429,10 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc,
{
struct tegra_dma_channel_regs *ch_regs = &sg_req->ch_regs;
+ if (tdc->tdma->chip_data->support_separate_wcount_reg) {
+ tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, ch_regs->wcount);
+ tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, 0);
+ }
tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR, ch_regs->csr);
tdc_write(tdc, TEGRA_APBDMA_CHAN_APBSEQ, ch_regs->apb_seq);
tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr);
@@ -461,6 +477,9 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc,
/* Safe to program new configuration */
tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr);
tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr);
+ if (tdc->tdma->chip_data->support_separate_wcount_reg)
+ tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT,
+ nsg_req->ch_regs.wcount);
tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR,
nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB);
nsg_req->configured = true;
@@ -652,6 +671,7 @@ static irqreturn_t tegra_dma_isr(int irq, void *dev_id)
status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, status);
+ tdc_write(tdc, TEGRA_APBDMA_CHAN_STATUS, TEGRA_APBDMA_STATUS_ISE_EOC);
tdc->isr_handler(tdc, false);
tasklet_schedule(&tdc->tasklet);
spin_unlock_irqrestore(&tdc->lock, flags);
@@ -714,6 +734,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
struct tegra_dma_desc *dma_desc;
unsigned long flags;
unsigned long status;
+ unsigned long wcount = 0;
bool was_busy;
spin_lock_irqsave(&tdc->lock, flags);
@@ -729,10 +750,14 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
tegra_dma_pause(tdc, true);
status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+ if (tdc->tdma->chip_data->support_separate_wcount_reg)
+ wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER);
if (status & TEGRA_APBDMA_STATUS_ISE_EOC) {
dev_dbg(tdc2dev(tdc), "%s():handling isr\n", __func__);
tdc->isr_handler(tdc, true);
status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
+ if (tdc->tdma->chip_data->support_separate_wcount_reg)
+ wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER);
}
was_busy = tdc->busy;
@@ -741,8 +766,10 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
if (!list_empty(&tdc->pending_sg_req) && was_busy) {
sgreq = list_first_entry(&tdc->pending_sg_req,
typeof(*sgreq), node);
+ if (!tdc->tdma->chip_data->support_separate_wcount_reg)
+ wcount = status;
sgreq->dma_desc->bytes_transferred +=
- get_current_xferred_count(tdc, sgreq, status);
+ get_current_xferred_count(tdc, sgreq, wcount);
}
tegra_dma_resume(tdc);
@@ -989,7 +1016,12 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
sg_req->ch_regs.apb_ptr = apb_ptr;
sg_req->ch_regs.ahb_ptr = mem;
- sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+ if (tdc->tdma->chip_data->support_separate_wcount_reg) {
+ sg_req->ch_regs.wcount = (len - 4) & 0xFFFC;
+ sg_req->ch_regs.csr = csr;
+ } else {
+ sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+ }
sg_req->ch_regs.apb_seq = apb_seq;
sg_req->ch_regs.ahb_seq = ahb_seq;
sg_req->configured = false;
@@ -1118,7 +1150,12 @@ struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
sg_req->ch_regs.apb_ptr = apb_ptr;
sg_req->ch_regs.ahb_ptr = mem;
- sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+ if (tdc->tdma->chip_data->support_separate_wcount_reg) {
+ sg_req->ch_regs.wcount = (len - 4) & 0xFFFC;
+ sg_req->ch_regs.csr = csr;
+ } else {
+ sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+ }
sg_req->ch_regs.apb_seq = apb_seq;
sg_req->ch_regs.ahb_seq = ahb_seq;
sg_req->configured = false;
@@ -1212,28 +1249,46 @@ static void tegra_dma_free_chan_resources(struct dma_chan *dc)
/* Tegra20 specific DMA controller information */
static const struct tegra_dma_chip_data tegra20_dma_chip_data = {
.nr_channels = 16,
+ .channel_reg_size = 0x20,
.max_dma_count = 1024UL * 64,
.support_channel_pause = false,
+ .support_separate_wcount_reg = false,
};
#if defined(CONFIG_OF)
/* Tegra30 specific DMA controller information */
static const struct tegra_dma_chip_data tegra30_dma_chip_data = {
.nr_channels = 32,
+ .channel_reg_size = 0x20,
.max_dma_count = 1024UL * 64,
.support_channel_pause = false,
+ .support_separate_wcount_reg = false,
};
/* Tegra114 specific DMA controller information */
static const struct tegra_dma_chip_data tegra114_dma_chip_data = {
.nr_channels = 32,
+ .channel_reg_size = 0x20,
.max_dma_count = 1024UL * 64,
.support_channel_pause = true,
+ .support_separate_wcount_reg = false,
+};
+
+/* Tegra148 specific DMA controller information */
+static const struct tegra_dma_chip_data tegra148_dma_chip_data = {
+ .nr_channels = 32,
+ .channel_reg_size = 0x40,
+ .max_dma_count = 1024UL * 64,
+ .support_channel_pause = true,
+ .support_separate_wcount_reg = true,
};
static const struct of_device_id tegra_dma_of_match[] = {
{
+ .compatible = "nvidia,tegra148-apbdma",
+ .data = &tegra148_dma_chip_data,
+ }, {
.compatible = "nvidia,tegra114-apbdma",
.data = &tegra114_dma_chip_data,
}, {
@@ -1334,7 +1389,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
struct tegra_dma_channel *tdc = &tdma->channels[i];
tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET +
- i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE;
+ i * cdata->channel_reg_size;
res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
if (!res) {