| /* SPDX-License-Identifier: GPL-2.0 */ |
| /* |
| * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates. |
| * Synopsys DesignWare eDMA core driver |
| * |
| * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com> |
| */ |
| |
| #ifndef _DW_EDMA_CORE_H |
| #define _DW_EDMA_CORE_H |
| |
| #include <linux/msi.h> |
| #include <linux/dma/edma.h> |
| |
| #include "../virt-dma.h" |
| |
| #define EDMA_LL_SZ 24 |
| |
| enum dw_edma_dir { |
| EDMA_DIR_WRITE = 0, |
| EDMA_DIR_READ |
| }; |
| |
| enum dw_edma_request { |
| EDMA_REQ_NONE = 0, |
| EDMA_REQ_STOP, |
| EDMA_REQ_PAUSE |
| }; |
| |
| enum dw_edma_status { |
| EDMA_ST_IDLE = 0, |
| EDMA_ST_PAUSE, |
| EDMA_ST_BUSY |
| }; |
| |
| enum dw_edma_xfer_type { |
| EDMA_XFER_SCATTER_GATHER = 0, |
| EDMA_XFER_CYCLIC, |
| EDMA_XFER_INTERLEAVED |
| }; |
| |
| struct dw_edma_chan; |
| struct dw_edma_chunk; |
| |
| struct dw_edma_burst { |
| struct list_head list; |
| u64 sar; |
| u64 dar; |
| u32 sz; |
| }; |
| |
| struct dw_edma_chunk { |
| struct list_head list; |
| struct dw_edma_chan *chan; |
| struct dw_edma_burst *burst; |
| |
| u32 bursts_alloc; |
| |
| u8 cb; |
| struct dw_edma_region ll_region; /* Linked list */ |
| }; |
| |
| struct dw_edma_desc { |
| struct virt_dma_desc vd; |
| struct dw_edma_chan *chan; |
| struct dw_edma_chunk *chunk; |
| |
| u32 chunks_alloc; |
| |
| u32 alloc_sz; |
| u32 xfer_sz; |
| }; |
| |
| struct dw_edma_chan { |
| struct virt_dma_chan vc; |
| struct dw_edma *dw; |
| int id; |
| enum dw_edma_dir dir; |
| |
| u32 ll_max; |
| |
| struct msi_msg msi; |
| |
| enum dw_edma_request request; |
| enum dw_edma_status status; |
| u8 configured; |
| |
| struct dma_slave_config config; |
| }; |
| |
| struct dw_edma_irq { |
| struct msi_msg msi; |
| u32 wr_mask; |
| u32 rd_mask; |
| struct dw_edma *dw; |
| }; |
| |
| struct dw_edma { |
| char name[32]; |
| |
| struct dma_device dma; |
| |
| u16 wr_ch_cnt; |
| u16 rd_ch_cnt; |
| |
| struct dw_edma_irq *irq; |
| int nr_irqs; |
| |
| struct dw_edma_chan *chan; |
| |
| raw_spinlock_t lock; /* Only for legacy */ |
| |
| struct dw_edma_chip *chip; |
| |
| const struct dw_edma_core_ops *core; |
| }; |
| |
| typedef void (*dw_edma_handler_t)(struct dw_edma_chan *); |
| |
| struct dw_edma_core_ops { |
| void (*off)(struct dw_edma *dw); |
| u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir); |
| enum dma_status (*ch_status)(struct dw_edma_chan *chan); |
| irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, |
| dw_edma_handler_t done, dw_edma_handler_t abort); |
| void (*start)(struct dw_edma_chunk *chunk, bool first); |
| void (*ch_config)(struct dw_edma_chan *chan); |
| void (*debugfs_on)(struct dw_edma *dw); |
| }; |
| |
| struct dw_edma_sg { |
| struct scatterlist *sgl; |
| unsigned int len; |
| }; |
| |
| struct dw_edma_cyclic { |
| dma_addr_t paddr; |
| size_t len; |
| size_t cnt; |
| }; |
| |
| struct dw_edma_transfer { |
| struct dma_chan *dchan; |
| union dw_edma_xfer { |
| struct dw_edma_sg sg; |
| struct dw_edma_cyclic cyclic; |
| struct dma_interleaved_template *il; |
| } xfer; |
| enum dma_transfer_direction direction; |
| unsigned long flags; |
| enum dw_edma_xfer_type type; |
| }; |
| |
| static inline |
| struct dw_edma_chan *vc2dw_edma_chan(struct virt_dma_chan *vc) |
| { |
| return container_of(vc, struct dw_edma_chan, vc); |
| } |
| |
| static inline |
| struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan) |
| { |
| return vc2dw_edma_chan(to_virt_chan(dchan)); |
| } |
| |
| static inline |
| void dw_edma_core_off(struct dw_edma *dw) |
| { |
| dw->core->off(dw); |
| } |
| |
| static inline |
| u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) |
| { |
| return dw->core->ch_count(dw, dir); |
| } |
| |
| static inline |
| enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan) |
| { |
| return chan->dw->core->ch_status(chan); |
| } |
| |
| static inline irqreturn_t |
| dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, |
| dw_edma_handler_t done, dw_edma_handler_t abort) |
| { |
| return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort); |
| } |
| |
| static inline |
| void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first) |
| { |
| dw->core->start(chunk, first); |
| } |
| |
| static inline |
| void dw_edma_core_ch_config(struct dw_edma_chan *chan) |
| { |
| chan->dw->core->ch_config(chan); |
| } |
| |
| static inline |
| void dw_edma_core_debugfs_on(struct dw_edma *dw) |
| { |
| dw->core->debugfs_on(dw); |
| } |
| |
| #endif /* _DW_EDMA_CORE_H */ |