298 lines
12 KiB
C
298 lines
12 KiB
C
/*
|
|
* 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
|