// SPDX-License-Identifier: GPL-2.0
// (C) 2017-2018 Synopsys, Inc. (www.synopsys.com)
/*
* Synopsys DesignWare AXI DMA Controller driver.
*
* Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
*/
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/dmaengine.h>
#include <linux/dmapool.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/types.h>
#include "dw-axi-dmac.h"
#include "../dmaengine.h"
#include "../virt-dma.h"
/*
* The set of bus widths supported by the DMA controller. DW AXI DMAC supports
* master data bus width up to 512 bits (for both AXI master interfaces), but
* it depends on IP block configurarion.
*/
#define AXI_DMA_BUSWIDTHS \
(DMA_SLAVE_BUSWIDTH_1_BYTE | \
DMA_SLAVE_BUSWIDTH_2_BYTES | \
DMA_SLAVE_BUSWIDTH_4_BYTES | \
DMA_SLAVE_BUSWIDTH_8_BYTES | \
DMA_SLAVE_BUSWIDTH_16_BYTES | \
DMA_SLAVE_BUSWIDTH_32_BYTES | \
DMA_SLAVE_BUSWIDTH_64_BYTES)
static inline void
axi_dma_iowrite32(struct axi_dma_chip *chip, u32 reg, u32 val)
{
iowrite32(val, chip->regs + reg);
}
static inline u32 axi_dma_ioread32(struct axi_dma_chip *chip, u32 reg)
{
return ioread32(chip->regs + reg);
}
static inline void
axi_chan_iowrite32(struct axi_dma_chan *chan, u32 reg, u32 val)
{
iowrite32(val, chan->chan_regs + reg);
}
static inline u32 axi_chan_ioread32(struct axi_dma_chan *chan, u32 reg)
{
return ioread32(chan->chan_regs + reg);
}
static inline void
axi_chan_iowrite64(struct axi_dma_chan *chan, u32 reg, u64 val)
{
/*
* We split one 64 bit write for two 32 bit write as some HW doesn't
* support 64 bit access.
*/
iowrite32(lower_32_bits(val), chan->chan_regs + reg);
iowrite32(upper_32_bits(val), chan->chan_regs + reg + 4);
}
static inline void axi_dma_disable(struct axi_dma_chip *chip)
{
u32 val;
val = axi_dma_ioread32(chip, DMAC_CFG);
val &= ~DMAC_EN_MASK;
axi_dma_iowrite32(chip, DMAC_CFG, val);
}
static inline void axi_dma_enable(struct axi_dma_chip *chip)
{
u32 val;
val = axi_dma_ioread32(chip, DMAC_CFG);
val |= DMAC_EN_MASK;
axi_dma_iowrite32(chip, DMAC_CFG, val);
}
static inline void axi_dma_irq_disable(struct axi_dma_chip *chip)
{
u32 val;
val = axi_dma_ioread32(chip, DMAC_CFG);
val &= ~INT_EN_MASK;
axi_dma_iowrite32(chip, DMAC_CFG, val);
}
static inline void axi_dma_irq_enable(struct axi_dma_chip *chip)
{
u32 val;
val = axi_dma_ioread32(chip, DMAC_CFG);
val |= INT_EN_MASK;
axi_dma_iowrite32(chip, DMAC_CFG, val);
}
static inline void axi_chan_irq_disable(struct axi_dma_chan *chan, u32 irq_mask)
{
u32 val;
if (likely(irq_mask == DWAXIDMAC_IRQ_ALL)) {
axi_chan_iowrite32(chan, CH_INTSTATUS_ENA, DWAXIDMAC_IRQ_NONE);
} else {
val = axi_chan_ioread32(chan, CH_INTSTATUS_ENA);
val &= ~irq_mask;
axi_chan_iowrite32(chan, CH_INTSTATUS_ENA, val);
}
}
static inline void axi_chan_irq_set(struct axi_dma_chan *chan, u32 irq_mask)
{
axi_chan_iowrite32(chan, CH_INTSTATUS_ENA, irq_mask);
}
static inline void axi_chan_irq_sig_set(struct axi_dma_chan *chan, u32 irq_mask)
{
axi_chan_iowrite32(chan, CH_INTSIGNAL_ENA, irq_mask);
}
static inline void axi_chan_irq_clear(struct axi_dma_chan *chan, u32 irq_mask)
{
axi_chan_iowrite32(chan, CH_INTCLEAR, irq_mask);
}
static inline u32 axi_chan_irq_read(struct axi_dma_chan *chan)
{
return axi_chan_ioread32(chan, CH_INTSTATUS);
}
static inline void axi_chan_disable(struct axi_dma_chan *chan)
{
u32 val;
val = axi_dma_ioread32(chan->chip, DMAC_CHEN);
val &= ~(BIT(chan->id) << DMAC_CHAN_EN_SHIFT);
val |= BIT(chan->id) << DMAC_CHAN_EN_WE_SHIFT;
axi_dma_iowrite32(chan->chip, <