1 /*
2 * Copyright (c) 2019-2025 Allwinner Technology Co., Ltd. ALL rights reserved.
3 *
4 * Allwinner is a trademark of Allwinner Technology Co.,Ltd., registered in
5 * the the People's Republic of China and other countries.
6 * All Allwinner Technology Co.,Ltd. trademarks are used with permission.
7 *
8 * DISCLAIMER
9 * THIRD PARTY LICENCES MAY BE REQUIRED TO IMPLEMENT THE SOLUTION/PRODUCT.
10 * IF YOU NEED TO INTEGRATE THIRD PARTY¡¯S TECHNOLOGY (SONY, DTS, DOLBY, AVS OR MPEGLA, ETC.)
11 * IN ALLWINNERS¡¯SDK OR PRODUCTS, YOU SHALL BE SOLELY RESPONSIBLE TO OBTAIN
12 * ALL APPROPRIATELY REQUIRED THIRD PARTY LICENCES.
13 * ALLWINNER SHALL HAVE NO WARRANTY, INDEMNITY OR OTHER OBLIGATIONS WITH RESPECT TO MATTERS
14 * COVERED UNDER ANY REQUIRED THIRD PARTY LICENSE.
15 * YOU ARE SOLELY RESPONSIBLE FOR YOUR USAGE OF THIRD PARTY¡¯S TECHNOLOGY.
16 *
17 *
18 * THIS SOFTWARE IS PROVIDED BY ALLWINNER"AS IS" AND TO THE MAXIMUM EXTENT
19 * PERMITTED BY LAW, ALLWINNER EXPRESSLY DISCLAIMS ALL WARRANTIES OF ANY KIND,
20 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING WITHOUT LIMITATION REGARDING
21 * THE TITLE, NON-INFRINGEMENT, ACCURACY, CONDITION, COMPLETENESS, PERFORMANCE
22 * OR MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
23 * IN NO EVENT SHALL ALLWINNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS, OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 #ifndef __SUNXI_HAL_DMA_H__
33 #define __SUNXI_HAL_DMA_H__
34 
35 #include <stdint.h>
36 #include <stdbool.h>
37 #include <stdio.h>
38 
39 /*
40  * include the platform dma header file.
41  */
42 #include <dma/platform-dma.h>
43 
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
47 
48 /* #define DMA_DEBUG */
49 
50 #define HEXADECIMAL (0x10)
51 #define REG_INTERVAL (0x04)
52 #define REG_CL (0x0c)
53 
54 //TODO:move reg list to sunxiwxx.h
55 #define HIGH_CHAN       8
56 
57 #define DMA_IRQ_EN(x)       (SUNXI_DMAC_PBASE + (0x00 + ((x) << 2)))        /* Interrupt enable register */
58 #define DMA_IRQ_STAT(x)     (SUNXI_DMAC_PBASE + (0x10 + ((x) << 2)))        /* Interrupt status register */
59 #define DMA_SECURE      (SUNXI_DMAC_PBASE + 0x20)               /* DMA security register */
60 #define DMA_GATE        (SUNXI_DMAC_PBASE + 0x28)               /* DMA gating register */
61 #define DMA_MCLK_GATE       0x04
62 #define DMA_COMMON_GATE     0x02
63 #define DMA_CHAN_GATE       0x01
64 #define DMA_STAT        (SUNXI_DMAC_PBASE + 0x30)           /* DMA Status Register RO */
65 #define DMA_ENABLE(x)       (SUNXI_DMAC_PBASE + (0x100 + ((x + START_CHAN_OFFSET) << 6)))   /* Channels enable register */
66 #define DMA_PAUSE(x)        (SUNXI_DMAC_PBASE + (0x104 + ((x + START_CHAN_OFFSET) << 6)))   /* DMA Channels pause register */
67 #define DMA_LLI_ADDR(x)     (SUNXI_DMAC_PBASE + (0x108 + ((x + START_CHAN_OFFSET) << 6)))   /* Descriptor address register */
68 #define DMA_CFG(x)      (SUNXI_DMAC_PBASE + (0x10C + ((x + START_CHAN_OFFSET) << 6)))   /* Configuration register RO */
69 #define DMA_CUR_SRC(x)      (SUNXI_DMAC_PBASE + (0x110 + ((x + START_CHAN_OFFSET) << 6)))   /* Current source address RO */
70 #define DMA_CUR_DST(x)      (SUNXI_DMAC_PBASE + (0x114 + ((x + START_CHAN_OFFSET) << 6)))   /* Current destination address RO */
71 #define DMA_CNT(x)      (SUNXI_DMAC_PBASE + (0x118 + ((x + START_CHAN_OFFSET) << 6)))   /* Byte counter left register RO */
72 #define DMA_PARA(x)     (SUNXI_DMAC_PBASE + (0x11C + ((x + START_CHAN_OFFSET) << 6)))   /* Parameter register RO */
73 #define LINK_END        0xFFFFF800          /* lastest link must be 0xfffff800 */
74 
75 /* DMA mode register */
76 #define DMA_OP_MODE(x)      (SUNXI_DMAC_PBASE + (0x128 + ((x + START_CHAN_OFFSET) << 6)))   /* DMA mode register */
77 #define SRC_HS_MASK     (0x1 << 2)          /* bit 2: Source handshake mode */
78 #define DST_HS_MASK     (0x1 << 3)          /* bit 3: Destination handshake mode */
79 
80 #define SET_OP_MODE(x, val) ({  \
81         writel(val,DMA_OP_MODE(x)); \
82         })
83 
84 
85 #define SHIFT_IRQ_MASK(val, ch) ({  \
86         (ch + START_CHAN_OFFSET) >= HIGH_CHAN   \
87         ? (val) << ((ch + START_CHAN_OFFSET - HIGH_CHAN) << 2) \
88         : (val) << ((ch + START_CHAN_OFFSET) << 2); \
89         })
90 
91 #define SHIFT_PENDING_MASK(val, ch) ({  \
92         (ch + START_CHAN_OFFSET) >= HIGH_CHAN   \
93         ? (val) << ((ch + START_CHAN_OFFSET - HIGH_CHAN) << 2) \
94         : (val) << ((ch + START_CHAN_OFFSET) << 2); \
95         })
96 
97 #define IRQ_HALF        0x01            /* Half package transfer interrupt pending */
98 #define IRQ_PKG         0x02            /* One package complete interrupt pending */
99 #define IRQ_QUEUE       0x04            /* All list complete transfer interrupt pending */
100 
101 /* DMA channel configuration register */
102 /* The detail information of DMA configuration */
103 #define SRC_WIDTH(x)        ((x) << 9)
104 #define SRC_BURST(x)        ((x) << 6)
105 #define SRC_IO_MODE     (0x01 << 8)
106 #define SRC_LINEAR_MODE     (0x00 << 8)
107 #define SRC_DRQ(x)      ((x) << 0)
108 #define DST_WIDTH(x)        ((x) << 25)
109 #define DST_BURST(x)        ((x) << 22)
110 #define DST_IO_MODE     (0x01 << 24)
111 #define DST_LINEAR_MODE     (0x00 << 24)
112 #define DST_DRQ(x)      ((x) << 16)
113 #define CHAN_START      1
114 #define CHAN_STOP       0
115 #define CHAN_PAUSE      1
116 #define CHAN_RESUME     0
117 #define NORMAL_WAIT     (8 << 0)
118 
119 #define GET_SRC_DRQ(x)      ((x) & 0x000000ff)
120 #define GET_DST_DRQ(x)      ((x) & 0x00ff0000)
121 
122 struct sunxi_dma_lli {
123     uint32_t    cfg;
124     uint32_t    src;
125     uint32_t    dst;
126     uint32_t    len;
127     uint32_t    para;
128     uint32_t    p_lln;
129     struct sunxi_dma_lli *vlln;
130 };
131 
132 
133 #define sunxi_slave_id(d, s)    (((d)<<16) | (s))
134 
135 typedef void (*dma_callback)(void *param);
136 
137 /**
138  * enum dma_slave_buswidth - defines bus width of the DMA slave
139  * device, source or target buses
140  */
141 enum dma_slave_buswidth {
142     DMA_SLAVE_BUSWIDTH_UNDEFINED = 0,
143     DMA_SLAVE_BUSWIDTH_1_BYTE = 1,
144     DMA_SLAVE_BUSWIDTH_2_BYTES = 2,
145     DMA_SLAVE_BUSWIDTH_3_BYTES = 3,
146     DMA_SLAVE_BUSWIDTH_4_BYTES = 4,
147     DMA_SLAVE_BUSWIDTH_8_BYTES = 8,
148     DMA_SLAVE_BUSWIDTH_16_BYTES = 16,
149     DMA_SLAVE_BUSWIDTH_32_BYTES = 32,
150     DMA_SLAVE_BUSWIDTH_64_BYTES = 64,
151 };
152 
153 enum dma_slave_burst {
154     DMA_SLAVE_BURST_1 = 1,
155     DMA_SLAVE_BURST_4 = 4,
156     DMA_SLAVE_BURST_8 = 8,
157     DMA_SLAVE_BURST_16 = 16,
158 };
159 
160 /**
161  * enum dma_transfer_direction - dma transfer mode and direction indicator
162  * @DMA_MEM_TO_MEM: Async/Memcpy mode
163  * @DMA_MEM_TO_DEV: Slave mode & From Memory to Device
164  * @DMA_DEV_TO_MEM: Slave mode & From Device to Memory
165  * @DMA_DEV_TO_DEV: Slave mode & From Device to Device
166  */
167 enum dma_transfer_direction {
168     DMA_MEM_TO_MEM = 0,
169     DMA_MEM_TO_DEV = 1,
170     DMA_DEV_TO_MEM = 2,
171     DMA_DEV_TO_DEV = 3,
172     DMA_TRANS_NONE,
173 };
174 
175 /**
176  * enum dma_status - DMA transaction status
177  * @DMA_COMPLETE: transaction completed
178  * @DMA_IN_PROGRESS: transaction not yet processed
179  * @DMA_PAUSED: transaction is paused
180  * @DMA_ERROR: transaction failed
181  */
182 enum dma_status {
183     DMA_INVALID_PARAMETER = -2,
184     DMA_ERROR = -1,
185     DMA_COMPLETE,
186     DMA_IN_PROGRESS,
187     DMA_PAUSED,
188 };
189 
190 /**
191  * struct dma_slave_config - dma slave channel runtime config
192  * @direction: whether the data shall go in or out on this slave
193  * channel, right now. DMA_MEM_TO_DEV and DMA_DEV_TO_MEM are
194  * legal values. DEPRECATED, drivers should use the direction argument
195  * to the device_prep_slave_sg and device_prep_dma_cyclic functions or
196  * the dir field in the dma_interleaved_template structure.
197  * @src_addr: this is the physical address where DMA slave data
198  * should be read (RX), if the source is memory this argument is
199  * ignored.
200  * @dst_addr: this is the physical address where DMA slave data
201  * should be written (TX), if the source is memory this argument
202  * is ignored.
203  * @src_addr_width: this is the width in bytes of the source (RX)
204  * register where DMA data shall be read. If the source
205  * is memory this may be ignored depending on architecture.
206  * Legal values: 1, 2, 4, 8.
207  * @dst_addr_width: same as src_addr_width but for destination
208  * target (TX) mutatis mutandis.
209  * @src_maxburst: the maximum number of words (note: words, as in
210  * units of the src_addr_width member, not bytes) that can be sent
211  * in one burst to the device. Typically something like half the
212  * FIFO depth on I/O peripherals so you don't overflow it. This
213  * may or may not be applicable on memory sources.
214  * @dst_maxburst: same as src_maxburst but for destination target
215  * mutatis mutandis.
216  * @slave_id: Slave requester id. Only valid for slave channels. The dma
217  * slave peripheral will have unique id as dma requester which need to be
218  * pass as slave config.
219  *
220  * This struct is passed in as configuration data to a DMA engine
221  * in order to set up a certain channel for DMA transport at runtime.
222  * The DMA device/engine has to provide support for an additional
223  * callback in the dma_device structure, device_config and this struct
224  * will then be passed in as an argument to the function.
225  *
226  * The rationale for adding configuration information to this struct is as
227  * follows: if it is likely that more than one DMA slave controllers in
228  * the world will support the configuration option, then make it generic.
229  * If not: if it is fixed so that it be sent in static from the platform
230  * data, then prefer to do that.
231  */
232 struct dma_slave_config {
233     enum dma_transfer_direction direction;
234     unsigned long src_addr;
235     unsigned long dst_addr;
236     enum dma_slave_buswidth src_addr_width;
237     enum dma_slave_buswidth dst_addr_width;
238     uint32_t src_maxburst;
239     uint32_t dst_maxburst;
240     uint32_t slave_id;
241 };
242 
243 struct sunxi_dma_chan {
244     uint8_t used:1;
245     uint8_t chan_count:4;
246     bool    cyclic:1;
247     struct dma_slave_config  cfg;
248     uint32_t periods_pos;
249     uint32_t buf_len;
250     struct sunxi_dma_lli *desc;
251     uint32_t    irq_type;
252     dma_callback callback;
253     void *callback_param;
254     /* volatile kspinlock_t lock; */
255     volatile int lock;
256 };
257 
258 /** This enum defines the DMA CHANNEL status. */
259 typedef enum {
260     HAL_DMA_CHAN_STATUS_BUSY  = 0,              /* DMA channel status busy */
261     HAL_DMA_CHAN_STATUS_FREE = 1               /* DMA channel status free */
262 } hal_dma_chan_status_t;
263 
264 /** This enum defines the return type of GPIO API. */
265 typedef enum {
266     HAL_DMA_STATUS_INVALID_PARAMETER    = -22,      /* Invalid input parameter. */
267     HAL_DMA_STATUS_NO_MEM           = -12,      /* No memory. */
268     HAL_DMA_STATUS_ERR_PERM         = -1,       /* Operation not permitted. */
269     HAL_DMA_STATUS_OK           = 0     /* The DMA status ok. */
270 } hal_dma_status_t;
271 
272 
273 hal_dma_chan_status_t hal_dma_chan_request(struct sunxi_dma_chan **dma_chan);
274 hal_dma_status_t hal_dma_prep_memcpy(struct sunxi_dma_chan *chan,
275                        uint32_t dest, uint32_t src, uint32_t len);
276 hal_dma_status_t hal_dma_prep_device(struct sunxi_dma_chan *chan,
277                        uint32_t dest, uint32_t src,
278                        uint32_t len, enum dma_transfer_direction dir);
279 hal_dma_status_t hal_dma_prep_cyclic(struct sunxi_dma_chan *chan,
280                      uint32_t buf_addr, uint32_t buf_len,
281                      uint32_t period_len, enum dma_transfer_direction dir);
282 hal_dma_status_t hal_dma_callback_install(struct sunxi_dma_chan *chan,
283                       dma_callback callback,
284                       void *callback_param);
285 hal_dma_status_t hal_dma_slave_config(struct sunxi_dma_chan *chan, struct dma_slave_config *config);
286 enum dma_status hal_dma_tx_status(struct sunxi_dma_chan *chan, uint32_t *left_size);
287 hal_dma_status_t hal_dma_start(struct sunxi_dma_chan *chan);
288 hal_dma_status_t hal_dma_stop(struct sunxi_dma_chan *chan);
289 hal_dma_status_t hal_dma_chan_free(struct sunxi_dma_chan *chan);
290 hal_dma_status_t hal_dma_chan_desc_free(struct sunxi_dma_chan *chan);
291 void hal_dma_init(void);
292 
293 #ifdef __cplusplus
294 }
295 #endif
296 
297 #endif
298