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