diff options
author | Laxman Dewangan <ldewangan@nvidia.com> | 2013-04-06 21:04:08 +0530 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2013-09-14 13:17:41 -0700 |
commit | 0184f29bdf2ee4a9658256ef81afdf0d51964ffe (patch) | |
tree | 0263ffcf91064faca331d714b4e7516cafca7e0b /drivers/dma | |
parent | 930099077848ffa494f397287bf3d407fc8a71c3 (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.c | 69 |
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) { |