void dma_resume_channel(int channel)
{
    /* Resume - must reinit to where it left off (so the docs say) */
    unsigned long control = DMAC_CH_CONTROL(channel);
    if ((control & 0x7ff) == 0)
        return; /* empty */

    DMAC_INT_TC_CLEAR = (1<<channel);
    DMAC_INT_ERR_CLEAR = (1<<channel);
    DMAC_CH_SRC_ADDR(channel) = DMAC_CH_SRC_ADDR(channel);
    DMAC_CH_DST_ADDR(channel) = DMAC_CH_DST_ADDR(channel);
    DMAC_CH_LLI(channel) = DMAC_CH_LLI(channel);
    DMAC_CH_CONTROL(channel) = control;
    bitset32(&DMAC_CH_CONFIGURATION(channel), (1<<0));
}
Beispiel #2
0
void dma_enable_channel(int channel, void *src, void *dst, int peri,
                        int flow_controller, bool src_inc, bool dst_inc,
                        size_t size, int nwords, void (*callback)(void))
{
    dma_callback[channel] = callback;

    /* Clear any pending interrupts leftover from previous operation */
    DMAC_INT_TC_CLEAR  = (1<<channel);
    DMAC_INT_ERR_CLEAR = (1<<channel);

    DMAC_CH_SRC_ADDR(channel) = (int)src;
    DMAC_CH_DST_ADDR(channel) = (int)dst;

    /* When LLI is 0 channel is disabled upon transfer completion */
    DMAC_CH_LLI(channel) = 0;

    /*  Channel Control Register */
    DMAC_CH_CONTROL(channel) =
         ((1<<31)                 /* LLI triggers terminal count interrupt */
     /* | (1<<30) */              /* cacheable  = 1,  non = 0 */
     /* | (1<<29) */              /* bufferable = 1,  non = 0 */
     /* | (1<<28) */              /* privileged = 1, user = 0 */
        | (dst_inc? (1<<27): 0)   /* specify address increment */
        | (src_inc? (1<<26): 0)   /* specify address increment */
       /* [25:24] */              /* undefined  */
        | (2<<21)                 /* dst width = word, 32bit */
        | (2<<18)                 /* src width = word, 32bit */
       /* OF uses transfers of 4 * 32 bits words on memory, i2sin, i2sout */
       /* OF uses transfers of 8 * 32 bits words on SD */
        | (nwords<<15)            /* dst size  */
        | (nwords<<12)            /* src size  */
        | ((size & 0x7ff)<<0));   /* transfer size */

    /*  Channel Config Register  */
    DMAC_CH_CONFIGURATION(channel) =
       /* [31:19] */              /* Read undefined. Write as zero  */
       /* (0<<18) */              /* Halt Bit    */
       /* (0<<17) */              /* Active Bit  */
       /* (0<<16) */              /* Lock Bit    */
          (1<<15)                 /* terminal count interrupt mask */
        | (1<<14)                 /* interrupt error mask */
        | (flow_controller<<11)   /* flow controller is peripheral or SDMAC */
       /* we set the same peripheral as source and destination because we
        * always use memory-to-peripheral or peripheral-to-memory transfers */
        | (peri<<6)               /* dst peripheral */
        | (peri<<1)               /* src peripheral */
        | (1<<0);                 /* enable channel */
}
static irqreturn_t str8100_dma_tc_irq_handler(int this_irq, void *dev_id, struct pt_regs *regs)
{
	u32 dma_tc_status,tot_size;
	u32 len;
//printk("%s: this_irq=%d\n",__FUNCTION__,this_irq);

	HAL_INTC_DISABLE_INTERRUPT_SOURCE(this_irq);
	//todo:

    HAL_DMAC_READ_TERMINAL_COUNT_INTERRUPT_STATUS(dma_tc_status);
printk("%s: this_irq=%d, dma_tc_status=%.8x\n",__FUNCTION__,this_irq,dma_tc_status);

#ifdef I2S_WM8772_DMAC_LLP_RING_TEST
	u32 i;
    /*
     * For LLP ring test, the TC interrupt shoule not happen!!
     */
	for(i=0;i<8;i++)
	if (dma_tc_status & DMAC_CH_ID(i)){                      
		HAL_DMAC_CLEAR_TERMINAL_COUNT_INTERRUPT_STATUS(DMAC_CH_ID(i));
		printk("%s: channel %d: Error!! there should be no tc irq happened!!\n",__FUNCTION__,i);
	}

#else
    /*
     * For this case, it's recommended to set I2S_WM8772_DMAC_LLP_NUM = 1
     */
    /*
     * For DMA's Tx for I2S Left Channel
     */
    if (dma_tc_status & DMAC_CH_ID(i2s_wm8772_dma_left_tx_channel))
    {                      
        HAL_DMAC_DISABLE_CHANNEL(i2s_wm8772_dma_left_tx_channel);
        
        HAL_DMAC_CLEAR_TERMINAL_COUNT_INTERRUPT_STATUS(DMAC_CH_ID(i2s_wm8772_dma_left_tx_channel));

        /*
         * Re-initialize DMA's channel for Left_Tx
         */
        DMAC_CH_SRC_ADDR(i2s_wm8772_dma_left_tx_channel) = i2s_left_tx_channel_dma_llp_desc[0].SrcAddr;

        DMAC_CH_DST_ADDR(i2s_wm8772_dma_left_tx_channel) = i2s_left_tx_channel_dma_llp_desc[0].DstAddr;

        /*
         * Note this macro DMAC_CH_SIZE is to configure TOT_SIZE field which is the total transfer
         * number of source transfer width!
         */        
        tot_size = Hal_Dmac_Get_Channel_Transfer_Unit_Number(I2S_WM8772_BUFFER_SIZE * 4, DMAC_CH_SRC_WIDTH_32_BITS);

        DMAC_CH_SIZE(i2s_wm8772_dma_left_tx_channel) = tot_size & 0x0FFF;

        HAL_DMAC_ENABLE_CHANNEL(i2s_wm8772_dma_left_tx_channel);
    }


    /*
     * For DMA's Tx for I2S Right Channel
     */
    if (dma_tc_status & DMAC_CH_ID(i2s_wm8772_dma_right_tx_channel))
    {                      
        HAL_DMAC_DISABLE_CHANNEL(i2s_wm8772_dma_right_tx_channel);
        
        HAL_DMAC_CLEAR_TERMINAL_COUNT_INTERRUPT_STATUS(DMAC_CH_ID(i2s_wm8772_dma_right_tx_channel));

        /*
         * Re-initialize DMA's channel for Right_Tx
         */
        DMAC_CH_SRC_ADDR(i2s_wm8772_dma_right_tx_channel) = i2s_right_tx_channel_dma_llp_desc[0].SrcAddr;

        DMAC_CH_DST_ADDR(i2s_wm8772_dma_right_tx_channel) = i2s_right_tx_channel_dma_llp_desc[0].DstAddr;

        /*
         * Note this macro DMAC_CH_SIZE is to configure TOT_SIZE field which is the total transfer
         * number of source transfer width!
         */        
        tot_size = Hal_Dmac_Get_Channel_Transfer_Unit_Number(I2S_WM8772_BUFFER_SIZE * 4, DMAC_CH_SRC_WIDTH_32_BITS);

        DMAC_CH_SIZE(i2s_wm8772_dma_right_tx_channel) = tot_size & 0x0FFF;

        HAL_DMAC_ENABLE_CHANNEL(i2s_wm8772_dma_right_tx_channel);
    }


    /*
     * For DMA's Rx for I2S Left Channel
     */
    if (dma_tc_status & DMAC_CH_ID(i2s_wm8772_dma_left_rx_channel))
    {                      
        HAL_DMAC_DISABLE_CHANNEL(i2s_wm8772_dma_left_rx_channel);
        
        HAL_DMAC_CLEAR_TERMINAL_COUNT_INTERRUPT_STATUS(DMAC_CH_ID(i2s_wm8772_dma_left_rx_channel));

        /*
         * Re-initialize DMA's channel for Left_Rx
         */
        DMAC_CH_SRC_ADDR(i2s_wm8772_dma_left_rx_channel) = i2s_left_rx_channel_dma_llp_desc[0].SrcAddr;

        DMAC_CH_DST_ADDR(i2s_wm8772_dma_left_rx_channel) = i2s_left_rx_channel_dma_llp_desc[0].DstAddr;

        /*
         * Note this macro DMAC_CH_SIZE is to configure TOT_SIZE field which is the total transfer
         * number of source transfer width!
         */        
        tot_size = Hal_Dmac_Get_Channel_Transfer_Unit_Number(I2S_WM8772_BUFFER_SIZE * 4, DMAC_CH_SRC_WIDTH_32_BITS);

        DMAC_CH_SIZE(i2s_wm8772_dma_left_rx_channel) = tot_size & 0x0FFF;

        HAL_DMAC_ENABLE_CHANNEL(i2s_wm8772_dma_left_rx_channel);
    }


    /*
     * For DMA's Rx for I2S Right Channel
     */
    if (dma_tc_status & DMAC_CH_ID(i2s_wm8772_dma_right_rx_channel))
    {                      
        HAL_DMAC_DISABLE_CHANNEL(i2s_wm8772_dma_right_rx_channel);
        
        HAL_DMAC_CLEAR_TERMINAL_COUNT_INTERRUPT_STATUS(DMAC_CH_ID(i2s_wm8772_dma_right_rx_channel));

        /*
         * Re-initialize DMA's channel for Right_Rx
         */
        DMAC_CH_SRC_ADDR(i2s_wm8772_dma_right_rx_channel) = i2s_right_rx_channel_dma_llp_desc[0].SrcAddr;

        DMAC_CH_DST_ADDR(i2s_wm8772_dma_right_rx_channel) = i2s_right_rx_channel_dma_llp_desc[0].DstAddr;

        /*
         * Note this macro DMAC_CH_SIZE is to configure TOT_SIZE field which is the total transfer
         * number of source transfer width!
         */        
        tot_size = Hal_Dmac_Get_Channel_Transfer_Unit_Number(I2S_WM8772_BUFFER_SIZE * 4, DMAC_CH_SRC_WIDTH_32_BITS);

        DMAC_CH_SIZE(i2s_wm8772_dma_right_rx_channel) = tot_size & 0x0FFF;

        HAL_DMAC_ENABLE_CHANNEL(i2s_wm8772_dma_right_rx_channel);
    }
#endif



	HAL_INTC_CLEAR_EDGE_TRIGGER_INTERRUPT(this_irq);
	HAL_INTC_ENABLE_INTERRUPT_SOURCE(this_irq);

    return IRQ_HANDLED;
}