/*
* Freescale MPC85xx, MPC83xx DMA Engine support
*
* Copyright (C) 2007 Freescale Semiconductor, Inc. All rights reserved.
*
* Author:
* Zhang Wei <wei.zhang@freescale.com>, Jul 2007
* Ebony Zhu <ebony.zhu@freescale.com>, May 2007
*
* Description:
* DMA engine driver for Freescale MPC8540 DMA controller, which is
* also fit for MPC8560, MPC8555, MPC8548, MPC8641, and etc.
* The support for MPC8349 DMA contorller is also added.
*
* This driver instructs the DMA controller to issue the PCI Read Multiple
* command for PCI read operations, instead of using the default PCI Read Line
* command. Please be aware that this setting may result in read pre-fetching
* on some platforms.
*
* This is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
*/
#include <linux/init.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/dmaengine.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/of_platform.h>
#include "fsldma.h"
static void dma_init(struct fsl_dma_chan *fsl_chan)
{
/* Reset the channel */
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, 0, 32);
switch (fsl_chan->feature & FSL_DMA_IP_MASK) {
case FSL_DMA_IP_85XX:
/* Set the channel to below modes:
* EIE - Error interrupt enable
* EOSIE - End of segments interrupt enable (basic mode)
* EOLNIE - End of links interrupt enable
*/
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EIE
| FSL_DMA_MR_EOLNIE | FSL_DMA_MR_EOSIE, 32);
break;
case FSL_DMA_IP_83XX:
/* Set the channel to below modes:
* EOTIE - End-of-transfer interrupt enable
* PRC_RM - PCI read multiple
*/
DMA_OUT(fsl_chan, &fsl_chan->reg_base->mr, FSL_DMA_MR_EOTIE
| FSL_DMA_MR_PRC_RM, 32);
break;
}
}
static void set_sr(struct fsl_dma_chan *fsl_chan, u32 val)
{
DMA_OUT(fsl_chan, &fsl_chan->reg_base->sr, val, 32);
}
static u32 get_sr(struct fsl_dma_chan *fsl_chan)
{
return DMA_IN(fsl_chan, &fsl_chan->reg_base->sr, 32);
}
static void set_desc_cnt(struct fsl_dma_chan *fsl_chan,
struct fsl_dma_ld_hw *hw, u32 count)
{
hw->count = CPU_TO_DMA(fsl_chan, count, 32);
}
static void set_desc_src(struct fsl_dma_chan *fsl_chan,
struct fsl_dma_ld_hw *hw, dma_addr_t src)
{
u64 snoop_bits;
snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
? ((u64)FSL_DMA_SATR_SREADTYPE_SNOOP_READ << 32) : 0;
hw->src_addr = CPU_TO_DMA(fsl_chan, snoop_bits | src, 64);
}
static void set_desc_dest(struct fsl_dma_chan *fsl_chan,
struct fsl_dma_ld_hw *hw, dma_addr_t dest)
{
u64 snoop_bits;
snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_85XX)
? ((u64)FSL_DMA_DATR_DWRITETYPE_SNOOP_WRITE << 32) : 0;
hw->dst_addr = CPU_TO_DMA(fsl_chan, snoop_bits | dest, 64);
}
static void set_desc_next(struct fsl_dma_chan *fsl_chan,
struct fsl_dma_ld_hw *hw, dma_addr_t next)
{
u64 snoop_bits;
snoop_bits = ((fsl_chan->feature & FSL_DMA_IP_MASK) == FSL_DMA_IP_83XX)
? FSL_DMA_SNEN : 0;
hw->next_ln_addr = CPU_TO_DMA(fsl_chan, snoop_bits | next, 64);
}
static void set_cdar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
{
DMA_OUT(fsl_chan, &fsl_chan->reg_base->cdar, addr | FSL_DMA_SNEN, 64);
}
static dma_addr_t get_cdar(struct fsl_dma_chan *fsl_chan)
{
return DMA_IN(fsl_chan, &fsl_chan->reg_base->cdar, 64) & ~FSL_DMA_SNEN;
}
static void set_ndar(struct fsl_dma_chan *fsl_chan, dma_addr_t addr)
{
DMA_OUT(fsl_chan, &fsl_chan->reg_base->ndar, addr, 64);
}
static dma_addr_t get_ndar(struct fsl_dma_chan *fsl_chan)
{
return DMA_IN(fsl_chan, &fsl_chan->reg_base->ndar, 64);
}