// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Ingenic JZ4780 DMA controller
*
* Copyright (c) 2015 Imagination Technologies
* Author: Alex Smith <alex@alex-smith.me.uk>
*/
#include <linux/clk.h>
#include <linux/dmapool.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include "dmaengine.h"
#include "virt-dma.h"
/* Global registers. */
#define JZ_DMA_REG_DMAC 0x00
#define JZ_DMA_REG_DIRQP 0x04
#define JZ_DMA_REG_DDR 0x08
#define JZ_DMA_REG_DDRS 0x0c
#define JZ_DMA_REG_DCKE 0x10
#define JZ_DMA_REG_DCKES 0x14
#define JZ_DMA_REG_DCKEC 0x18
#define JZ_DMA_REG_DMACP 0x1c
#define JZ_DMA_REG_DSIRQP 0x20
#define JZ_DMA_REG_DSIRQM 0x24
#define JZ_DMA_REG_DCIRQP 0x28
#define JZ_DMA_REG_DCIRQM 0x2c
/* Per-channel registers. */
#define JZ_DMA_REG_CHAN(n) (n * 0x20)
#define JZ_DMA_REG_DSA 0x00
#define JZ_DMA_REG_DTA 0x04
#define JZ_DMA_REG_DTC 0x08
#define JZ_DMA_REG_DRT 0x0c
#define JZ_DMA_REG_DCS 0x10
#define JZ_DMA_REG_DCM 0x14
#define JZ_DMA_REG_DDA 0x18
#define JZ_DMA_REG_DSD 0x1c
#define JZ_DMA_DMAC_DMAE BIT(0)
#define JZ_DMA_DMAC_AR BIT(2)
#define JZ_DMA_DMAC_HLT BIT(3)
#define JZ_DMA_DMAC_FAIC BIT(27)
#define JZ_DMA_DMAC_FMSC BIT(31)
#define JZ_DMA_DRT_AUTO 0x8
#define JZ_DMA_DCS_CTE BIT(0)
#define JZ_DMA_DCS_HLT BIT(2)
#define JZ_DMA_DCS_TT BIT(3)
#define JZ_DMA_DCS_AR BIT(4)
#define JZ_DMA_DCS_DES8 BIT(30)
#define JZ_DMA_DCM_LINK BIT(0)
#define JZ_DMA_DCM_TIE BIT(1)
#define JZ_DMA_DCM_STDE BIT(2)
#define JZ_DMA_DCM_TSZ_SHIFT 8
#define JZ_DMA_DCM_TSZ_MASK (0x7 << JZ_DMA_DCM_TSZ_SHIFT)
#define JZ_DMA_DCM_DP_SHIFT 12
#define JZ_DMA_DCM_SP_SHIFT 14
#define JZ_DMA_DCM_DAI BIT(22)
#define JZ_DMA_DCM_SAI BIT(23)
#define JZ_DMA_SIZE_4_BYTE 0x0
#define JZ_DMA_SIZE_1_BYTE 0x1
#define JZ_DMA_SIZE_2_BYTE 0x2
#define JZ_DMA_SIZE_16_BYTE 0x3
#define JZ_DMA_SIZE_32_BYTE 0x4
#define JZ_DMA_SIZE_64_BYTE 0x5
#define JZ_DMA_SIZE_128_BYTE 0x6
#define JZ_DMA_WIDTH_32_BIT 0x0
#define JZ_DMA_WIDTH_8_BIT 0x1
#define JZ_DMA_WIDTH_16_BIT 0x2
#define JZ_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
#define JZ4780_DMA_CTRL_OFFSET 0x1000
/* macros for use with jz4780_dma_soc_data.flags */
#define JZ_SOC_DATA_ALLOW_LEGACY_DT BIT(0)
#define JZ_SOC_DATA_PROGRAMMABLE_DMA BIT(1)
#define JZ_SOC_DATA_PER_CHAN_PM BIT(2)
#define JZ_SOC_DATA_NO_DCKES_DCKEC BIT(3)
#define JZ_SOC_DATA_BREAK_LINKS BIT(4)
/**
* struct jz4780_dma_hwdesc - descriptor structure read by the DMA controller.
* @dcm: value for the DCM (channel command) register
* @dsa: source address
* @dta: target address
* @dtc: transfer count (number of blocks of the transfer size specified in DCM
* to transfer) in the low 24 bits, offset of the next descriptor from the
* descriptor base address in the upper 8 bits.
*/
struct jz4780_dma_hwdesc {
uint32_t dcm;
uint32_t dsa;
uint32_t dta;
uint32_t dtc;
};
/* Size of allocations for hardware descriptor blocks. */
#define JZ_DMA_DESC_BLOCK_SIZE PAGE_SIZE
#define JZ_DMA_MAX_DESC \
(JZ_DMA_DESC_BLOCK_SIZE / sizeof(struct jz4780_dma_hwdesc))
struct jz4780_dma_desc {
struct virt_dma_desc vdesc;
struct jz4780_dma_hwdesc *desc;
dma_addr_t desc_phys;
unsigned int count;
enum dma_transaction_type type;
uint32_t status;
};
struct jz4780_dma_chan {
struct virt_dma_chan vchan;
unsigned int id;
struct dma_pool *desc_pool;
uint32_t transfer_type;
uint32_t transfer_shift;
struct dma_slave_config config;
struct jz4780_dma_desc *desc;
unsigned int curr_hwdesc;
};
struct jz4780_dma_soc_data {
unsigned int nb_channels;
unsigned int transfer_ord_max;
unsigned long flags;
};
struct jz4780_dma_dev {
struct dma_device dma_device;
void __iomem *chn_base;
void __iomem *ctrl_base;
struct clk *clk;
unsigned int irq;
const struct jz4780_dma_soc_data *soc_data;
uint32_t chan_reserved;
struct jz4780_dma_chan chan[];
};
struct jz4780_dma_filter_data {
uint32_t transfer_type;
int channel;
};
static inline struct jz4780_dma_chan *to_jz4780_dma_chan(struct dma_chan *chan)
{
return container_of(chan, struct jz4780_dma_chan, vchan.chan);
}
static inline struct jz4780_dma_desc *to_jz4780_dma_desc(
struct virt_dma_desc *vdesc)
{
return container_of(vdesc, struct jz4780_dma_desc, vdesc);
}
static inline struct jz4780_dma_dev *jz4780_dma_chan_parent(
struct jz4780_dma_chan *jzchan)
{
return container_of(jzchan->vchan.chan.device, struct jz4780_dma_dev,
dma_device);
}
static inline uint32_t jz4780_dma_chn_readl(struct jz4780_dma_dev *jzdma,
unsigned int chn, unsigned int reg)
{
return readl(jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
}
static inline void jz4780_dma_chn_writel(struct jz4780_dma_dev *jzdma,
unsigned int chn, unsigned int reg, uint32_t val)
{
writel(val, jzdma->chn_base + reg + JZ_DMA_REG_CHAN(chn));
}
static inline uint32_t jz4780_dma_ctrl_readl(struct jz4780_dma_dev *jzdma,
unsigned int reg)
{
return readl(jzdma->ctrl_base + reg);
}
static inline void jz4780_dma_ctrl_writel(struct jz4780_dma_dev *jzdma,
unsigned int reg, uint32_t val)
{
writel(val, jzdma->ctrl_base + reg);
}
static inline void