| 1 | /* SPDX-License-Identifier: GPL-2.0 */ |
| 2 | /* |
| 3 | * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates. |
| 4 | * Synopsys DesignWare eDMA core driver |
| 5 | * |
| 6 | * Author: Gustavo Pimentel <gustavo.pimentel@synopsys.com> |
| 7 | */ |
| 8 | |
| 9 | #ifndef _DW_EDMA_CORE_H |
| 10 | #define _DW_EDMA_CORE_H |
| 11 | |
| 12 | #include <linux/msi.h> |
| 13 | #include <linux/dma/edma.h> |
| 14 | |
| 15 | #include "../virt-dma.h" |
| 16 | |
| 17 | #define EDMA_LL_SZ 24 |
| 18 | |
| 19 | enum dw_edma_dir { |
| 20 | EDMA_DIR_WRITE = 0, |
| 21 | EDMA_DIR_READ |
| 22 | }; |
| 23 | |
| 24 | enum dw_edma_request { |
| 25 | EDMA_REQ_NONE = 0, |
| 26 | EDMA_REQ_STOP, |
| 27 | EDMA_REQ_PAUSE |
| 28 | }; |
| 29 | |
| 30 | enum dw_edma_status { |
| 31 | EDMA_ST_IDLE = 0, |
| 32 | EDMA_ST_PAUSE, |
| 33 | EDMA_ST_BUSY |
| 34 | }; |
| 35 | |
| 36 | enum dw_edma_xfer_type { |
| 37 | EDMA_XFER_SCATTER_GATHER = 0, |
| 38 | EDMA_XFER_CYCLIC, |
| 39 | EDMA_XFER_INTERLEAVED |
| 40 | }; |
| 41 | |
| 42 | struct dw_edma_chan; |
| 43 | struct dw_edma_chunk; |
| 44 | |
| 45 | struct dw_edma_burst { |
| 46 | struct list_head list; |
| 47 | u64 sar; |
| 48 | u64 dar; |
| 49 | u32 sz; |
| 50 | }; |
| 51 | |
| 52 | struct dw_edma_chunk { |
| 53 | struct list_head list; |
| 54 | struct dw_edma_chan *chan; |
| 55 | struct dw_edma_burst *burst; |
| 56 | |
| 57 | u32 bursts_alloc; |
| 58 | |
| 59 | u8 cb; |
| 60 | struct dw_edma_region ll_region; /* Linked list */ |
| 61 | }; |
| 62 | |
| 63 | struct dw_edma_desc { |
| 64 | struct virt_dma_desc vd; |
| 65 | struct dw_edma_chan *chan; |
| 66 | struct dw_edma_chunk *chunk; |
| 67 | |
| 68 | u32 chunks_alloc; |
| 69 | |
| 70 | u32 alloc_sz; |
| 71 | u32 xfer_sz; |
| 72 | }; |
| 73 | |
| 74 | struct dw_edma_chan { |
| 75 | struct virt_dma_chan vc; |
| 76 | struct dw_edma *dw; |
| 77 | int id; |
| 78 | enum dw_edma_dir dir; |
| 79 | |
| 80 | u32 ll_max; |
| 81 | |
| 82 | struct msi_msg msi; |
| 83 | |
| 84 | enum dw_edma_request request; |
| 85 | enum dw_edma_status status; |
| 86 | u8 configured; |
| 87 | |
| 88 | struct dma_slave_config config; |
| 89 | }; |
| 90 | |
| 91 | struct dw_edma_irq { |
| 92 | struct msi_msg msi; |
| 93 | u32 wr_mask; |
| 94 | u32 rd_mask; |
| 95 | struct dw_edma *dw; |
| 96 | }; |
| 97 | |
| 98 | struct dw_edma { |
| 99 | char name[32]; |
| 100 | |
| 101 | struct dma_device dma; |
| 102 | |
| 103 | u16 wr_ch_cnt; |
| 104 | u16 rd_ch_cnt; |
| 105 | |
| 106 | struct dw_edma_irq *irq; |
| 107 | int nr_irqs; |
| 108 | |
| 109 | struct dw_edma_chan *chan; |
| 110 | |
| 111 | raw_spinlock_t lock; /* Only for legacy */ |
| 112 | |
| 113 | struct dw_edma_chip *chip; |
| 114 | |
| 115 | const struct dw_edma_core_ops *core; |
| 116 | }; |
| 117 | |
| 118 | typedef void (*dw_edma_handler_t)(struct dw_edma_chan *); |
| 119 | |
| 120 | struct dw_edma_core_ops { |
| 121 | void (*off)(struct dw_edma *dw); |
| 122 | u16 (*ch_count)(struct dw_edma *dw, enum dw_edma_dir dir); |
| 123 | enum dma_status (*ch_status)(struct dw_edma_chan *chan); |
| 124 | irqreturn_t (*handle_int)(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, |
| 125 | dw_edma_handler_t done, dw_edma_handler_t abort); |
| 126 | void (*start)(struct dw_edma_chunk *chunk, bool first); |
| 127 | void (*ch_config)(struct dw_edma_chan *chan); |
| 128 | void (*debugfs_on)(struct dw_edma *dw); |
| 129 | }; |
| 130 | |
| 131 | struct dw_edma_sg { |
| 132 | struct scatterlist *sgl; |
| 133 | unsigned int len; |
| 134 | }; |
| 135 | |
| 136 | struct dw_edma_cyclic { |
| 137 | dma_addr_t paddr; |
| 138 | size_t len; |
| 139 | size_t cnt; |
| 140 | }; |
| 141 | |
| 142 | struct dw_edma_transfer { |
| 143 | struct dma_chan *dchan; |
| 144 | union dw_edma_xfer { |
| 145 | struct dw_edma_sg sg; |
| 146 | struct dw_edma_cyclic cyclic; |
| 147 | struct dma_interleaved_template *il; |
| 148 | } xfer; |
| 149 | enum dma_transfer_direction direction; |
| 150 | unsigned long flags; |
| 151 | enum dw_edma_xfer_type type; |
| 152 | }; |
| 153 | |
| 154 | static inline |
| 155 | struct dw_edma_chan *vc2dw_edma_chan(struct virt_dma_chan *vc) |
| 156 | { |
| 157 | return container_of(vc, struct dw_edma_chan, vc); |
| 158 | } |
| 159 | |
| 160 | static inline |
| 161 | struct dw_edma_chan *dchan2dw_edma_chan(struct dma_chan *dchan) |
| 162 | { |
| 163 | return vc2dw_edma_chan(vc: to_virt_chan(chan: dchan)); |
| 164 | } |
| 165 | |
| 166 | static inline |
| 167 | void dw_edma_core_off(struct dw_edma *dw) |
| 168 | { |
| 169 | dw->core->off(dw); |
| 170 | } |
| 171 | |
| 172 | static inline |
| 173 | u16 dw_edma_core_ch_count(struct dw_edma *dw, enum dw_edma_dir dir) |
| 174 | { |
| 175 | return dw->core->ch_count(dw, dir); |
| 176 | } |
| 177 | |
| 178 | static inline |
| 179 | enum dma_status dw_edma_core_ch_status(struct dw_edma_chan *chan) |
| 180 | { |
| 181 | return chan->dw->core->ch_status(chan); |
| 182 | } |
| 183 | |
| 184 | static inline irqreturn_t |
| 185 | dw_edma_core_handle_int(struct dw_edma_irq *dw_irq, enum dw_edma_dir dir, |
| 186 | dw_edma_handler_t done, dw_edma_handler_t abort) |
| 187 | { |
| 188 | return dw_irq->dw->core->handle_int(dw_irq, dir, done, abort); |
| 189 | } |
| 190 | |
| 191 | static inline |
| 192 | void dw_edma_core_start(struct dw_edma *dw, struct dw_edma_chunk *chunk, bool first) |
| 193 | { |
| 194 | dw->core->start(chunk, first); |
| 195 | } |
| 196 | |
| 197 | static inline |
| 198 | void dw_edma_core_ch_config(struct dw_edma_chan *chan) |
| 199 | { |
| 200 | chan->dw->core->ch_config(chan); |
| 201 | } |
| 202 | |
| 203 | static inline |
| 204 | void dw_edma_core_debugfs_on(struct dw_edma *dw) |
| 205 | { |
| 206 | dw->core->debugfs_on(dw); |
| 207 | } |
| 208 | |
| 209 | #endif /* _DW_EDMA_CORE_H */ |
| 210 | |