diff options
author | Green Wan <green.wan@sifive.com> | 2019-11-07 11:49:21 +0300 |
---|---|---|
committer | Vinod Koul <vkoul@kernel.org> | 2019-11-14 10:10:46 +0300 |
commit | 6973886ad58e6b4988813331abb76ae0b364a9c2 (patch) | |
tree | fbd80c2cb1a27c58b89176fde037c50d7e2937b8 /drivers/dma/sf-pdma/sf-pdma.h | |
parent | fa805360f4cfa34cb3575715e1c8b4f9a253b474 (diff) | |
download | linux-6973886ad58e6b4988813331abb76ae0b364a9c2.tar.xz |
dmaengine: sf-pdma: add platform DMA support for HiFive Unleashed A00
Add PDMA driver, sf-pdma, to enable DMA engine on HiFive Unleashed
Rev A00 board.
- Implement dmaengine APIs, support MEM_TO_MEM async copy.
- Tested by DMA Test client
- Supports 4 channels DMA, each channel has 1 done and 1 err
interrupt connected to platform-level interrupt controller (PLIC).
- Depends on DMA_ENGINE and DMA_VIRTUAL_CHANNELS
The datasheet is here:
https://static.dev.sifive.com/FU540-C000-v1.0.pdf
Follow the DMAengine controller doc,
"./Documentation/driver-api/dmaengine/provider.rst" to implement DMA
engine. And use the dma test client in doc,
"./Documentation/driver-api/dmaengine/dmatest.rst", to test.
Each DMA channel has separate HW regs and support done and error ISRs.
4 channels share 1 done and 1 err ISRs. There's no expander/arbitrator
in DMA HW.
------ ------
| |--< done 23 >--|ch 0|
| |--< err 24 >--| | (dma0chan0)
| | ------
| | ------
| |--< done 25 >--|ch 1|
| |--< err 26 >--| | (dma0chan1)
|PLIC| ------
| | ------
| |--< done 27 >--|ch 2|
| |--< err 28 >--| | (dma0chan2)
| | ------
| | ------
| |--< done 29 >--|ch 3|
| |--< err 30 >--| | (dma0chan3)
------ ------
Signed-off-by: Green Wan <green.wan@sifive.com>
Link: https://lore.kernel.org/r/20191107084955.7580-4-green.wan@sifive.com
Signed-off-by: Vinod Koul <vkoul@kernel.org>
Diffstat (limited to 'drivers/dma/sf-pdma/sf-pdma.h')
-rw-r--r-- | drivers/dma/sf-pdma/sf-pdma.h | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/drivers/dma/sf-pdma/sf-pdma.h b/drivers/dma/sf-pdma/sf-pdma.h new file mode 100644 index 000000000000..55816c9e0249 --- /dev/null +++ b/drivers/dma/sf-pdma/sf-pdma.h @@ -0,0 +1,122 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/** + * SiFive FU540 Platform DMA driver + * Copyright (C) 2019 SiFive + * + * Based partially on: + * - drivers/dma/fsl-edma.c + * - drivers/dma/dw-edma/ + * - drivers/dma/pxa-dma.c + * + * See the following sources for further documentation: + * - Chapter 12 "Platform DMA Engine (PDMA)" of + * SiFive FU540-C000 v1.0 + * https://static.dev.sifive.com/FU540-C000-v1.0.pdf + */ +#ifndef _SF_PDMA_H +#define _SF_PDMA_H + +#include <linux/dmaengine.h> +#include <linux/dma-direction.h> + +#include "../dmaengine.h" +#include "../virt-dma.h" + +#define PDMA_NR_CH 4 + +#if (PDMA_NR_CH != 4) +#error "Please define PDMA_NR_CH to 4" +#endif + +#define PDMA_BASE_ADDR 0x3000000 +#define PDMA_CHAN_OFFSET 0x1000 + +/* Register Offset */ +#define PDMA_CTRL 0x000 +#define PDMA_XFER_TYPE 0x004 +#define PDMA_XFER_SIZE 0x008 +#define PDMA_DST_ADDR 0x010 +#define PDMA_SRC_ADDR 0x018 +#define PDMA_ACT_TYPE 0x104 /* Read-only */ +#define PDMA_REMAINING_BYTE 0x108 /* Read-only */ +#define PDMA_CUR_DST_ADDR 0x110 /* Read-only*/ +#define PDMA_CUR_SRC_ADDR 0x118 /* Read-only*/ + +/* CTRL */ +#define PDMA_CLEAR_CTRL 0x0 +#define PDMA_CLAIM_MASK GENMASK(0, 0) +#define PDMA_RUN_MASK GENMASK(1, 1) +#define PDMA_ENABLE_DONE_INT_MASK GENMASK(14, 14) +#define PDMA_ENABLE_ERR_INT_MASK GENMASK(15, 15) +#define PDMA_DONE_STATUS_MASK GENMASK(30, 30) +#define PDMA_ERR_STATUS_MASK GENMASK(31, 31) + +/* Transfer Type */ +#define PDMA_FULL_SPEED 0xFF000008 + +/* Error Recovery */ +#define MAX_RETRY 1 + +struct pdma_regs { + /* read-write regs */ + void __iomem *ctrl; /* 4 bytes */ + + void __iomem *xfer_type; /* 4 bytes */ + void __iomem *xfer_size; /* 8 bytes */ + void __iomem *dst_addr; /* 8 bytes */ + void __iomem *src_addr; /* 8 bytes */ + + /* read-only */ + void __iomem *act_type; /* 4 bytes */ + void __iomem *residue; /* 8 bytes */ + void __iomem *cur_dst_addr; /* 8 bytes */ + void __iomem *cur_src_addr; /* 8 bytes */ +}; + +struct sf_pdma_desc { + u32 xfer_type; + u64 xfer_size; + u64 dst_addr; + u64 src_addr; + struct virt_dma_desc vdesc; + struct sf_pdma_chan *chan; + bool in_use; + enum dma_transfer_direction dirn; + struct dma_async_tx_descriptor *async_tx; +}; + +enum sf_pdma_pm_state { + RUNNING = 0, + SUSPENDED, +}; + +struct sf_pdma_chan { + struct virt_dma_chan vchan; + enum dma_status status; + enum sf_pdma_pm_state pm_state; + u32 slave_id; + struct sf_pdma *pdma; + struct sf_pdma_desc *desc; + struct dma_slave_config cfg; + u32 attr; + dma_addr_t dma_dev_addr; + u32 dma_dev_size; + struct tasklet_struct done_tasklet; + struct tasklet_struct err_tasklet; + struct pdma_regs regs; + spinlock_t lock; /* protect chan data */ + bool xfer_err; + int txirq; + int errirq; + int retries; +}; + +struct sf_pdma { + struct dma_device dma_dev; + void __iomem *membase; + void __iomem *mappedbase; + u32 n_chans; + struct sf_pdma_chan chans[PDMA_NR_CH]; +}; + +#endif /* _SF_PDMA_H */ |