blob: 61c046613fed5ccebce408b253d9ce75e8102a0b [file] [log] [blame]
/*******************************************************************************
* 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;
}