e2dfce24f4
It currently assumes that there are always four channels, it would cause the error if there is actually less than four channels. Change that by getting number of channel from device tree. For backwards-compatibility, it uses the default value (i.e. 4) when there is no 'dma-channels' information in dts. Signed-off-by: Zong Li <zong.li@sifive.com> Acked-by: Palmer Dabbelt <palmer@rivosinc.com> Reviewed-by: Bin Meng <bmeng.cn@gmail.com> Link: https://lore.kernel.org/r/f08a95b6582a51712c5b2c3cb859136d07bfa8b9.1648461096.git.zong.li@sifive.com Signed-off-by: Vinod Koul <vkoul@kernel.org>
121 lines
2.9 KiB
C
121 lines
2.9 KiB
C
/* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
/*
|
|
* SiFive FU540 Platform DMA driver
|
|
* Copyright (C) 2019 SiFive
|
|
*
|
|
* Based partially on:
|
|
* - drivers/dma/fsl-edma.c
|
|
* - drivers/dma/dw-edma/
|
|
* - drivers/dma/pxa-dma.c
|
|
*
|
|
* See the following sources for further documentation:
|
|
* - Chapter 12 "Platform DMA Engine (PDMA)" of
|
|
* SiFive FU540-C000 v1.0
|
|
* https://static.dev.sifive.com/FU540-C000-v1.0.pdf
|
|
*/
|
|
#ifndef _SF_PDMA_H
|
|
#define _SF_PDMA_H
|
|
|
|
#include <linux/dmaengine.h>
|
|
#include <linux/dma-direction.h>
|
|
|
|
#include "../dmaengine.h"
|
|
#include "../virt-dma.h"
|
|
|
|
#define PDMA_MAX_NR_CH 4
|
|
|
|
#define PDMA_BASE_ADDR 0x3000000
|
|
#define PDMA_CHAN_OFFSET 0x1000
|
|
|
|
/* Register Offset */
|
|
#define PDMA_CTRL 0x000
|
|
#define PDMA_XFER_TYPE 0x004
|
|
#define PDMA_XFER_SIZE 0x008
|
|
#define PDMA_DST_ADDR 0x010
|
|
#define PDMA_SRC_ADDR 0x018
|
|
#define PDMA_ACT_TYPE 0x104 /* Read-only */
|
|
#define PDMA_REMAINING_BYTE 0x108 /* Read-only */
|
|
#define PDMA_CUR_DST_ADDR 0x110 /* Read-only*/
|
|
#define PDMA_CUR_SRC_ADDR 0x118 /* Read-only*/
|
|
|
|
/* CTRL */
|
|
#define PDMA_CLEAR_CTRL 0x0
|
|
#define PDMA_CLAIM_MASK GENMASK(0, 0)
|
|
#define PDMA_RUN_MASK GENMASK(1, 1)
|
|
#define PDMA_ENABLE_DONE_INT_MASK GENMASK(14, 14)
|
|
#define PDMA_ENABLE_ERR_INT_MASK GENMASK(15, 15)
|
|
#define PDMA_DONE_STATUS_MASK GENMASK(30, 30)
|
|
#define PDMA_ERR_STATUS_MASK GENMASK(31, 31)
|
|
|
|
/* Transfer Type */
|
|
#define PDMA_FULL_SPEED 0xFF000008
|
|
|
|
/* Error Recovery */
|
|
#define MAX_RETRY 1
|
|
|
|
#define SF_PDMA_REG_BASE(ch) (pdma->membase + (PDMA_CHAN_OFFSET * (ch)))
|
|
|
|
struct pdma_regs {
|
|
/* read-write regs */
|
|
void __iomem *ctrl; /* 4 bytes */
|
|
|
|
void __iomem *xfer_type; /* 4 bytes */
|
|
void __iomem *xfer_size; /* 8 bytes */
|
|
void __iomem *dst_addr; /* 8 bytes */
|
|
void __iomem *src_addr; /* 8 bytes */
|
|
|
|
/* read-only */
|
|
void __iomem *act_type; /* 4 bytes */
|
|
void __iomem *residue; /* 8 bytes */
|
|
void __iomem *cur_dst_addr; /* 8 bytes */
|
|
void __iomem *cur_src_addr; /* 8 bytes */
|
|
};
|
|
|
|
struct sf_pdma_desc {
|
|
u32 xfer_type;
|
|
u64 xfer_size;
|
|
u64 dst_addr;
|
|
u64 src_addr;
|
|
struct virt_dma_desc vdesc;
|
|
struct sf_pdma_chan *chan;
|
|
bool in_use;
|
|
enum dma_transfer_direction dirn;
|
|
struct dma_async_tx_descriptor *async_tx;
|
|
};
|
|
|
|
enum sf_pdma_pm_state {
|
|
RUNNING = 0,
|
|
SUSPENDED,
|
|
};
|
|
|
|
struct sf_pdma_chan {
|
|
struct virt_dma_chan vchan;
|
|
enum dma_status status;
|
|
enum sf_pdma_pm_state pm_state;
|
|
u32 slave_id;
|
|
struct sf_pdma *pdma;
|
|
struct sf_pdma_desc *desc;
|
|
struct dma_slave_config cfg;
|
|
u32 attr;
|
|
dma_addr_t dma_dev_addr;
|
|
u32 dma_dev_size;
|
|
struct tasklet_struct done_tasklet;
|
|
struct tasklet_struct err_tasklet;
|
|
struct pdma_regs regs;
|
|
spinlock_t lock; /* protect chan data */
|
|
bool xfer_err;
|
|
int txirq;
|
|
int errirq;
|
|
int retries;
|
|
};
|
|
|
|
struct sf_pdma {
|
|
struct dma_device dma_dev;
|
|
void __iomem *membase;
|
|
void __iomem *mappedbase;
|
|
u32 n_chans;
|
|
struct sf_pdma_chan chans[];
|
|
};
|
|
|
|
#endif /* _SF_PDMA_H */
|