/******************************************************************************* | |
* Copyright (C) 2016, ZXIC Corporation. | |
* | |
* File Name: | |
* File Mark: | |
* Description: | |
* Others: | |
* Version: 1.0 | |
* Author: zxic | |
* Date: 2016.12.15 | |
* modify | |
********************************************************************************/ | |
/**************************************************************************** | |
* Include files | |
****************************************************************************/ | |
#include <malloc.h> | |
#include <errno.h> | |
#include <asm/io.h> | |
#include <linux/mtd/mtd.h> | |
#include <asm-generic/ioctl.h> | |
#include <config.h> | |
#include <common.h> | |
#include <command.h> | |
#include "zx29_dma.h" | |
/**************************************************************************** | |
* Local Macros | |
****************************************************************************/ | |
#define BIT(value,BIT_NO) (unsigned int)((unsigned int)value << (BIT_NO)) | |
#define DMA_CTRL_ENABLE(value) BIT(value,0) | |
#define DMA_CTRL_SOFT_B_REQ(value) BIT(value,1) | |
#define DMA_CTRL_SRC_FIFO_MOD(value) BIT(value,2) | |
#define DMA_CTRL_DEST_FIFO_MOD(value) BIT(value,3) | |
#define DMA_CTRL_IRQ_MOD(value) BIT(value,4) | |
#define DMA_CTRL_SRC_BURST_SIZE(value) BIT(value,6) | |
#define DMA_CTRL_SRC_BURST_LENGTH(value) BIT(value,9) | |
#define DMA_CTRL_DEST_BURST_SIZE(value) BIT(value,13) | |
#define DMA_CTRL_DEST_BURST_LENGTH(value) BIT(value,16) | |
#define DMA_CTRL_INTERRUPT_SEL(value) BIT(value,20) | |
#define DMA_CTRL_FORCE_CLOSE(value) BIT(value,31); | |
#define MAX(a,b) ((a) > (b) ? (a) : (b)) | |
/**************************************************************************** | |
* Local Types | |
****************************************************************************/ | |
dma_callback_func channel_cbk[DMA_CH_NUM]; | |
volatile dma_regs* dma_reg; | |
static unsigned int parse_dma_req(dma_transfer_mode trans_mode) | |
{ | |
unsigned int control = 0; | |
switch(trans_mode) | |
{ | |
case TRAN_PERI_TO_PERI: | |
control = DMA_CTRL_SOFT_B_REQ(DMA_PERIPHERAL_REQ)\ | |
| DMA_CTRL_SRC_FIFO_MOD(DMA_ADDRMOD_FIFO) \ | |
| DMA_CTRL_DEST_FIFO_MOD(DMA_ADDRMOD_FIFO); | |
break; | |
case TRAN_PERI_TO_MEM: | |
control = DMA_CTRL_SOFT_B_REQ(DMA_PERIPHERAL_REQ)\ | |
| DMA_CTRL_SRC_FIFO_MOD(DMA_ADDRMOD_FIFO) \ | |
| DMA_CTRL_DEST_FIFO_MOD(DMA_ADDRMOD_RAM); | |
break; | |
case TRAN_MEM_TO_PERI: | |
control = DMA_CTRL_SOFT_B_REQ(DMA_PERIPHERAL_REQ)\ | |
| DMA_CTRL_SRC_FIFO_MOD(DMA_ADDRMOD_RAM) \ | |
| DMA_CTRL_DEST_FIFO_MOD(DMA_ADDRMOD_FIFO); | |
break; | |
case TRAN_MEM_TO_MEM: | |
default: | |
control = DMA_CTRL_SOFT_B_REQ(DMA_SOFT_REQ)\ | |
| DMA_CTRL_SRC_FIFO_MOD(DMA_ADDRMOD_RAM) \ | |
| DMA_CTRL_DEST_FIFO_MOD(DMA_ADDRMOD_RAM); | |
break; | |
} | |
return control; | |
} | |
/************************************************************************** | |
* Function: dma_config | |
* Description: | |
* Parameters: | |
* Input: | |
* channel_id: | |
* chan_para: config param | |
* Output: None | |
* Returns: | |
**************************************************************************/ | |
int dma_config(dma_peripheral_id channel_id, dma_channel_def *chan_para) | |
{ | |
volatile dma_chan_reg __iomem* chan_reg; | |
if (channel_id >= DMA_CH_NUM || chan_para == NULL) | |
return -EINVAL; | |
if (chan_para->dma_control.tran_mode>=DMA_TRAN_MOD_ALL\ | |
||chan_para->dma_control.irq_mode>=DMA_IRQMOD_ALL\ | |
||chan_para->dma_control.src_burst_size>=DMA_BURST_SIZE_ALL\ | |
||chan_para->dma_control.src_burst_len>=DMA_BURST_LEN_ALL\ | |
||chan_para->dma_control.dest_burst_size>=DMA_BURST_SIZE_ALL\ | |
||chan_para->dma_control.dest_burst_len>=DMA_BURST_LEN_ALL) | |
{ | |
return -EINVAL; | |
} | |
chan_reg = &(dma_reg->channel[channel_id]); | |
chan_reg->src_addr = chan_para->src_addr; | |
chan_reg->dest_addr = chan_para->dest_addr; | |
chan_reg->xpara = chan_para->count; | |
chan_reg->link_addr = 0; | |
chan_reg->control = parse_dma_req(chan_para->dma_control.tran_mode)\ | |
| DMA_CTRL_SRC_BURST_SIZE(chan_para->dma_control.src_burst_size) \ | |
| DMA_CTRL_SRC_BURST_LENGTH((chan_para->dma_control.src_burst_len )) \ | |
| DMA_CTRL_DEST_BURST_SIZE(chan_para->dma_control.dest_burst_size) \ | |
| DMA_CTRL_DEST_BURST_LENGTH((chan_para->dma_control.dest_burst_len ))\ | |
| DMA_CTRL_INTERRUPT_SEL(DMA_INT_TO_A9) ; | |
/* now we do not use int mode */ | |
// if(chan_para->dma_control.irq_mode) | |
chan_reg->control |= DMA_CTRL_IRQ_MOD(DMA_ALL_IRQ_DISABLE); | |
return SUCCESS; | |
} | |
/************************************************************************** | |
* Function: dma_start | |
* Description: | |
* Parameters: | |
* Input: | |
* channel_id | |
* CallBack:if not null, when dma transfer is over, 'callback' will be called in the dma isr | |
data: parameter for callback(set NULL) | |
* Output: None | |
* Returns: | |
* T_ZDrvDma_Ret | |
* Others: None | |
**************************************************************************/ | |
int dma_start(dma_peripheral_id channel_id, dma_callback_func callback, void *data) | |
{ | |
if(channel_id >= DMA_CH_NUM) | |
{ | |
return -EINVAL; | |
} | |
channel_cbk[channel_id] = callback; | |
dma_reg->channel[channel_id].control |= DMA_CTRL_ENABLE(DMA_ENABLE); | |
return SUCCESS; | |
} | |
/************************************************************************** | |
* Function: dma_get_status | |
* Description: | |
* Parameters: | |
* Input: | |
* Output: None | |
* Returns: | |
* DMA_TRANSFER_DONE: channelID 's dma transfer has done. | |
* DMA_CFG_ERROR:something wrong with channelID's dma configuration | |
* DMA_NOT_DONE: if dma not done and dma config has no problem,return this value. | |
* | |
* Others: None | |
**************************************************************************/ | |
dma_status dma_get_status(dma_peripheral_id channel_id) | |
{ | |
unsigned int dma_err_reg_val = 0; | |
if(dma_reg->raw_int_tc_status&(0x1<<channel_id)) | |
{ | |
dma_reg->raw_int_tc_status |= (0x1<<channel_id); | |
return DMA_TRANSFER_DONE; | |
} | |
else | |
{ | |
dma_err_reg_val = dma_reg->raw_int_src_err_status\ | |
|dma_reg->raw_int_dest_err_status\ | |
|dma_reg->raw_int_cfg_err_status; | |
if(dma_err_reg_val & (0x1<<channel_id)) | |
{ | |
BUG(); | |
dma_reg->raw_int_src_err_status |= (0x1<<channel_id); | |
dma_reg->raw_int_dest_err_status |= (0x1<<channel_id); | |
dma_reg->raw_int_cfg_err_status |= (0x1<<channel_id); | |
return DMA_CFG_ERROR; | |
} | |
} | |
return DMA_NOT_DONE; | |
} | |
/************************************************************************** | |
* Function: zDrvDma_DisableChannel | |
* Description: Ç¿ÖÆÍ£Ö¹ucChannelËùָͨµÀºÅµÄ´«Êä¡£ | |
* Í£Ö¹ºóÈôÏëÖØÐÂÆô¶¯´«Ê䣬ÐèÖØÐÂÅäÖòÎÊý¡£ | |
* Parameters: | |
* Input: | |
* ucChannel: zDrvDma_AllocChannelµÄ·µ»ØÖµ¡£ | |
* Output: None | |
* Returns: | |
* | |
* Others: ´Ëº¯ÊýÍ£Ö¹DMA´«Ê䣬²»ÊÇÔÝÍ£¡£ | |
**************************************************************************/ | |
int dma_disable_channel(dma_peripheral_id channel_id) | |
{ | |
if(channel_id >= DMA_CH_NUM) | |
{ | |
return -EINVAL; | |
} | |
dma_reg->channel[channel_id].control |= DMA_CTRL_FORCE_CLOSE(1); | |
return SUCCESS; | |
} | |
/******************************************************************************* | |
* Function: dma_initiate | |
* Description: reset dma controller,the reset line will hold 2ms | |
* Parameters: | |
* Input: | |
* | |
* Output: | |
* | |
* Returns: | |
* | |
* Others: | |
********************************************************************************/ | |
int dma_init(void) | |
{ | |
dma_reg = (volatile dma_regs *)(PS_DMA_BASE); | |
dma_reg->irq_type |= 0xF; | |
return SUCCESS; | |
} | |