/** * @brief Set channel is masked * * When channel is masked, the GDMA transaction will stop. * When GDMA controller comes back from another channel (chain feature) * * >> Channel Mask=0: It's strange, and turns on related bit in GDMA interrupt * status register (16:23 Unmasked) * * >> Channel Mask=1: It'll start GDMA transation, and clear this bit. * * @param ChNum GDMA channel number * @retval 1 success * @retval 0 fail */ int GdmaMaskChannel(uint32_t ChNum) { uint32_t Data=0; Data=GDMA_READ_REG(GDMA_CTRL_REG1(ChNum)); Data |= ( 0x01 << CH_MASK_OFFSET); GDMA_WRITE_REG(GDMA_CTRL_REG1(ChNum), Data); GDMA_PRINT("%s: Write %0X to %X\n", __FUNCTION__, Data, GDMA_CTRL_REG1(ChNum)); return 1; }
static int RalinkGdmaInit(void) { uint32_t Ret=0; GDMA_PRINT("Enable Ralink GDMA Controller Module\n"); Ret = request_irq(SURFBOARDINT_DMA, GdmaIrqHandler, \ SA_INTERRUPT, "Ralink_DMA", NULL); if(Ret){ GDMA_PRINT("IRQ %d is not free.\n", SURFBOARDINT_DMA); return 1; } //Enable GDMA interrupt GDMA_WRITE_REG(RALINK_REG_INTENA, RALINK_INTCTL_DMA); //Channel0~Channel7 are round-robin GDMA_WRITE_REG(RALINK_GDMAGCT, 0x01); return 0; }
/** * @brief GDMA interrupt handler * * When GDMA transcation is done, call related handler * to do the remain job. * */ irqreturn_t GdmaIrqHandler( int irq, void *irqaction ) { u32 Ch=0; u32 flags; u32 GdmaStatus=GDMA_READ_REG(RALINK_GDMAISTS); GDMA_PRINT("Rcv Gdma Interrupt=%x\n",GdmaStatus); spin_lock_irqsave(&gdma_int_lock, flags); //UnMask error for(Ch=0;Ch<MAX_GDMA_CHANNEL;Ch++) { if(GdmaStatus & (0x1 << (Ch+UMASK_INT_STATUS_OFFSET)) ) { if(GdmaUnMaskIntCallback[Ch] != NULL) { //write 1 clear GDMA_WRITE_REG(RALINK_GDMAISTS, 1<< (Ch + UMASK_INT_STATUS_OFFSET)); GdmaUnMaskIntCallback[Ch](Ch); } } } //processing done for(Ch=0;Ch<MAX_GDMA_CHANNEL;Ch++) { if(GdmaStatus & (0x1<<Ch)) { if(GdmaTxDoneCallback[Ch] != NULL) { //write 1 clear GDMA_WRITE_REG(RALINK_GDMAISTS, 1<< (Ch + TX_DONE_INT_STATUS_OFFSET)); GdmaTxDoneCallback[Ch](Ch); } } } spin_unlock_irqrestore(&gdma_int_lock, flags); return IRQ_HANDLED; }
/** * @brief Start GDMA transaction for memory to memory copy * * @param *Src source address * @param *Dst destination address * @param TransCount data length * @param *DoneIntCallback callback function when transcation is done * @retval 1 success * @retval 0 fail */ int GdmaMem2Mem( uint32_t Src, uint32_t Dst, uint16_t TransCount, void (*DoneIntCallback)(uint32_t data) ) { GdmaReqEntry Entry; Entry.Src= (Src & 0x1FFFFFFF); Entry.Dst= (Dst & 0x1FFFFFFF); Entry.TransCount = TransCount; Entry.SrcBurstMode=INC_MODE; Entry.DstBurstMode=INC_MODE; Entry.BurstSize=BUSTER_SIZE_32B; Entry.SrcReqNum=DMA_MEM_REQ; Entry.DstReqNum=DMA_MEM_REQ; Entry.DoneIntCallback=DoneIntCallback; Entry.UnMaskIntCallback=NULL; Entry.SoftMode=1; Entry.ChMask=0; Entry.CoherentIntEbl=1; //No reserved channel for Memory to Memory GDMA, //get free channel on demand if(!_GdmaGetFreeCh(&Entry.ChNum)) { GDMA_PRINT("GDMA Channels are all busy\n"); return 0; } //set next channel to their own channel //to disable chain feature Entry.NextUnMaskCh= Entry.ChNum; //set next channel to another channel //to enable chain feature //Entry.NextUnMaskCh= (Entry.ChNum+1) % MAX_GDMA_CHANNEL; return _GdmaReqEntryIns(&Entry); }
/** * @brief Start GDMA transaction for receiving data to I2S * * @param *Src source address * @param *Dst destination address * @param TxNo I2S Tx number * @param TransCount data length * @param *DoneIntCallback callback function when transcation is done * @param *UnMaskIntCallback callback func when ch mask field is incorrect * @retval 1 success * @retval 0 fail */ int GdmaI2sRx( uint32_t Src, uint32_t Dst, uint8_t RxNo, uint16_t TransCount, void (*DoneIntCallback)(uint32_t data), void (*UnMaskIntCallback)(uint32_t data) ) { GdmaReqEntry Entry; Entry.Src= (Src & 0x1FFFFFFF); Entry.Dst= (Dst & 0x1FFFFFFF); Entry.TransCount = TransCount; Entry.SrcBurstMode=FIX_MODE; Entry.DstBurstMode=INC_MODE; Entry.BurstSize=BUSTER_SIZE_4B; Entry.SrcReqNum=DMA_I2S_RX_REQ; Entry.DstReqNum=DMA_MEM_REQ; Entry.DoneIntCallback=DoneIntCallback; Entry.UnMaskIntCallback=UnMaskIntCallback; Entry.SoftMode=0; Entry.ChMask=1; Entry.CoherentIntEbl=1; if(RxNo==0) { //RX0 //enable chain feature Entry.ChNum=GDMA_I2S_RX0; Entry.NextUnMaskCh=GDMA_I2S_RX1; }else if(RxNo==1) { //RX1 //enable chain feature Entry.ChNum=GDMA_I2S_RX1; Entry.NextUnMaskCh=GDMA_I2S_RX0; }else { GDMA_PRINT("I2S Rx Number %x is invalid\n", RxNo); return 0; } return _GdmaReqEntryIns(&Entry); }
/** * @brief Start GDMA transaction for sending data to PCM * * @param *Src source address * @param *Dst destination address * @param TransCount data length * @param PcmNo PCM channel * @param TxNo PCM Tx number * @param *DoneIntCallback callback func when transcation is done * @param *UnMaskIntCallback callback func when ch mask field is incorrect * @retval 1 success * @retval 0 fail */ int GdmaPcmTx( uint32_t Src, uint32_t Dst, uint8_t PcmNo, uint8_t TxNo, uint16_t TransCount, void (*DoneIntCallback)(uint32_t data), void (*UnMaskIntCallback)(uint32_t data) ) { GdmaReqEntry Entry; Entry.Src= (Src & 0x1FFFFFFF); Entry.Dst= (Dst & 0x1FFFFFFF); Entry.TransCount = TransCount; Entry.SrcBurstMode=INC_MODE; Entry.DstBurstMode=FIX_MODE; Entry.BurstSize=BUSTER_SIZE_4B; Entry.SrcReqNum=DMA_MEM_REQ; Entry.DoneIntCallback=DoneIntCallback; Entry.UnMaskIntCallback=UnMaskIntCallback; Entry.SoftMode=0; //Hardware Mode Entry.ChMask=1; Entry.CoherentIntEbl=0; if(PcmNo==0){//PCM0 Entry.DstReqNum=DMA_PCM_TX0_REQ; if(TxNo==0) { //TX0 //enable chain feature Entry.ChNum=GDMA_PCM0_TX0; Entry.NextUnMaskCh=GDMA_PCM0_TX1; }else if(TxNo==1) { //TX1 //enable chain feature Entry.ChNum=GDMA_PCM0_TX1; Entry.NextUnMaskCh=GDMA_PCM0_TX0; }else { GDMA_PRINT("PCM Tx Number %x is invalid\n", TxNo); return 0; } }else if(PcmNo==1) {//PCM1 Entry.DstReqNum=DMA_PCM_TX1_REQ; if(TxNo==0) { //TX0 //enable chain feature Entry.ChNum=GDMA_PCM1_TX0; Entry.NextUnMaskCh=GDMA_PCM1_TX1; }else if(TxNo==1) { //TX1 //enable chain feature Entry.ChNum=GDMA_PCM1_TX1; Entry.NextUnMaskCh=GDMA_PCM1_TX0; }else { GDMA_PRINT("PCM Tx Number %x is invalid\n", TxNo); return 0; } }else { GDMA_PRINT("PCM Channel %x is invalid\n", PcmNo); return 0; } return _GdmaReqEntryIns(&Entry); }
int _GdmaReqEntryIns(GdmaReqEntry *NewEntry) { uint32_t Data=0; GDMA_PRINT("== << GDMA Control Reg (Channel=%d) >> ===\n", NewEntry->ChNum); GDMA_PRINT(" Channel Source Addr = %x \n", NewEntry->Src); GDMA_PRINT(" Channel Dest Addr = %x \n", NewEntry->Dst); GDMA_PRINT(" Transfer Count=%d\n", NewEntry->TransCount); GDMA_PRINT(" Source DMA Req= DMA_REQ%d\n", NewEntry->SrcReqNum); GDMA_PRINT(" Dest DMA Req= DMA_REQ%d\n", NewEntry->DstReqNum); GDMA_PRINT(" Source Burst Mode=%s\n", NewEntry->SrcBurstMode ? "Fix" : "Inc"); GDMA_PRINT(" Dest Burst Mode=%s\n", NewEntry->DstBurstMode ? "Fix" : "Inc"); GDMA_PRINT(" Burst Size=%s\n", NewEntry->BurstSize ==0 ? "1 transfer" : \ NewEntry->BurstSize ==1 ? "2 transfer" :\ NewEntry->BurstSize ==2 ? "4 transfer" :\ NewEntry->BurstSize ==3 ? "8 transfer" :\ NewEntry->BurstSize ==4 ? "16 transfer" :\ "Error"); GDMA_PRINT(" Hardware/Software Mode = %s\n", NewEntry->SoftMode ? "Soft" : "Hw"); GDMA_PRINT("== << GDMA Control Reg1 (Channel=%d) >> =\n", NewEntry->ChNum); GDMA_PRINT("Channel Done Interrput=%s\n", (NewEntry->DoneIntCallback!=NULL) ? "Enable" : "Disable"); GDMA_PRINT("Channel Unmasked Int=%s\n", (NewEntry->UnMaskIntCallback!=NULL) ? "Enable" : "Disable"); #if !defined (CONFIG_RALINK_RT3052) && !defined (CONFIG_RALINK_RT3883) GDMA_PRINT("Coherent Interrupt =%s\n", (NewEntry->CoherentIntEbl==1)? "Enable" : "Disable"); #endif GDMA_PRINT("Next Unmasked Channel=%d\n", NewEntry->NextUnMaskCh); GDMA_PRINT("Channel Mask=%d\n", NewEntry->ChMask); GDMA_PRINT("========================================\n"); GDMA_WRITE_REG(GDMA_SRC_REG(NewEntry->ChNum), NewEntry->Src); GDMA_PRINT("SrcAddr: Write %0X to %X\n", \ NewEntry->Src, GDMA_SRC_REG(NewEntry->ChNum)); GDMA_WRITE_REG(GDMA_DST_REG(NewEntry->ChNum), NewEntry->Dst); GDMA_PRINT("DstAddr: Write %0X to %X\n", \ NewEntry->Dst, GDMA_DST_REG(NewEntry->ChNum)); Data |= ( (NewEntry->NextUnMaskCh) << NEXT_UNMASK_CH_OFFSET); Data |= ( NewEntry->ChMask << CH_MASK_OFFSET); #if !defined (CONFIG_RALINK_RT3052) && !defined (CONFIG_RALINK_RT3883) Data |= ( NewEntry->CoherentIntEbl << COHERENT_INT_EBL_OFFSET); #endif if(NewEntry->UnMaskIntCallback!=NULL) { Data |= (0x01<<CH_UNMASKINT_EBL_OFFSET); GdmaUnMaskIntCallback[NewEntry->ChNum] = NewEntry->UnMaskIntCallback; } #if defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) Data |= (NewEntry->SrcReqNum << SRC_DMA_REQ_OFFSET); Data |= (NewEntry->DstReqNum << DST_DMA_REQ_OFFSET); #endif GDMA_WRITE_REG(GDMA_CTRL_REG1(NewEntry->ChNum), Data); GDMA_PRINT("CTRL1: Write %08X to %8X\n", Data, GDMA_CTRL_REG1(NewEntry->ChNum)); Data = ((NewEntry->TransCount) << TRANS_CNT_OFFSET); #if defined (CONFIG_RALINK_RT3052) Data |= (NewEntry->SrcReqNum << SRC_DMA_REQ_OFFSET); Data |= (NewEntry->DstReqNum << DST_DMA_REQ_OFFSET); #endif Data |= (NewEntry->SrcBurstMode << SRC_BRST_MODE_OFFSET); Data |= (NewEntry->DstBurstMode << DST_BRST_MODE_OFFSET); Data |= (NewEntry->BurstSize << BRST_SIZE_OFFSET); if(NewEntry->DoneIntCallback!=NULL) { Data |= (0x01<<CH_DONEINT_EBL_OFFSET); GdmaDoneIntCallback[NewEntry->ChNum] = NewEntry->DoneIntCallback; } if(NewEntry->SoftMode) { Data |= (0x01<<MODE_SEL_OFFSET); } Data |= (0x01<<CH_EBL_OFFSET); GDMA_WRITE_REG(GDMA_CTRL_REG(NewEntry->ChNum), Data); GDMA_PRINT("CTRL: Write %08X to %8X\n", Data, GDMA_CTRL_REG(NewEntry->ChNum)); //if there is no interrupt handler, this function will //return 1 until GDMA done. if(NewEntry->DoneIntCallback==NULL) { //wait for GDMA processing done #if defined (CONFIG_RALINK_RT3052) while((GDMA_READ_REG(RALINK_GDMAISTS) & (0x1<<NewEntry->ChNum))==0); //write 1 clear GDMA_WRITE_REG(RALINK_GDMAISTS, 1<< NewEntry->ChNum); #elif defined (CONFIG_RALINK_RT3883) || defined (CONFIG_RALINK_RT3352) || defined (CONFIG_RALINK_RT5350) while((GDMA_READ_REG(RALINK_GDMA_DONEINT) & (0x1<<NewEntry->ChNum))==0); //write 1 clear GDMA_WRITE_REG(RALINK_GDMA_DONEINT, 1<< NewEntry->ChNum); #endif } return 1; }