1
0
mirror of git://projects.qi-hardware.com/openwrt-xburst.git synced 2025-04-21 12:27:27 +03:00

jz4740: new dma api. cleanup audio pcm module

This commit is contained in:
Lars-Peter Clausen
2010-01-05 03:18:01 +01:00
parent 9d14f68289
commit 5ae0421a75
5 changed files with 473 additions and 1553 deletions

View File

@@ -15,251 +15,75 @@
#ifndef __ASM_JZ4740_DMA_H__
#define __ASM_JZ4740_DMA_H__
#include <linux/interrupt.h>
#include <asm/io.h> /* need byte IO */
#include <linux/spinlock.h> /* And spinlocks */
#include <linux/delay.h>
#include <asm/mach-jz4740/regs.h>
#include <asm/mach-jz4740/ops.h>
struct jz4740_dma_chan;
/*
* Descriptor structure for JZ4740 DMA engine
* Note: this structure must always be aligned to a 16-bytes boundary.
*/
typedef struct {
volatile u32 dcmd; /* DCMD value for the current transfer */
volatile u32 dsadr; /* DSAR value for the current transfer */
volatile u32 dtadr; /* DTAR value for the current transfer */
volatile u32 ddadr; /* Points to the next descriptor + transfer count */
} jz_dma_desc;
/* DMA Device ID's follow */
enum {
DMA_ID_UART0_TX = 0,
DMA_ID_UART0_RX,
DMA_ID_SSI_TX,
DMA_ID_SSI_RX,
DMA_ID_AIC_TX,
DMA_ID_AIC_RX,
DMA_ID_MSC_TX,
DMA_ID_MSC_RX,
DMA_ID_TCU_OVERFLOW,
DMA_ID_AUTO,
DMA_ID_RAW_SET,
DMA_ID_MAX
enum jz4740_dma_request_type {
JZ4740_DMA_TYPE_AUTO_REQUEST = 8,
JZ4740_DMA_TYPE_UART_TRANSMIT = 20,
JZ4740_DMA_TYPE_UART_RECEIVE = 21,
JZ4740_DMA_TYPE_SPI_TRANSMIT = 22,
JZ4740_DMA_TYPE_SPI_RECEIVE = 23,
JZ4740_DMA_TYPE_AIC_TRANSMIT = 24,
JZ4740_DMA_TYPE_AIC_RECEIVE = 25,
JZ4740_DMA_TYPE_MMC_TRANSMIT = 26,
JZ4740_DMA_TYPE_MMC_RECEIVE = 27,
JZ4740_DMA_TYPE_TCU = 28,
JZ4740_DMA_TYPE_SADC = 29,
JZ4740_DMA_TYPE_SLCD = 30,
};
/* DMA modes, simulated by sw */
#define DMA_MODE_READ 0x0 /* I/O to memory, no autoinit, increment, single mode */
#define DMA_MODE_WRITE 0x1 /* memory to I/O, no autoinit, increment, single mode */
#define DMA_AUTOINIT 0x2
#define DMA_MODE_MASK 0x3
struct jz_dma_chan {
int dev_id; /* DMA ID: this channel is allocated if >=0, free otherwise */
unsigned int io; /* DMA channel number */
const char *dev_str; /* string describes the DMA channel */
int irq; /* DMA irq number */
void *irq_dev; /* DMA private device structure */
unsigned int fifo_addr; /* physical fifo address of the requested device */
unsigned int cntl; /* DMA controll */
unsigned int mode; /* DMA configuration */
unsigned int source; /* DMA request source */
enum jz4740_dma_width {
JZ4740_DMA_WIDTH_8BIT,
JZ4740_DMA_WIDTH_16BIT,
JZ4740_DMA_WIDTH_32BIT,
};
extern struct jz_dma_chan jz_dma_table[];
enum jz4740_dma_transfer_size {
JZ4740_DMA_TRANSFER_SIZE_4BYTE = 0,
JZ4740_DMA_TRANSFER_SIZE_1BYTE = 1,
JZ4740_DMA_TRANSFER_SIZE_2BYTE = 2,
JZ4740_DMA_TRANSFER_SIZE_16BYTE = 3,
JZ4740_DMA_TRANSFER_SIZE_32BYTE = 4,
};
enum jz4740_dma_flags {
JZ4740_DMA_SRC_AUTOINC = 0x2,
JZ4740_DMA_DST_AUTOINC = 0x1,
};
enum jz4740_dma_mode {
JZ4740_DMA_MODE_SINGLE = 0,
JZ4740_DMA_MODE_BLOCK = 1,
};
struct jz4740_dma_config {
enum jz4740_dma_width src_width;
enum jz4740_dma_width dst_width;
enum jz4740_dma_transfer_size transfer_size;
enum jz4740_dma_request_type request_type;
enum jz4740_dma_flags flags;
enum jz4740_dma_mode mode;
};
typedef void (*jz4740_dma_complete_callback_t)(struct jz4740_dma_chan *, int , void *);
struct jz4740_dma_chan* jz4740_dma_request(void *dev, const char *name);
void jz4740_dma_free(struct jz4740_dma_chan *dma);
void jz4740_dma_configure(struct jz4740_dma_chan *dma,
const struct jz4740_dma_config *config);
#define DMA_8BIT_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
void jz4740_dma_enable(struct jz4740_dma_chan *dma);
void jz4740_dma_disable(struct jz4740_dma_chan *dma);
#define DMA_8BIT_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
DMAC_DCMD_DS_8BIT | DMAC_DCMD_RDIL_IGN
void jz4740_dma_set_src_addr(struct jz4740_dma_chan *dma, dma_addr_t src);
void jz4740_dma_set_dst_addr(struct jz4740_dma_chan *dma, dma_addr_t dst);
void jz4740_dma_set_transfer_count(struct jz4740_dma_chan *dma, uint32_t count);
#define DMA_16BIT_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
uint32_t jz4740_dma_get_residue(const struct jz4740_dma_chan *dma);
#define DMA_16BIT_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_16 | \
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
#define DMA_32BIT_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
#define DMA_32BIT_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_32BIT | DMAC_DCMD_RDIL_IGN
#define DMA_16BYTE_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_16BYTE_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_32BYTE_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_8 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_32BYTE_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_8 | \
DMAC_DCMD_DS_32BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_32_16BYTE_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_32_16BYTE_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_32 | DMAC_DCMD_DWDH_32 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_16BIT_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_16BIT_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
DMAC_DCMD_DS_16BIT | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_16BYTE_RX_CMD \
DMAC_DCMD_DAI | \
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
#define DMA_AIC_16BYTE_TX_CMD \
DMAC_DCMD_SAI | \
DMAC_DCMD_SWDH_16 | DMAC_DCMD_DWDH_16 | \
DMAC_DCMD_DS_16BYTE | DMAC_DCMD_RDIL_IGN
extern int jz_request_dma(int dev_id,
const char *dev_str,
irqreturn_t (*irqhandler)(int, void *),
unsigned long irqflags,
void *irq_dev_id);
extern void jz_free_dma(unsigned int dmanr);
extern int jz_dma_read_proc(char *buf, char **start, off_t fpos,
int length, int *eof, void *data);
extern void dump_jz_dma_channel(unsigned int dmanr);
extern void enable_dma(unsigned int dmanr);
extern void disable_dma(unsigned int dmanr);
extern void set_dma_addr(unsigned int dmanr, unsigned int phyaddr);
extern void set_dma_count(unsigned int dmanr, unsigned int bytecnt);
extern void set_dma_mode(unsigned int dmanr, unsigned int mode);
extern void jz_set_alsa_dma(unsigned int dmanr, unsigned int mode, unsigned int audio_fmt);
extern unsigned int get_dma_residue(unsigned int dmanr);
extern spinlock_t dma_spin_lock;
static __inline__ unsigned long claim_dma_lock(void)
{
unsigned long flags;
spin_lock_irqsave(&dma_spin_lock, flags);
return flags;
}
static __inline__ void release_dma_lock(unsigned long flags)
{
spin_unlock_irqrestore(&dma_spin_lock, flags);
}
/* Clear the 'DMA Pointer Flip Flop'.
* Write 0 for LSB/MSB, 1 for MSB/LSB access.
*/
#define clear_dma_ff(channel)
static __inline__ struct jz_dma_chan *get_dma_chan(unsigned int dmanr)
{
if (dmanr > MAX_DMA_NUM
|| jz_dma_table[dmanr].dev_id < 0)
return NULL;
return &jz_dma_table[dmanr];
}
static __inline__ int dma_halted(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 1;
return __dmac_channel_transmit_halt_detected(dmanr) ? 1 : 0;
}
static __inline__ unsigned int get_dma_mode(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
return chan->mode;
}
static __inline__ void clear_dma_done(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
}
static __inline__ void clear_dma_halt(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT);
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT);
}
static __inline__ void clear_dma_flag(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return;
REG_DMAC_DCCSR(chan->io) &= ~(DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
REG_DMAC_DMACR &= ~(DMAC_DMACR_HLT | DMAC_DMACR_AR);
}
static __inline__ void set_dma_page(unsigned int dmanr, char pagenr)
{
}
static __inline__ unsigned int get_dma_done_status(unsigned int dmanr)
{
unsigned long dccsr;
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return 0;
dccsr = REG_DMAC_DCCSR(chan->io);
return dccsr & (DMAC_DCCSR_HLT | DMAC_DCCSR_TT | DMAC_DCCSR_AR);
}
static __inline__ int get_dma_done_irq(unsigned int dmanr)
{
struct jz_dma_chan *chan = get_dma_chan(dmanr);
if (!chan)
return -1;
return chan->irq;
}
void jz4740_dma_set_complete_cb(struct jz4740_dma_chan *dma,
jz4740_dma_complete_callback_t cb);
#endif /* __ASM_JZ4740_DMA_H__ */