Initial commit: TXW82x FPV v2.7.0.7-42229 SDK + project sources
This commit is contained in:
216
sdk/driver/dma/dw_dmac.c
Normal file
216
sdk/driver/dma/dw_dmac.c
Normal file
@@ -0,0 +1,216 @@
|
||||
#include "typesdef.h"
|
||||
#include "list.h"
|
||||
#include "errno.h"
|
||||
#include "dev.h"
|
||||
#include "string.h"
|
||||
#include "osal/irq.h"
|
||||
#include "osal/semaphore.h"
|
||||
#include "osal/mutex.h"
|
||||
#include "hal/dma.h"
|
||||
#include "dev/dma/dw_dmac.h"
|
||||
#include "osal/string.h"
|
||||
|
||||
static void dw_dmac_irq_handler(void *data)
|
||||
{
|
||||
uint32 ch;
|
||||
struct hgdma_dw *dma = (struct hgdma_dw *)data;
|
||||
|
||||
for(ch=0; ch<DW_DMAC_MAX_DMAC_CHN; ch++) {
|
||||
if((dma->hw->MaskTfrL & BIT(ch)) && (dma->hw->RawTfrL & BIT(ch))) {
|
||||
dma->hw->ClearTfrL = BIT(ch);
|
||||
dma->state[ch] |= DW_DMAC_XFER_DONE(ch);
|
||||
if(dma->irq_hdl[ch]) {
|
||||
dma->irq_hdl[ch]((void *)dma, ch, DMA_IRQ_TYPE_DONE, dma->irq_data[ch]);
|
||||
}
|
||||
}
|
||||
if((dma->hw->MaskErrL & BIT(ch)) && (dma->hw->RawErrL & BIT(ch))) {
|
||||
dma->hw->ClearErrL = BIT(ch);
|
||||
dma->state[ch] |= DW_DMAC_XFER_ERR(ch);
|
||||
if(dma->irq_hdl[ch]) {
|
||||
dma->irq_hdl[ch]((void *)dma, ch, DMA_IRQ_TYPE_ERROR, dma->irq_data[ch]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int32 dw_dmac_xfer(struct dma_device *dma, struct dma_xfer_data *data)
|
||||
{
|
||||
uint32 ch;
|
||||
uint32 flags;
|
||||
uint32 src_id = data->src_id;
|
||||
uint32 dest_id = data->dst_id;
|
||||
uint32 direct = data->dir;
|
||||
uint8 src_dir = (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) ? DW_DMAC_ADDR_NO_CHANGE : DW_DMAC_ADDR_INC;
|
||||
uint8 dst_dir = (data->dst_addr_mode == DMA_XFER_MODE_RECYCLE) ? DW_DMAC_ADDR_NO_CHANGE : DW_DMAC_ADDR_INC;
|
||||
struct hgdma_dw *dev = (struct hgdma_dw *)dma;
|
||||
struct hgdma_dw_hw *hw = (struct hgdma_dw_hw *)dev->hw;
|
||||
|
||||
if(!dev->opened) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
/* get free channel */
|
||||
flags = disable_irq();
|
||||
for(ch=0; ch<DW_DMAC_MAX_DMAC_CHN; ch++) {
|
||||
if(!(dev->chn_used_flag & BIT(ch))) {
|
||||
dev->chn_used_flag |= BIT(ch);
|
||||
break;
|
||||
}
|
||||
}
|
||||
enable_irq(flags);
|
||||
|
||||
if(ch >= DW_DMAC_MAX_DMAC_CHN)
|
||||
return -EBUSY;
|
||||
|
||||
ASSERT(data->element_per_width < DMA_SLAVE_BUSWIDTH_8_BYTES);
|
||||
if(data->element_per_width >= DMA_SLAVE_BUSWIDTH_8_BYTES) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
hw->CH[ch].SARH = 0x0000;
|
||||
hw->CH[ch].DARH = 0x0000;
|
||||
hw->CH[ch].SARL = data->src;
|
||||
hw->CH[ch].DARL = data->dest;
|
||||
switch(direct) {
|
||||
case DMA_XFER_DIR_M2M:
|
||||
hw->CH[ch].CTLL = DW_DMAC_CTLL_SMS(1) | DW_DMAC_CTLL_DMS(1) |
|
||||
DW_DMAC_CTLL_FC(DW_DMAC_FC_D_M2M) |
|
||||
DW_DMAC_CTLL_SRC_DIR(src_dir) |
|
||||
DW_DMAC_CTLL_DST_DIR(dst_dir);
|
||||
/* Configure dma req channel */
|
||||
hw->CH[ch].CFGH = DW_DMAC_CFGH_DST_PER(0) |
|
||||
DW_DMAC_CFGH_SRC_PER(0) |
|
||||
DW_DMAC_CFGH_PROTCTL(1);
|
||||
break;
|
||||
case DMA_XFER_DIR_D2M:
|
||||
hw->CH[ch].CTLL = DW_DMAC_CTLL_SMS(0) | DW_DMAC_CTLL_DMS(1) |
|
||||
DW_DMAC_CTLL_FC(DW_DMAC_FC_D_P2M) |
|
||||
DW_DMAC_CTLL_SRC_DIR(src_dir) |
|
||||
DW_DMAC_CTLL_DST_DIR(dst_dir);
|
||||
/* Configure dma req channel */
|
||||
hw->CH[ch].CFGH = DW_DMAC_CFGH_DST_PER(0) |
|
||||
DW_DMAC_CFGH_SRC_PER(src_id) |
|
||||
DW_DMAC_CFGH_PROTCTL(1);
|
||||
break;
|
||||
case DMA_XFER_DIR_M2D:
|
||||
hw->CH[ch].CTLL = DW_DMAC_CTLL_SMS(1) | DW_DMAC_CTLL_DMS(0) |
|
||||
DW_DMAC_CTLL_FC(DW_DMAC_FC_D_M2P) |
|
||||
DW_DMAC_CTLL_SRC_DIR(src_dir) |
|
||||
DW_DMAC_CTLL_DST_DIR(dst_dir);
|
||||
/* Configure dma req channel */
|
||||
hw->CH[ch].CFGH = DW_DMAC_CFGH_DST_PER(dest_id) |
|
||||
DW_DMAC_CFGH_SRC_PER(0) |
|
||||
DW_DMAC_CFGH_PROTCTL(1);
|
||||
break;
|
||||
case DMA_XFER_DIR_D2D:
|
||||
hw->CH[ch].CTLL = DW_DMAC_CTLL_SMS(0) | DW_DMAC_CTLL_DMS(0) |
|
||||
DW_DMAC_CTLL_FC(DW_DMAC_FC_D_P2P) |
|
||||
DW_DMAC_CTLL_SRC_DIR(src_dir) |
|
||||
DW_DMAC_CTLL_DST_DIR(dst_dir);
|
||||
/* Configure dma req channel */
|
||||
hw->CH[ch].CFGH = DW_DMAC_CFGH_DST_PER(dest_id) |
|
||||
DW_DMAC_CFGH_SRC_PER(src_id) |
|
||||
DW_DMAC_CFGH_PROTCTL(1);
|
||||
break;
|
||||
default:
|
||||
dev->chn_used_flag &= ~ BIT(ch);
|
||||
return RET_ERR;
|
||||
}
|
||||
/* Configure block size */
|
||||
hw->CH[ch].CTLH = data->element_num;
|
||||
|
||||
hw->CH[ch].CTLL |= DW_DMAC_CTLL_INT_EN |
|
||||
DW_DMAC_CTLL_SRC_MSIZE(DW_DMAC_MSIZE_1) |
|
||||
DW_DMAC_CTLL_DST_MSIZE(DW_DMAC_MSIZE_1) |
|
||||
DW_DMAC_CTLL_SRC_WIDTH(data->element_per_width) |
|
||||
DW_DMAC_CTLL_DST_WIDTH(data->element_per_width);
|
||||
/* AMBA burst length no limited. */
|
||||
hw->CH[ch].CFGL = DW_DMAC_CFGL_MAX_BURST(0);
|
||||
|
||||
dev->state[ch] = 0x0000;
|
||||
dev->irq_hdl[ch] = data->irq_hdl;
|
||||
dev->irq_data[ch] = data->irq_data;
|
||||
|
||||
//start xfer
|
||||
hw->ChEnRegL = DW_DMAC_WRITE_EN(ch);
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int32 dw_dmac_get_status(struct dma_device *dma, uint32 chn)
|
||||
{
|
||||
struct hgdma_dw *dev = (struct hgdma_dw *)dma;
|
||||
|
||||
if(!dev->opened) {
|
||||
return RET_ERR;
|
||||
}
|
||||
|
||||
if(dev->state[chn] & DW_DMAC_XFER_ERR(chn)) {
|
||||
return DMA_ERROR;
|
||||
} else if(dev->state[chn] & DW_DMAC_XFER_DONE(chn)) {
|
||||
return DMA_SUCCESS;
|
||||
} else {
|
||||
return DMA_IN_PROGRESS;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 dw_dmac_stop(struct dma_device *dma, uint32 chn)
|
||||
{
|
||||
uint32 flags;
|
||||
|
||||
struct hgdma_dw *dev = (struct hgdma_dw *)dma;
|
||||
struct hgdma_dw_hw *p_dmac = (struct hgdma_dw_hw *)dev->hw;
|
||||
|
||||
flags = disable_irq();
|
||||
if(dev->chn_used_flag & BIT(chn)) {
|
||||
p_dmac->ChEnRegL = DW_DMAC_WRITE_DIS(chn);
|
||||
dev->chn_used_flag &= ~ BIT(chn);
|
||||
}
|
||||
enable_irq(flags);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
static const struct dma_hal_ops dw_ops = {
|
||||
.xfer = dw_dmac_xfer,
|
||||
.get_status = dw_dmac_get_status,
|
||||
.stop = dw_dmac_stop,
|
||||
};
|
||||
|
||||
__init int32 dw_dmac_attach(uint32 dev_id, struct hgdma_dw *dmac)
|
||||
{
|
||||
uint32 ch;
|
||||
|
||||
dmac->opened = 1;
|
||||
dmac->dev.dev.ops = (const struct devobj_ops *)&dw_ops;
|
||||
|
||||
for(ch=0; ch<DW_DMAC_MAX_DMAC_CHN; ch++) {
|
||||
dmac->irq_hdl[ch] = NULL;
|
||||
dmac->irq_data[ch] = 0;
|
||||
dmac->state[ch] = 0;
|
||||
}
|
||||
|
||||
dmac->hw->ChEnRegL = 0xFF00;
|
||||
dmac->hw->DmaCfgRegL = 0x0000;
|
||||
|
||||
/* reset dmac */
|
||||
dmac->hw->ClearBlockL = DW_DMAC_MAX_DMAC_CHN_MASK;
|
||||
dmac->hw->ClearDstTranL = DW_DMAC_MAX_DMAC_CHN_MASK;
|
||||
dmac->hw->ClearErrL = DW_DMAC_MAX_DMAC_CHN_MASK;
|
||||
dmac->hw->ClearSrcTranL = DW_DMAC_MAX_DMAC_CHN_MASK;
|
||||
dmac->hw->ClearTfrL = DW_DMAC_MAX_DMAC_CHN_MASK;
|
||||
|
||||
/* disable mask */
|
||||
dmac->hw->MaskErrL = 0xFFFF;
|
||||
dmac->hw->MaskTfrL = 0xFFFF;
|
||||
dmac->hw->MaskBlockL = 0xFF00;
|
||||
dmac->hw->MaskDstTranL = 0xFF00;
|
||||
dmac->hw->MaskSrcTranL = 0xFF00;
|
||||
|
||||
/* enable DMAC */
|
||||
dmac->hw->DmaCfgRegL = DW_DMAC_CFG_DMA_EN;
|
||||
|
||||
irq_enable(dmac->irq_num);
|
||||
request_irq(dmac->irq_num, dw_dmac_irq_handler, dmac);
|
||||
dev_register(dev_id, (struct dev_obj *)dmac);
|
||||
return RET_OK;
|
||||
}
|
||||
434
sdk/driver/dma/hg_m2m_dma.c
Normal file
434
sdk/driver/dma/hg_m2m_dma.c
Normal file
@@ -0,0 +1,434 @@
|
||||
#include "typesdef.h"
|
||||
#include "list.h"
|
||||
#include "errno.h"
|
||||
#include "dev.h"
|
||||
#include "osal/irq.h"
|
||||
#include "osal/semaphore.h"
|
||||
#include "osal/mutex.h"
|
||||
#include "osal/string.h"
|
||||
#include "hal/dma.h"
|
||||
#include "dev/dma/hg_m2m_dma.h"
|
||||
#include "osal/sleep.h"
|
||||
|
||||
#define DMA_LEN_THRESHOLD (2048)
|
||||
uint32_t in_disable_irq(void);
|
||||
|
||||
static void hg_m2m0_dma_irq_handler(void *data)
|
||||
{
|
||||
struct mem_dma_dev *dma = (struct mem_dma_dev *)data;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dma->hw;
|
||||
|
||||
hw->dma_ch[0].DMA_SAIE = 1;
|
||||
os_sema_up(&dma->done[0]);
|
||||
}
|
||||
|
||||
static void hg_m2m1_dma_irq_handler(void *data)
|
||||
{
|
||||
struct mem_dma_dev *dma = (struct mem_dma_dev *)data;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dma->hw;
|
||||
|
||||
hw->dma_ch[1].DMA_SAIE = 1;
|
||||
os_sema_up(&dma->done[1]);
|
||||
}
|
||||
|
||||
#ifdef TXW82X
|
||||
static void hg_m2m2_dma_irq_handler(void *data)
|
||||
{
|
||||
struct mem_dma_dev *dma = (struct mem_dma_dev *)data;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dma->hw;
|
||||
|
||||
hw->dma_ch[2].DMA_SAIE = 1;
|
||||
os_sema_up(&dma->done[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline int32 hg_m2m_dma_get_free_ch(struct mem_dma_dev *dev, uint8 ch_fix)
|
||||
{
|
||||
int32 ch = (ch_fix >= HG_M2M_DMA_NUM) ? (HG_M2M_DMA_NUM-1) : ch_fix;
|
||||
uint32 flags = disable_irq();
|
||||
for (; ch>=0; ) {
|
||||
if (!(dev->busy_flag & BIT(ch))){
|
||||
dev->busy_flag |= BIT(ch);
|
||||
break;
|
||||
}
|
||||
if (ch_fix < HG_M2M_DMA_NUM) {
|
||||
ch = -1;
|
||||
break;
|
||||
} else {
|
||||
ch--;
|
||||
}
|
||||
}
|
||||
|
||||
enable_irq(flags);
|
||||
return ch;
|
||||
}
|
||||
|
||||
static inline void hg_m2m_dma_free_ch(struct mem_dma_dev *dev, int32 ch)
|
||||
{
|
||||
uint32 flags = disable_irq();
|
||||
dev->busy_flag &= ~ BIT(ch);
|
||||
enable_irq(flags);
|
||||
}
|
||||
|
||||
#define is_memset_same_val(n) ((((n) >> 0) & 0xff) == (((n) >> 8) & 0xff))
|
||||
static void hg_soft_memset(uint32 *dest, uint32 val, uint32 size)
|
||||
{
|
||||
uint32 i = 0;
|
||||
uint8 head_size = (uint32)dest % 4;
|
||||
uint8 tail_size = ((uint32)dest+size) % 4;
|
||||
uint32 c_size = ALIGN(size, 4) + ALIGN(head_size, 4);
|
||||
uint32 *p_dst = (uint32 *)((uint32)dest - head_size);
|
||||
uint8 *p_dst_bt = (uint8 *)dest;
|
||||
if (is_memset_same_val(val))
|
||||
{
|
||||
os_memset((void*)dest, (val & 0xff), size);
|
||||
} else {
|
||||
for (; i < c_size>>2; i++)
|
||||
*p_dst++ = val;
|
||||
for (i = head_size; i < (head_size << 1); i++)
|
||||
*p_dst_bt++ = val>>((i % 4)<<3);
|
||||
p_dst_bt = (uint8 *)((uint32)dest + size - tail_size);
|
||||
for (i = tail_size; i < (tail_size << 1); i++)
|
||||
*p_dst_bt++ = val>>((i % 4)<<3);
|
||||
}
|
||||
}
|
||||
|
||||
const uint8 dma_element_size[4] = {1,2,4,8};
|
||||
static int32 hg_m2m_dma_xfer(struct dma_device *dma, struct dma_xfer_data *data)
|
||||
{
|
||||
int32 ch = -1;
|
||||
uint32 val = (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) ? (*((uint32 *)data->src)) : (0);
|
||||
uint32 count = data->element_num * dma_element_size[data->element_per_width];
|
||||
static uint8 ch0_lock = 0;
|
||||
uint32 retry;
|
||||
uint32 addr_offset = 0;
|
||||
uint32 dma_cnt = 0;
|
||||
int32 ret = 0;
|
||||
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dev->hw;
|
||||
|
||||
retry = (__in_interrupt() || in_disable_irq()) ? 1 : (count >> (8+(2*dev->dma1_status)));
|
||||
if (!retry) retry = 1;
|
||||
|
||||
if (data->element_per_width >= DMA_SLAVE_BUSWIDTH_UNDEFINED) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* get free channel */
|
||||
for ( ; (!dev->suspend) && (retry--); ) {
|
||||
if (data->dir != DMA_XFER_DIR_M2M) {
|
||||
uint32 flags = disable_irq();
|
||||
ch = hg_m2m_dma_get_free_ch(dev, 0);
|
||||
if (0 == ch)
|
||||
ch0_lock = 1;
|
||||
enable_irq(flags);
|
||||
} else {
|
||||
ch = hg_m2m_dma_get_free_ch(dev, ch0_lock ? (HG_M2M_DMA_NUM - 1) : HG_M2M_DMA_NUM);
|
||||
}
|
||||
if (ch >= 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch < 0) {
|
||||
if (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) {
|
||||
hg_soft_memset((void*)data->dest, val, count);
|
||||
} else if(data->src_addr_mode == DMA_XFER_MODE_INCREASE){
|
||||
os_memcpy((void*)data->dest, (void*)data->src, count);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
#ifdef TXW81X
|
||||
uint32 dst_addr = data->dest>>24;
|
||||
if (dst_addr == 0x38 || dst_addr == 0x08) {
|
||||
while(ll_sysctrl_dma2ahb_is_busy((ch) ? (DMA2AHB_BURST_CH_M2M1_WR) : (DMA2AHB_BURST_CH_M2M0_WR)));
|
||||
}
|
||||
#endif
|
||||
|
||||
//sysctrl_m2m_dma_reset();
|
||||
#if defined(TXW81X)
|
||||
hw->dma_ch[ch].DMA_CON &= HG_M2M_DMA_CON_ENDIAN_RES;
|
||||
hw->dma_ch[ch].DMA_ISIZE = 0;
|
||||
#elif defined(TXW82X)
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
hw->dma_ch[ch].DMA_CON |= HG_M2M_DMA_CON_ENDIAN_SET(data->endian);
|
||||
#else
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
#endif
|
||||
hw->dma_ch[ch].DMA_DATA = val;
|
||||
|
||||
while(count)
|
||||
{
|
||||
hw->dma_ch[ch].DMA_TADR = (uint32)data->dest + addr_offset;
|
||||
hw->dma_ch[ch].DMA_SADR = (uint32)data->src + addr_offset;
|
||||
dma_cnt = (count > (HG_M2M_DMA_MAX_LEN)) ? (HG_M2M_DMA_MAX_LEN) : (count);
|
||||
if ((!__in_interrupt()) && (!in_disable_irq()) && (dma_cnt > DMA_LEN_THRESHOLD)) {
|
||||
hw->dma_ch[ch].DMA_SAIE = 0x10001;
|
||||
os_sema_eat(&dev->done[ch]);
|
||||
} else {
|
||||
hw->dma_ch[ch].DMA_SAIE = 1;
|
||||
}
|
||||
hw->dma_ch[ch].DMA_DLEN = dma_cnt - 1;
|
||||
count -= dma_cnt;
|
||||
addr_offset += dma_cnt;
|
||||
|
||||
if (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) {
|
||||
hw->dma_ch[ch].DMA_CON |= (HG_M2M_DMA_CON_MEMSET | HG_M2M_DMA_CON_DTE);
|
||||
} else if(data->src_addr_mode == DMA_XFER_MODE_INCREASE){
|
||||
hw->dma_ch[ch].DMA_CON |= (HG_M2M_DMA_CON_MEMCPY | HG_M2M_DMA_CON_DTE);
|
||||
}
|
||||
|
||||
if (hw->dma_ch[ch].DMA_SAIE & 0x10000) {
|
||||
ret = os_sema_down(&dev->done[ch], 50);
|
||||
if (!ret) {
|
||||
os_printf(KERN_ERR"hw_dma err: {%08x <--- %08x} len=%d\r\n", hw->dma_ch[ch].DMA_TADR, hw->dma_ch[ch].DMA_SADR, dma_cnt);
|
||||
}
|
||||
} else {
|
||||
while (hw->dma_ch[ch].DMA_CON & HG_M2M_DMA_CON_DTE) {
|
||||
}
|
||||
}
|
||||
}
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
hg_m2m_dma_free_ch(dev, ch);
|
||||
if(ch && dev->dma1_mutex && !dev->dma1_status)
|
||||
{
|
||||
dev->dma1_status = true;
|
||||
hg_m2m_dma_get_free_ch(dev, ch);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int32 hg_m2m_dma_only_hw_xfer(struct dma_device *dma, struct dma_xfer_data *data)
|
||||
{
|
||||
int32 ch = -1;
|
||||
uint32 val = (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) ? (*((uint32 *)data->src)) : (0);
|
||||
uint32 count = data->element_num * dma_element_size[data->element_per_width];
|
||||
static uint8 ch0_lock = 0;
|
||||
uint32 retry;
|
||||
uint32 addr_offset = 0;
|
||||
uint32 dma_cnt = 0;
|
||||
int32 ret = 0;
|
||||
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dev->hw;
|
||||
|
||||
retry = (__in_interrupt() || in_disable_irq()) ? 1 : (count >> (8+(2*dev->dma1_status)));
|
||||
if (!retry) retry = 1;
|
||||
|
||||
if (data->element_per_width >= DMA_SLAVE_BUSWIDTH_UNDEFINED) {
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* get free channel */
|
||||
for ( ; (!dev->suspend) && (retry); ) {
|
||||
if (data->dir != DMA_XFER_DIR_M2M) {
|
||||
uint32 flags = disable_irq();
|
||||
ch = hg_m2m_dma_get_free_ch(dev, 0);
|
||||
if (0 == ch)
|
||||
ch0_lock = 1;
|
||||
enable_irq(flags);
|
||||
} else {
|
||||
ch = hg_m2m_dma_get_free_ch(dev, ch0_lock ? (HG_M2M_DMA_NUM - 1) : HG_M2M_DMA_NUM);
|
||||
}
|
||||
if (ch >= 0) {
|
||||
break;
|
||||
}
|
||||
os_sleep_ms(1);
|
||||
}
|
||||
|
||||
#ifdef TXW81X
|
||||
uint32 dst_addr = data->dest>>24;
|
||||
if (dst_addr == 0x38 || dst_addr == 0x08) {
|
||||
while(ll_sysctrl_dma2ahb_is_busy((ch) ? (DMA2AHB_BURST_CH_M2M1_WR) : (DMA2AHB_BURST_CH_M2M0_WR)));
|
||||
}
|
||||
#endif
|
||||
|
||||
//sysctrl_m2m_dma_reset();
|
||||
#if defined(TXW81X)
|
||||
hw->dma_ch[ch].DMA_CON &= HG_M2M_DMA_CON_ENDIAN_RES;
|
||||
hw->dma_ch[ch].DMA_ISIZE = 0;
|
||||
#elif defined(TXW82X)
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
hw->dma_ch[ch].DMA_CON |= HG_M2M_DMA_CON_ENDIAN_SET(data->endian);
|
||||
#else
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
#endif
|
||||
hw->dma_ch[ch].DMA_DATA = val;
|
||||
|
||||
while(count)
|
||||
{
|
||||
hw->dma_ch[ch].DMA_TADR = (uint32)data->dest + addr_offset;
|
||||
hw->dma_ch[ch].DMA_SADR = (uint32)data->src + addr_offset;
|
||||
dma_cnt = (count > (HG_M2M_DMA_MAX_LEN)) ? (HG_M2M_DMA_MAX_LEN) : (count);
|
||||
if ((!__in_interrupt()) && (!in_disable_irq()) && (dma_cnt > DMA_LEN_THRESHOLD)) {
|
||||
hw->dma_ch[ch].DMA_SAIE = 0x10001;
|
||||
os_sema_eat(&dev->done[ch]);
|
||||
} else {
|
||||
hw->dma_ch[ch].DMA_SAIE = 1;
|
||||
}
|
||||
hw->dma_ch[ch].DMA_DLEN = dma_cnt - 1;
|
||||
count -= dma_cnt;
|
||||
addr_offset += dma_cnt;
|
||||
|
||||
if (data->src_addr_mode == DMA_XFER_MODE_RECYCLE) {
|
||||
hw->dma_ch[ch].DMA_CON |= (HG_M2M_DMA_CON_MEMSET | HG_M2M_DMA_CON_DTE);
|
||||
} else if(data->src_addr_mode == DMA_XFER_MODE_INCREASE){
|
||||
hw->dma_ch[ch].DMA_CON |= (HG_M2M_DMA_CON_MEMCPY | HG_M2M_DMA_CON_DTE);
|
||||
}
|
||||
|
||||
if (hw->dma_ch[ch].DMA_SAIE & 0x10000) {
|
||||
ret = os_sema_down(&dev->done[ch], 50);
|
||||
if (!ret) {
|
||||
os_printf(KERN_ERR"hw_dma err: {%08x <--- %08x} len=%d\r\n", hw->dma_ch[ch].DMA_TADR, hw->dma_ch[ch].DMA_SADR, dma_cnt);
|
||||
}
|
||||
} else {
|
||||
while (hw->dma_ch[ch].DMA_CON & HG_M2M_DMA_CON_DTE) {
|
||||
}
|
||||
}
|
||||
}
|
||||
hw->dma_ch[ch].DMA_CON = 0x00;
|
||||
hg_m2m_dma_free_ch(dev, ch);
|
||||
if(ch && dev->dma1_mutex && !dev->dma1_status)
|
||||
{
|
||||
dev->dma1_status = true;
|
||||
hg_m2m_dma_get_free_ch(dev, ch);
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
static int32 hg_m2m_dma_get_status(struct dma_device *dma, uint32 chn)
|
||||
{
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dev->hw;
|
||||
|
||||
if (hw->dma_ch[chn].DMA_CON & HG_M2M_DMA_CON_DTE) {
|
||||
return DMA_IN_PROGRESS;
|
||||
} else {
|
||||
return DMA_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
static int32 hg_m2m_dma_ioctl(struct dma_device *dma, uint32 cmd, int32 param1, int32 param2)
|
||||
{
|
||||
int32 ret_val = RET_OK;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
#if (defined(TX81X) || defined(TXW82X))
|
||||
case DMA_IOCTL_CMD_ENDIAN:{
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
struct mem_dma_hw *hw = (struct mem_dma_hw *)dev->hw;
|
||||
for (int i = 0; i < HG_M2M_DMA_NUM; i++)
|
||||
hw->dma_ch[i].DMA_CON = ((hw->dma_ch[i].DMA_CON & (~HG_M2M_DMA_CON_ENDIAN_RES)) | HG_M2M_DMA_CON_ENDIAN_SET(param1));
|
||||
break;
|
||||
}
|
||||
|
||||
case DMA_IOCTL_CMD_CHECK_DMA1_STATUS:{
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
ret_val = dev->dma1_status;
|
||||
break;
|
||||
}
|
||||
|
||||
case DMA_IOCTL_CMD_DMA1_LOCK:{
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
int32 ch = hg_m2m_dma_get_free_ch(dev, 1);
|
||||
if(ch)
|
||||
{
|
||||
dev->dma1_status = true;
|
||||
}else{
|
||||
hg_m2m_dma_free_ch(dev, ch);
|
||||
dev->dma1_status = false;
|
||||
}
|
||||
dev->dma1_mutex = true;
|
||||
break;
|
||||
};
|
||||
|
||||
case DMA_IOCTL_CMD_DMA1_UNLOCK:{
|
||||
struct mem_dma_dev *dev = (struct mem_dma_dev *)dma;
|
||||
hg_m2m_dma_free_ch(dev, 1);
|
||||
dev->dma1_mutex = false;
|
||||
dev->dma1_status = false;
|
||||
break;
|
||||
};
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret_val = -ENOTSUPP;
|
||||
break;
|
||||
}
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SLEEP
|
||||
int32 hg_m2m_dma_suspend(struct dev_obj *dev)
|
||||
{
|
||||
struct mem_dma_dev *dma = (struct mem_dma_dev *)dev;
|
||||
|
||||
if (dma->suspend) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
|
||||
/* force all dma busy */
|
||||
dma->suspend = 1;
|
||||
|
||||
for (int i = 0; i < HG_M2M_DMA_NUM; i++)
|
||||
while (0 != hg_m2m_dma_get_free_ch(dma, i)) { os_sleep_ms(1); }
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
int32 hg_m2m_dma_resume(struct dev_obj *dev)
|
||||
{
|
||||
struct mem_dma_dev *dma = (struct mem_dma_dev *)dev;
|
||||
|
||||
if (!dma->suspend) {
|
||||
return -ENOTSUP;
|
||||
}
|
||||
hg_m2m_dma_free_ch(dma, 0);
|
||||
hg_m2m_dma_free_ch(dma, 1);
|
||||
irq_enable(dma->irq_num);
|
||||
irq_enable(dma->irq_num+1);
|
||||
dma->suspend = 0;
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static const struct dma_hal_ops m2m_ops = {
|
||||
.xfer = hg_m2m_dma_xfer,
|
||||
.only_hw_xfer = hg_m2m_dma_only_hw_xfer,
|
||||
.get_status = hg_m2m_dma_get_status,
|
||||
.ioctl = hg_m2m_dma_ioctl,
|
||||
#ifdef CONFIG_SLEEP
|
||||
.ops.suspend = hg_m2m_dma_suspend,
|
||||
.ops.resume = hg_m2m_dma_resume,
|
||||
#endif
|
||||
};
|
||||
|
||||
__init int32 hg_m2m_dma_dev_attach(uint32 dev_id, struct mem_dma_dev *p_dma)
|
||||
{
|
||||
#ifdef TXW82X
|
||||
void *irq_handler[] = {hg_m2m0_dma_irq_handler, hg_m2m1_dma_irq_handler, hg_m2m2_dma_irq_handler};
|
||||
#else
|
||||
void *irq_handler[] = {hg_m2m0_dma_irq_handler, hg_m2m1_dma_irq_handler};
|
||||
#endif
|
||||
p_dma->dev.dev.ops = (const struct devobj_ops *)&m2m_ops;
|
||||
p_dma->busy_flag = 0;
|
||||
p_dma->suspend = 0;
|
||||
|
||||
for (uint8 i = 0; i < HG_M2M_DMA_NUM; i++)
|
||||
{
|
||||
os_sema_init(&p_dma->done[i], 0);
|
||||
p_dma->hw->dma_ch[i].DMA_CON = 0x00;
|
||||
p_dma->hw->dma_ch[i].DMA_SAIE = HG_M2M_DMA_SAIE_TCP_PENDING;
|
||||
irq_enable(p_dma->irq_num[i]);
|
||||
request_irq(p_dma->irq_num[i], irq_handler[i], p_dma);
|
||||
}
|
||||
|
||||
dev_register(dev_id, (struct dev_obj *)p_dma);
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user