162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2013-2014 Allwinner Tech Co., Ltd 462306a36Sopenharmony_ci * Author: Sugar <shuge@allwinnertech.com> 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright (C) 2014 Maxime Ripard 762306a36Sopenharmony_ci * Maxime Ripard <maxime.ripard@free-electrons.com> 862306a36Sopenharmony_ci */ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/clk.h> 1162306a36Sopenharmony_ci#include <linux/delay.h> 1262306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1362306a36Sopenharmony_ci#include <linux/dmaengine.h> 1462306a36Sopenharmony_ci#include <linux/dmapool.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/module.h> 1762306a36Sopenharmony_ci#include <linux/of.h> 1862306a36Sopenharmony_ci#include <linux/of_dma.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/reset.h> 2162306a36Sopenharmony_ci#include <linux/slab.h> 2262306a36Sopenharmony_ci#include <linux/types.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "virt-dma.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * Common registers 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci#define DMA_IRQ_EN(x) ((x) * 0x04) 3062306a36Sopenharmony_ci#define DMA_IRQ_HALF BIT(0) 3162306a36Sopenharmony_ci#define DMA_IRQ_PKG BIT(1) 3262306a36Sopenharmony_ci#define DMA_IRQ_QUEUE BIT(2) 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci#define DMA_IRQ_CHAN_NR 8 3562306a36Sopenharmony_ci#define DMA_IRQ_CHAN_WIDTH 4 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define DMA_IRQ_STAT(x) ((x) * 0x04 + 0x10) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define DMA_STAT 0x30 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Offset between DMA_IRQ_EN and DMA_IRQ_STAT limits number of channels */ 4362306a36Sopenharmony_ci#define DMA_MAX_CHANNELS (DMA_IRQ_CHAN_NR * 0x10 / 4) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* 4662306a36Sopenharmony_ci * sun8i specific registers 4762306a36Sopenharmony_ci */ 4862306a36Sopenharmony_ci#define SUN8I_DMA_GATE 0x20 4962306a36Sopenharmony_ci#define SUN8I_DMA_GATE_ENABLE 0x4 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SUNXI_H3_SECURE_REG 0x20 5262306a36Sopenharmony_ci#define SUNXI_H3_DMA_GATE 0x28 5362306a36Sopenharmony_ci#define SUNXI_H3_DMA_GATE_ENABLE 0x4 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * Channels specific registers 5662306a36Sopenharmony_ci */ 5762306a36Sopenharmony_ci#define DMA_CHAN_ENABLE 0x00 5862306a36Sopenharmony_ci#define DMA_CHAN_ENABLE_START BIT(0) 5962306a36Sopenharmony_ci#define DMA_CHAN_ENABLE_STOP 0 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define DMA_CHAN_PAUSE 0x04 6262306a36Sopenharmony_ci#define DMA_CHAN_PAUSE_PAUSE BIT(1) 6362306a36Sopenharmony_ci#define DMA_CHAN_PAUSE_RESUME 0 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci#define DMA_CHAN_LLI_ADDR 0x08 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define DMA_CHAN_CUR_CFG 0x0c 6862306a36Sopenharmony_ci#define DMA_CHAN_MAX_DRQ_A31 0x1f 6962306a36Sopenharmony_ci#define DMA_CHAN_MAX_DRQ_H6 0x3f 7062306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_DRQ_A31(x) ((x) & DMA_CHAN_MAX_DRQ_A31) 7162306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_DRQ_H6(x) ((x) & DMA_CHAN_MAX_DRQ_H6) 7262306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_MODE_A31(x) (((x) & 0x1) << 5) 7362306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_MODE_H6(x) (((x) & 0x1) << 8) 7462306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_BURST_A31(x) (((x) & 0x3) << 7) 7562306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_BURST_H3(x) (((x) & 0x3) << 6) 7662306a36Sopenharmony_ci#define DMA_CHAN_CFG_SRC_WIDTH(x) (((x) & 0x3) << 9) 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_DRQ_A31(x) (DMA_CHAN_CFG_SRC_DRQ_A31(x) << 16) 7962306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_DRQ_H6(x) (DMA_CHAN_CFG_SRC_DRQ_H6(x) << 16) 8062306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_MODE_A31(x) (DMA_CHAN_CFG_SRC_MODE_A31(x) << 16) 8162306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_MODE_H6(x) (DMA_CHAN_CFG_SRC_MODE_H6(x) << 16) 8262306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_BURST_A31(x) (DMA_CHAN_CFG_SRC_BURST_A31(x) << 16) 8362306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_BURST_H3(x) (DMA_CHAN_CFG_SRC_BURST_H3(x) << 16) 8462306a36Sopenharmony_ci#define DMA_CHAN_CFG_DST_WIDTH(x) (DMA_CHAN_CFG_SRC_WIDTH(x) << 16) 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci#define DMA_CHAN_CUR_SRC 0x10 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci#define DMA_CHAN_CUR_DST 0x14 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define DMA_CHAN_CUR_CNT 0x18 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci#define DMA_CHAN_CUR_PARA 0x1c 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci/* 9562306a36Sopenharmony_ci * LLI address mangling 9662306a36Sopenharmony_ci * 9762306a36Sopenharmony_ci * The LLI link physical address is also mangled, but we avoid dealing 9862306a36Sopenharmony_ci * with that by allocating LLIs from the DMA32 zone. 9962306a36Sopenharmony_ci */ 10062306a36Sopenharmony_ci#define SRC_HIGH_ADDR(x) (((x) & 0x3U) << 16) 10162306a36Sopenharmony_ci#define DST_HIGH_ADDR(x) (((x) & 0x3U) << 18) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* 10462306a36Sopenharmony_ci * Various hardware related defines 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_ci#define LLI_LAST_ITEM 0xfffff800 10762306a36Sopenharmony_ci#define NORMAL_WAIT 8 10862306a36Sopenharmony_ci#define DRQ_SDRAM 1 10962306a36Sopenharmony_ci#define LINEAR_MODE 0 11062306a36Sopenharmony_ci#define IO_MODE 1 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci/* forward declaration */ 11362306a36Sopenharmony_cistruct sun6i_dma_dev; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci/* 11662306a36Sopenharmony_ci * Hardware channels / ports representation 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * The hardware is used in several SoCs, with differing numbers 11962306a36Sopenharmony_ci * of channels and endpoints. This structure ties those numbers 12062306a36Sopenharmony_ci * to a certain compatible string. 12162306a36Sopenharmony_ci */ 12262306a36Sopenharmony_cistruct sun6i_dma_config { 12362306a36Sopenharmony_ci u32 nr_max_channels; 12462306a36Sopenharmony_ci u32 nr_max_requests; 12562306a36Sopenharmony_ci u32 nr_max_vchans; 12662306a36Sopenharmony_ci /* 12762306a36Sopenharmony_ci * In the datasheets/user manuals of newer Allwinner SoCs, a special 12862306a36Sopenharmony_ci * bit (bit 2 at register 0x20) is present. 12962306a36Sopenharmony_ci * It's named "DMA MCLK interface circuit auto gating bit" in the 13062306a36Sopenharmony_ci * documents, and the footnote of this register says that this bit 13162306a36Sopenharmony_ci * should be set up when initializing the DMA controller. 13262306a36Sopenharmony_ci * Allwinner A23/A33 user manuals do not have this bit documented, 13362306a36Sopenharmony_ci * however these SoCs really have and need this bit, as seen in the 13462306a36Sopenharmony_ci * BSP kernel source code. 13562306a36Sopenharmony_ci */ 13662306a36Sopenharmony_ci void (*clock_autogate_enable)(struct sun6i_dma_dev *); 13762306a36Sopenharmony_ci void (*set_burst_length)(u32 *p_cfg, s8 src_burst, s8 dst_burst); 13862306a36Sopenharmony_ci void (*set_drq)(u32 *p_cfg, s8 src_drq, s8 dst_drq); 13962306a36Sopenharmony_ci void (*set_mode)(u32 *p_cfg, s8 src_mode, s8 dst_mode); 14062306a36Sopenharmony_ci u32 src_burst_lengths; 14162306a36Sopenharmony_ci u32 dst_burst_lengths; 14262306a36Sopenharmony_ci u32 src_addr_widths; 14362306a36Sopenharmony_ci u32 dst_addr_widths; 14462306a36Sopenharmony_ci bool has_high_addr; 14562306a36Sopenharmony_ci bool has_mbus_clk; 14662306a36Sopenharmony_ci}; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci/* 14962306a36Sopenharmony_ci * Hardware representation of the LLI 15062306a36Sopenharmony_ci * 15162306a36Sopenharmony_ci * The hardware will be fed the physical address of this structure, 15262306a36Sopenharmony_ci * and read its content in order to start the transfer. 15362306a36Sopenharmony_ci */ 15462306a36Sopenharmony_cistruct sun6i_dma_lli { 15562306a36Sopenharmony_ci u32 cfg; 15662306a36Sopenharmony_ci u32 src; 15762306a36Sopenharmony_ci u32 dst; 15862306a36Sopenharmony_ci u32 len; 15962306a36Sopenharmony_ci u32 para; 16062306a36Sopenharmony_ci u32 p_lli_next; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* 16362306a36Sopenharmony_ci * This field is not used by the DMA controller, but will be 16462306a36Sopenharmony_ci * used by the CPU to go through the list (mostly for dumping 16562306a36Sopenharmony_ci * or freeing it). 16662306a36Sopenharmony_ci */ 16762306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli_next; 16862306a36Sopenharmony_ci}; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistruct sun6i_desc { 17262306a36Sopenharmony_ci struct virt_dma_desc vd; 17362306a36Sopenharmony_ci dma_addr_t p_lli; 17462306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli; 17562306a36Sopenharmony_ci}; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_cistruct sun6i_pchan { 17862306a36Sopenharmony_ci u32 idx; 17962306a36Sopenharmony_ci void __iomem *base; 18062306a36Sopenharmony_ci struct sun6i_vchan *vchan; 18162306a36Sopenharmony_ci struct sun6i_desc *desc; 18262306a36Sopenharmony_ci struct sun6i_desc *done; 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cistruct sun6i_vchan { 18662306a36Sopenharmony_ci struct virt_dma_chan vc; 18762306a36Sopenharmony_ci struct list_head node; 18862306a36Sopenharmony_ci struct dma_slave_config cfg; 18962306a36Sopenharmony_ci struct sun6i_pchan *phy; 19062306a36Sopenharmony_ci u8 port; 19162306a36Sopenharmony_ci u8 irq_type; 19262306a36Sopenharmony_ci bool cyclic; 19362306a36Sopenharmony_ci}; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistruct sun6i_dma_dev { 19662306a36Sopenharmony_ci struct dma_device slave; 19762306a36Sopenharmony_ci void __iomem *base; 19862306a36Sopenharmony_ci struct clk *clk; 19962306a36Sopenharmony_ci struct clk *clk_mbus; 20062306a36Sopenharmony_ci int irq; 20162306a36Sopenharmony_ci spinlock_t lock; 20262306a36Sopenharmony_ci struct reset_control *rstc; 20362306a36Sopenharmony_ci struct tasklet_struct task; 20462306a36Sopenharmony_ci atomic_t tasklet_shutdown; 20562306a36Sopenharmony_ci struct list_head pending; 20662306a36Sopenharmony_ci struct dma_pool *pool; 20762306a36Sopenharmony_ci struct sun6i_pchan *pchans; 20862306a36Sopenharmony_ci struct sun6i_vchan *vchans; 20962306a36Sopenharmony_ci const struct sun6i_dma_config *cfg; 21062306a36Sopenharmony_ci u32 num_pchans; 21162306a36Sopenharmony_ci u32 num_vchans; 21262306a36Sopenharmony_ci u32 max_request; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic struct device *chan2dev(struct dma_chan *chan) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci return &chan->dev->device; 21862306a36Sopenharmony_ci} 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_cistatic inline struct sun6i_dma_dev *to_sun6i_dma_dev(struct dma_device *d) 22162306a36Sopenharmony_ci{ 22262306a36Sopenharmony_ci return container_of(d, struct sun6i_dma_dev, slave); 22362306a36Sopenharmony_ci} 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_cistatic inline struct sun6i_vchan *to_sun6i_vchan(struct dma_chan *chan) 22662306a36Sopenharmony_ci{ 22762306a36Sopenharmony_ci return container_of(chan, struct sun6i_vchan, vc.chan); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic inline struct sun6i_desc * 23162306a36Sopenharmony_cito_sun6i_desc(struct dma_async_tx_descriptor *tx) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return container_of(tx, struct sun6i_desc, vd.tx); 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic inline void sun6i_dma_dump_com_regs(struct sun6i_dma_dev *sdev) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci dev_dbg(sdev->slave.dev, "Common register:\n" 23962306a36Sopenharmony_ci "\tmask0(%04x): 0x%08x\n" 24062306a36Sopenharmony_ci "\tmask1(%04x): 0x%08x\n" 24162306a36Sopenharmony_ci "\tpend0(%04x): 0x%08x\n" 24262306a36Sopenharmony_ci "\tpend1(%04x): 0x%08x\n" 24362306a36Sopenharmony_ci "\tstats(%04x): 0x%08x\n", 24462306a36Sopenharmony_ci DMA_IRQ_EN(0), readl(sdev->base + DMA_IRQ_EN(0)), 24562306a36Sopenharmony_ci DMA_IRQ_EN(1), readl(sdev->base + DMA_IRQ_EN(1)), 24662306a36Sopenharmony_ci DMA_IRQ_STAT(0), readl(sdev->base + DMA_IRQ_STAT(0)), 24762306a36Sopenharmony_ci DMA_IRQ_STAT(1), readl(sdev->base + DMA_IRQ_STAT(1)), 24862306a36Sopenharmony_ci DMA_STAT, readl(sdev->base + DMA_STAT)); 24962306a36Sopenharmony_ci} 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_cistatic inline void sun6i_dma_dump_chan_regs(struct sun6i_dma_dev *sdev, 25262306a36Sopenharmony_ci struct sun6i_pchan *pchan) 25362306a36Sopenharmony_ci{ 25462306a36Sopenharmony_ci dev_dbg(sdev->slave.dev, "Chan %d reg:\n" 25562306a36Sopenharmony_ci "\t___en(%04x): \t0x%08x\n" 25662306a36Sopenharmony_ci "\tpause(%04x): \t0x%08x\n" 25762306a36Sopenharmony_ci "\tstart(%04x): \t0x%08x\n" 25862306a36Sopenharmony_ci "\t__cfg(%04x): \t0x%08x\n" 25962306a36Sopenharmony_ci "\t__src(%04x): \t0x%08x\n" 26062306a36Sopenharmony_ci "\t__dst(%04x): \t0x%08x\n" 26162306a36Sopenharmony_ci "\tcount(%04x): \t0x%08x\n" 26262306a36Sopenharmony_ci "\t_para(%04x): \t0x%08x\n\n", 26362306a36Sopenharmony_ci pchan->idx, 26462306a36Sopenharmony_ci DMA_CHAN_ENABLE, 26562306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_ENABLE), 26662306a36Sopenharmony_ci DMA_CHAN_PAUSE, 26762306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_PAUSE), 26862306a36Sopenharmony_ci DMA_CHAN_LLI_ADDR, 26962306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_LLI_ADDR), 27062306a36Sopenharmony_ci DMA_CHAN_CUR_CFG, 27162306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_CUR_CFG), 27262306a36Sopenharmony_ci DMA_CHAN_CUR_SRC, 27362306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_CUR_SRC), 27462306a36Sopenharmony_ci DMA_CHAN_CUR_DST, 27562306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_CUR_DST), 27662306a36Sopenharmony_ci DMA_CHAN_CUR_CNT, 27762306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_CUR_CNT), 27862306a36Sopenharmony_ci DMA_CHAN_CUR_PARA, 27962306a36Sopenharmony_ci readl(pchan->base + DMA_CHAN_CUR_PARA)); 28062306a36Sopenharmony_ci} 28162306a36Sopenharmony_ci 28262306a36Sopenharmony_cistatic inline s8 convert_burst(u32 maxburst) 28362306a36Sopenharmony_ci{ 28462306a36Sopenharmony_ci switch (maxburst) { 28562306a36Sopenharmony_ci case 1: 28662306a36Sopenharmony_ci return 0; 28762306a36Sopenharmony_ci case 4: 28862306a36Sopenharmony_ci return 1; 28962306a36Sopenharmony_ci case 8: 29062306a36Sopenharmony_ci return 2; 29162306a36Sopenharmony_ci case 16: 29262306a36Sopenharmony_ci return 3; 29362306a36Sopenharmony_ci default: 29462306a36Sopenharmony_ci return -EINVAL; 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci} 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_cistatic inline s8 convert_buswidth(enum dma_slave_buswidth addr_width) 29962306a36Sopenharmony_ci{ 30062306a36Sopenharmony_ci return ilog2(addr_width); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void sun6i_enable_clock_autogate_a23(struct sun6i_dma_dev *sdev) 30462306a36Sopenharmony_ci{ 30562306a36Sopenharmony_ci writel(SUN8I_DMA_GATE_ENABLE, sdev->base + SUN8I_DMA_GATE); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void sun6i_enable_clock_autogate_h3(struct sun6i_dma_dev *sdev) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci writel(SUNXI_H3_DMA_GATE_ENABLE, sdev->base + SUNXI_H3_DMA_GATE); 31162306a36Sopenharmony_ci} 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_cistatic void sun6i_set_burst_length_a31(u32 *p_cfg, s8 src_burst, s8 dst_burst) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_BURST_A31(src_burst) | 31662306a36Sopenharmony_ci DMA_CHAN_CFG_DST_BURST_A31(dst_burst); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void sun6i_set_burst_length_h3(u32 *p_cfg, s8 src_burst, s8 dst_burst) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_BURST_H3(src_burst) | 32262306a36Sopenharmony_ci DMA_CHAN_CFG_DST_BURST_H3(dst_burst); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void sun6i_set_drq_a31(u32 *p_cfg, s8 src_drq, s8 dst_drq) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_A31(src_drq) | 32862306a36Sopenharmony_ci DMA_CHAN_CFG_DST_DRQ_A31(dst_drq); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic void sun6i_set_drq_h6(u32 *p_cfg, s8 src_drq, s8 dst_drq) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_DRQ_H6(src_drq) | 33462306a36Sopenharmony_ci DMA_CHAN_CFG_DST_DRQ_H6(dst_drq); 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic void sun6i_set_mode_a31(u32 *p_cfg, s8 src_mode, s8 dst_mode) 33862306a36Sopenharmony_ci{ 33962306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_MODE_A31(src_mode) | 34062306a36Sopenharmony_ci DMA_CHAN_CFG_DST_MODE_A31(dst_mode); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic void sun6i_set_mode_h6(u32 *p_cfg, s8 src_mode, s8 dst_mode) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci *p_cfg |= DMA_CHAN_CFG_SRC_MODE_H6(src_mode) | 34662306a36Sopenharmony_ci DMA_CHAN_CFG_DST_MODE_H6(dst_mode); 34762306a36Sopenharmony_ci} 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_cistatic size_t sun6i_get_chan_size(struct sun6i_pchan *pchan) 35062306a36Sopenharmony_ci{ 35162306a36Sopenharmony_ci struct sun6i_desc *txd = pchan->desc; 35262306a36Sopenharmony_ci struct sun6i_dma_lli *lli; 35362306a36Sopenharmony_ci size_t bytes; 35462306a36Sopenharmony_ci dma_addr_t pos; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci pos = readl(pchan->base + DMA_CHAN_LLI_ADDR); 35762306a36Sopenharmony_ci bytes = readl(pchan->base + DMA_CHAN_CUR_CNT); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (pos == LLI_LAST_ITEM) 36062306a36Sopenharmony_ci return bytes; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci for (lli = txd->v_lli; lli; lli = lli->v_lli_next) { 36362306a36Sopenharmony_ci if (lli->p_lli_next == pos) { 36462306a36Sopenharmony_ci for (lli = lli->v_lli_next; lli; lli = lli->v_lli_next) 36562306a36Sopenharmony_ci bytes += lli->len; 36662306a36Sopenharmony_ci break; 36762306a36Sopenharmony_ci } 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return bytes; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cistatic void *sun6i_dma_lli_add(struct sun6i_dma_lli *prev, 37462306a36Sopenharmony_ci struct sun6i_dma_lli *next, 37562306a36Sopenharmony_ci dma_addr_t next_phy, 37662306a36Sopenharmony_ci struct sun6i_desc *txd) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci if ((!prev && !txd) || !next) 37962306a36Sopenharmony_ci return NULL; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (!prev) { 38262306a36Sopenharmony_ci txd->p_lli = next_phy; 38362306a36Sopenharmony_ci txd->v_lli = next; 38462306a36Sopenharmony_ci } else { 38562306a36Sopenharmony_ci prev->p_lli_next = next_phy; 38662306a36Sopenharmony_ci prev->v_lli_next = next; 38762306a36Sopenharmony_ci } 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci next->p_lli_next = LLI_LAST_ITEM; 39062306a36Sopenharmony_ci next->v_lli_next = NULL; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci return next; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic inline void sun6i_dma_dump_lli(struct sun6i_vchan *vchan, 39662306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli, 39762306a36Sopenharmony_ci dma_addr_t p_lli) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci dev_dbg(chan2dev(&vchan->vc.chan), 40062306a36Sopenharmony_ci "\n\tdesc:\tp - %pad v - 0x%p\n" 40162306a36Sopenharmony_ci "\t\tc - 0x%08x s - 0x%08x d - 0x%08x\n" 40262306a36Sopenharmony_ci "\t\tl - 0x%08x p - 0x%08x n - 0x%08x\n", 40362306a36Sopenharmony_ci &p_lli, v_lli, 40462306a36Sopenharmony_ci v_lli->cfg, v_lli->src, v_lli->dst, 40562306a36Sopenharmony_ci v_lli->len, v_lli->para, v_lli->p_lli_next); 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void sun6i_dma_free_desc(struct virt_dma_desc *vd) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct sun6i_desc *txd = to_sun6i_desc(&vd->tx); 41162306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vd->tx.chan->device); 41262306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli, *v_next; 41362306a36Sopenharmony_ci dma_addr_t p_lli, p_next; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (unlikely(!txd)) 41662306a36Sopenharmony_ci return; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci p_lli = txd->p_lli; 41962306a36Sopenharmony_ci v_lli = txd->v_lli; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci while (v_lli) { 42262306a36Sopenharmony_ci v_next = v_lli->v_lli_next; 42362306a36Sopenharmony_ci p_next = v_lli->p_lli_next; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci dma_pool_free(sdev->pool, v_lli, p_lli); 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci v_lli = v_next; 42862306a36Sopenharmony_ci p_lli = p_next; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci kfree(txd); 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_cistatic int sun6i_dma_start_desc(struct sun6i_vchan *vchan) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device); 43762306a36Sopenharmony_ci struct virt_dma_desc *desc = vchan_next_desc(&vchan->vc); 43862306a36Sopenharmony_ci struct sun6i_pchan *pchan = vchan->phy; 43962306a36Sopenharmony_ci u32 irq_val, irq_reg, irq_offset; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (!pchan) 44262306a36Sopenharmony_ci return -EAGAIN; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci if (!desc) { 44562306a36Sopenharmony_ci pchan->desc = NULL; 44662306a36Sopenharmony_ci pchan->done = NULL; 44762306a36Sopenharmony_ci return -EAGAIN; 44862306a36Sopenharmony_ci } 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci list_del(&desc->node); 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci pchan->desc = to_sun6i_desc(&desc->tx); 45362306a36Sopenharmony_ci pchan->done = NULL; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci sun6i_dma_dump_lli(vchan, pchan->desc->v_lli, pchan->desc->p_lli); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci irq_reg = pchan->idx / DMA_IRQ_CHAN_NR; 45862306a36Sopenharmony_ci irq_offset = pchan->idx % DMA_IRQ_CHAN_NR; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci vchan->irq_type = vchan->cyclic ? DMA_IRQ_PKG : DMA_IRQ_QUEUE; 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci irq_val = readl(sdev->base + DMA_IRQ_EN(irq_reg)); 46362306a36Sopenharmony_ci irq_val &= ~((DMA_IRQ_HALF | DMA_IRQ_PKG | DMA_IRQ_QUEUE) << 46462306a36Sopenharmony_ci (irq_offset * DMA_IRQ_CHAN_WIDTH)); 46562306a36Sopenharmony_ci irq_val |= vchan->irq_type << (irq_offset * DMA_IRQ_CHAN_WIDTH); 46662306a36Sopenharmony_ci writel(irq_val, sdev->base + DMA_IRQ_EN(irq_reg)); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci writel(pchan->desc->p_lli, pchan->base + DMA_CHAN_LLI_ADDR); 46962306a36Sopenharmony_ci writel(DMA_CHAN_ENABLE_START, pchan->base + DMA_CHAN_ENABLE); 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_ci sun6i_dma_dump_com_regs(sdev); 47262306a36Sopenharmony_ci sun6i_dma_dump_chan_regs(sdev, pchan); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return 0; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic void sun6i_dma_tasklet(struct tasklet_struct *t) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = from_tasklet(sdev, t, task); 48062306a36Sopenharmony_ci struct sun6i_vchan *vchan; 48162306a36Sopenharmony_ci struct sun6i_pchan *pchan; 48262306a36Sopenharmony_ci unsigned int pchan_alloc = 0; 48362306a36Sopenharmony_ci unsigned int pchan_idx; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci list_for_each_entry(vchan, &sdev->slave.channels, vc.chan.device_node) { 48662306a36Sopenharmony_ci spin_lock_irq(&vchan->vc.lock); 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_ci pchan = vchan->phy; 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci if (pchan && pchan->done) { 49162306a36Sopenharmony_ci if (sun6i_dma_start_desc(vchan)) { 49262306a36Sopenharmony_ci /* 49362306a36Sopenharmony_ci * No current txd associated with this channel 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_ci dev_dbg(sdev->slave.dev, "pchan %u: free\n", 49662306a36Sopenharmony_ci pchan->idx); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci /* Mark this channel free */ 49962306a36Sopenharmony_ci vchan->phy = NULL; 50062306a36Sopenharmony_ci pchan->vchan = NULL; 50162306a36Sopenharmony_ci } 50262306a36Sopenharmony_ci } 50362306a36Sopenharmony_ci spin_unlock_irq(&vchan->vc.lock); 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci spin_lock_irq(&sdev->lock); 50762306a36Sopenharmony_ci for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) { 50862306a36Sopenharmony_ci pchan = &sdev->pchans[pchan_idx]; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (pchan->vchan || list_empty(&sdev->pending)) 51162306a36Sopenharmony_ci continue; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci vchan = list_first_entry(&sdev->pending, 51462306a36Sopenharmony_ci struct sun6i_vchan, node); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci /* Remove from pending channels */ 51762306a36Sopenharmony_ci list_del_init(&vchan->node); 51862306a36Sopenharmony_ci pchan_alloc |= BIT(pchan_idx); 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci /* Mark this channel allocated */ 52162306a36Sopenharmony_ci pchan->vchan = vchan; 52262306a36Sopenharmony_ci vchan->phy = pchan; 52362306a36Sopenharmony_ci dev_dbg(sdev->slave.dev, "pchan %u: alloc vchan %p\n", 52462306a36Sopenharmony_ci pchan->idx, &vchan->vc); 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci spin_unlock_irq(&sdev->lock); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci for (pchan_idx = 0; pchan_idx < sdev->num_pchans; pchan_idx++) { 52962306a36Sopenharmony_ci if (!(pchan_alloc & BIT(pchan_idx))) 53062306a36Sopenharmony_ci continue; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci pchan = sdev->pchans + pchan_idx; 53362306a36Sopenharmony_ci vchan = pchan->vchan; 53462306a36Sopenharmony_ci if (vchan) { 53562306a36Sopenharmony_ci spin_lock_irq(&vchan->vc.lock); 53662306a36Sopenharmony_ci sun6i_dma_start_desc(vchan); 53762306a36Sopenharmony_ci spin_unlock_irq(&vchan->vc.lock); 53862306a36Sopenharmony_ci } 53962306a36Sopenharmony_ci } 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_cistatic irqreturn_t sun6i_dma_interrupt(int irq, void *dev_id) 54362306a36Sopenharmony_ci{ 54462306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = dev_id; 54562306a36Sopenharmony_ci struct sun6i_vchan *vchan; 54662306a36Sopenharmony_ci struct sun6i_pchan *pchan; 54762306a36Sopenharmony_ci int i, j, ret = IRQ_NONE; 54862306a36Sopenharmony_ci u32 status; 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci for (i = 0; i < sdev->num_pchans / DMA_IRQ_CHAN_NR; i++) { 55162306a36Sopenharmony_ci status = readl(sdev->base + DMA_IRQ_STAT(i)); 55262306a36Sopenharmony_ci if (!status) 55362306a36Sopenharmony_ci continue; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci dev_dbg(sdev->slave.dev, "DMA irq status %s: 0x%x\n", 55662306a36Sopenharmony_ci i ? "high" : "low", status); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci writel(status, sdev->base + DMA_IRQ_STAT(i)); 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci for (j = 0; (j < DMA_IRQ_CHAN_NR) && status; j++) { 56162306a36Sopenharmony_ci pchan = sdev->pchans + j; 56262306a36Sopenharmony_ci vchan = pchan->vchan; 56362306a36Sopenharmony_ci if (vchan && (status & vchan->irq_type)) { 56462306a36Sopenharmony_ci if (vchan->cyclic) { 56562306a36Sopenharmony_ci vchan_cyclic_callback(&pchan->desc->vd); 56662306a36Sopenharmony_ci } else { 56762306a36Sopenharmony_ci spin_lock(&vchan->vc.lock); 56862306a36Sopenharmony_ci vchan_cookie_complete(&pchan->desc->vd); 56962306a36Sopenharmony_ci pchan->done = pchan->desc; 57062306a36Sopenharmony_ci spin_unlock(&vchan->vc.lock); 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci } 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_ci status = status >> DMA_IRQ_CHAN_WIDTH; 57562306a36Sopenharmony_ci } 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (!atomic_read(&sdev->tasklet_shutdown)) 57862306a36Sopenharmony_ci tasklet_schedule(&sdev->task); 57962306a36Sopenharmony_ci ret = IRQ_HANDLED; 58062306a36Sopenharmony_ci } 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_cistatic int set_config(struct sun6i_dma_dev *sdev, 58662306a36Sopenharmony_ci struct dma_slave_config *sconfig, 58762306a36Sopenharmony_ci enum dma_transfer_direction direction, 58862306a36Sopenharmony_ci u32 *p_cfg) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci enum dma_slave_buswidth src_addr_width, dst_addr_width; 59162306a36Sopenharmony_ci u32 src_maxburst, dst_maxburst; 59262306a36Sopenharmony_ci s8 src_width, dst_width, src_burst, dst_burst; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci src_addr_width = sconfig->src_addr_width; 59562306a36Sopenharmony_ci dst_addr_width = sconfig->dst_addr_width; 59662306a36Sopenharmony_ci src_maxburst = sconfig->src_maxburst; 59762306a36Sopenharmony_ci dst_maxburst = sconfig->dst_maxburst; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci switch (direction) { 60062306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 60162306a36Sopenharmony_ci if (src_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 60262306a36Sopenharmony_ci src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 60362306a36Sopenharmony_ci src_maxburst = src_maxburst ? src_maxburst : 8; 60462306a36Sopenharmony_ci break; 60562306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 60662306a36Sopenharmony_ci if (dst_addr_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) 60762306a36Sopenharmony_ci dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES; 60862306a36Sopenharmony_ci dst_maxburst = dst_maxburst ? dst_maxburst : 8; 60962306a36Sopenharmony_ci break; 61062306a36Sopenharmony_ci default: 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci } 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci if (!(BIT(src_addr_width) & sdev->slave.src_addr_widths)) 61562306a36Sopenharmony_ci return -EINVAL; 61662306a36Sopenharmony_ci if (!(BIT(dst_addr_width) & sdev->slave.dst_addr_widths)) 61762306a36Sopenharmony_ci return -EINVAL; 61862306a36Sopenharmony_ci if (!(BIT(src_maxburst) & sdev->cfg->src_burst_lengths)) 61962306a36Sopenharmony_ci return -EINVAL; 62062306a36Sopenharmony_ci if (!(BIT(dst_maxburst) & sdev->cfg->dst_burst_lengths)) 62162306a36Sopenharmony_ci return -EINVAL; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci src_width = convert_buswidth(src_addr_width); 62462306a36Sopenharmony_ci dst_width = convert_buswidth(dst_addr_width); 62562306a36Sopenharmony_ci dst_burst = convert_burst(dst_maxburst); 62662306a36Sopenharmony_ci src_burst = convert_burst(src_maxburst); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci *p_cfg = DMA_CHAN_CFG_SRC_WIDTH(src_width) | 62962306a36Sopenharmony_ci DMA_CHAN_CFG_DST_WIDTH(dst_width); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci sdev->cfg->set_burst_length(p_cfg, src_burst, dst_burst); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return 0; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic inline void sun6i_dma_set_addr(struct sun6i_dma_dev *sdev, 63762306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli, 63862306a36Sopenharmony_ci dma_addr_t src, dma_addr_t dst) 63962306a36Sopenharmony_ci{ 64062306a36Sopenharmony_ci v_lli->src = lower_32_bits(src); 64162306a36Sopenharmony_ci v_lli->dst = lower_32_bits(dst); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (sdev->cfg->has_high_addr) 64462306a36Sopenharmony_ci v_lli->para |= SRC_HIGH_ADDR(upper_32_bits(src)) | 64562306a36Sopenharmony_ci DST_HIGH_ADDR(upper_32_bits(dst)); 64662306a36Sopenharmony_ci} 64762306a36Sopenharmony_ci 64862306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *sun6i_dma_prep_dma_memcpy( 64962306a36Sopenharmony_ci struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, 65062306a36Sopenharmony_ci size_t len, unsigned long flags) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 65362306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 65462306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli; 65562306a36Sopenharmony_ci struct sun6i_desc *txd; 65662306a36Sopenharmony_ci dma_addr_t p_lli; 65762306a36Sopenharmony_ci s8 burst, width; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci dev_dbg(chan2dev(chan), 66062306a36Sopenharmony_ci "%s; chan: %d, dest: %pad, src: %pad, len: %zu. flags: 0x%08lx\n", 66162306a36Sopenharmony_ci __func__, vchan->vc.chan.chan_id, &dest, &src, len, flags); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci if (!len) 66462306a36Sopenharmony_ci return NULL; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci txd = kzalloc(sizeof(*txd), GFP_NOWAIT); 66762306a36Sopenharmony_ci if (!txd) 66862306a36Sopenharmony_ci return NULL; 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli); 67162306a36Sopenharmony_ci if (!v_lli) { 67262306a36Sopenharmony_ci dev_err(sdev->slave.dev, "Failed to alloc lli memory\n"); 67362306a36Sopenharmony_ci goto err_txd_free; 67462306a36Sopenharmony_ci } 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci v_lli->len = len; 67762306a36Sopenharmony_ci v_lli->para = NORMAL_WAIT; 67862306a36Sopenharmony_ci sun6i_dma_set_addr(sdev, v_lli, src, dest); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci burst = convert_burst(8); 68162306a36Sopenharmony_ci width = convert_buswidth(DMA_SLAVE_BUSWIDTH_4_BYTES); 68262306a36Sopenharmony_ci v_lli->cfg = DMA_CHAN_CFG_SRC_WIDTH(width) | 68362306a36Sopenharmony_ci DMA_CHAN_CFG_DST_WIDTH(width); 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci sdev->cfg->set_burst_length(&v_lli->cfg, burst, burst); 68662306a36Sopenharmony_ci sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, DRQ_SDRAM); 68762306a36Sopenharmony_ci sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, LINEAR_MODE); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci sun6i_dma_lli_add(NULL, v_lli, p_lli, txd); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci sun6i_dma_dump_lli(vchan, v_lli, p_lli); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci return vchan_tx_prep(&vchan->vc, &txd->vd, flags); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_cierr_txd_free: 69662306a36Sopenharmony_ci kfree(txd); 69762306a36Sopenharmony_ci return NULL; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *sun6i_dma_prep_slave_sg( 70162306a36Sopenharmony_ci struct dma_chan *chan, struct scatterlist *sgl, 70262306a36Sopenharmony_ci unsigned int sg_len, enum dma_transfer_direction dir, 70362306a36Sopenharmony_ci unsigned long flags, void *context) 70462306a36Sopenharmony_ci{ 70562306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 70662306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 70762306a36Sopenharmony_ci struct dma_slave_config *sconfig = &vchan->cfg; 70862306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli, *prev = NULL; 70962306a36Sopenharmony_ci struct sun6i_desc *txd; 71062306a36Sopenharmony_ci struct scatterlist *sg; 71162306a36Sopenharmony_ci dma_addr_t p_lli; 71262306a36Sopenharmony_ci u32 lli_cfg; 71362306a36Sopenharmony_ci int i, ret; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci if (!sgl) 71662306a36Sopenharmony_ci return NULL; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci ret = set_config(sdev, sconfig, dir, &lli_cfg); 71962306a36Sopenharmony_ci if (ret) { 72062306a36Sopenharmony_ci dev_err(chan2dev(chan), "Invalid DMA configuration\n"); 72162306a36Sopenharmony_ci return NULL; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci txd = kzalloc(sizeof(*txd), GFP_NOWAIT); 72562306a36Sopenharmony_ci if (!txd) 72662306a36Sopenharmony_ci return NULL; 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 72962306a36Sopenharmony_ci v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli); 73062306a36Sopenharmony_ci if (!v_lli) 73162306a36Sopenharmony_ci goto err_lli_free; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci v_lli->len = sg_dma_len(sg); 73462306a36Sopenharmony_ci v_lli->para = NORMAL_WAIT; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci if (dir == DMA_MEM_TO_DEV) { 73762306a36Sopenharmony_ci sun6i_dma_set_addr(sdev, v_lli, 73862306a36Sopenharmony_ci sg_dma_address(sg), 73962306a36Sopenharmony_ci sconfig->dst_addr); 74062306a36Sopenharmony_ci v_lli->cfg = lli_cfg; 74162306a36Sopenharmony_ci sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port); 74262306a36Sopenharmony_ci sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE); 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci dev_dbg(chan2dev(chan), 74562306a36Sopenharmony_ci "%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n", 74662306a36Sopenharmony_ci __func__, vchan->vc.chan.chan_id, 74762306a36Sopenharmony_ci &sconfig->dst_addr, &sg_dma_address(sg), 74862306a36Sopenharmony_ci sg_dma_len(sg), flags); 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci } else { 75162306a36Sopenharmony_ci sun6i_dma_set_addr(sdev, v_lli, 75262306a36Sopenharmony_ci sconfig->src_addr, 75362306a36Sopenharmony_ci sg_dma_address(sg)); 75462306a36Sopenharmony_ci v_lli->cfg = lli_cfg; 75562306a36Sopenharmony_ci sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM); 75662306a36Sopenharmony_ci sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci dev_dbg(chan2dev(chan), 75962306a36Sopenharmony_ci "%s; chan: %d, dest: %pad, src: %pad, len: %u. flags: 0x%08lx\n", 76062306a36Sopenharmony_ci __func__, vchan->vc.chan.chan_id, 76162306a36Sopenharmony_ci &sg_dma_address(sg), &sconfig->src_addr, 76262306a36Sopenharmony_ci sg_dma_len(sg), flags); 76362306a36Sopenharmony_ci } 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd); 76662306a36Sopenharmony_ci } 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "First: %pad\n", &txd->p_lli); 76962306a36Sopenharmony_ci for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli; 77062306a36Sopenharmony_ci p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next) 77162306a36Sopenharmony_ci sun6i_dma_dump_lli(vchan, v_lli, p_lli); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return vchan_tx_prep(&vchan->vc, &txd->vd, flags); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_cierr_lli_free: 77662306a36Sopenharmony_ci for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli; 77762306a36Sopenharmony_ci p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next) 77862306a36Sopenharmony_ci dma_pool_free(sdev->pool, v_lli, p_lli); 77962306a36Sopenharmony_ci kfree(txd); 78062306a36Sopenharmony_ci return NULL; 78162306a36Sopenharmony_ci} 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *sun6i_dma_prep_dma_cyclic( 78462306a36Sopenharmony_ci struct dma_chan *chan, 78562306a36Sopenharmony_ci dma_addr_t buf_addr, 78662306a36Sopenharmony_ci size_t buf_len, 78762306a36Sopenharmony_ci size_t period_len, 78862306a36Sopenharmony_ci enum dma_transfer_direction dir, 78962306a36Sopenharmony_ci unsigned long flags) 79062306a36Sopenharmony_ci{ 79162306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 79262306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 79362306a36Sopenharmony_ci struct dma_slave_config *sconfig = &vchan->cfg; 79462306a36Sopenharmony_ci struct sun6i_dma_lli *v_lli, *prev = NULL; 79562306a36Sopenharmony_ci struct sun6i_desc *txd; 79662306a36Sopenharmony_ci dma_addr_t p_lli; 79762306a36Sopenharmony_ci u32 lli_cfg; 79862306a36Sopenharmony_ci unsigned int i, periods = buf_len / period_len; 79962306a36Sopenharmony_ci int ret; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ret = set_config(sdev, sconfig, dir, &lli_cfg); 80262306a36Sopenharmony_ci if (ret) { 80362306a36Sopenharmony_ci dev_err(chan2dev(chan), "Invalid DMA configuration\n"); 80462306a36Sopenharmony_ci return NULL; 80562306a36Sopenharmony_ci } 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci txd = kzalloc(sizeof(*txd), GFP_NOWAIT); 80862306a36Sopenharmony_ci if (!txd) 80962306a36Sopenharmony_ci return NULL; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < periods; i++) { 81262306a36Sopenharmony_ci v_lli = dma_pool_alloc(sdev->pool, GFP_DMA32 | GFP_NOWAIT, &p_lli); 81362306a36Sopenharmony_ci if (!v_lli) { 81462306a36Sopenharmony_ci dev_err(sdev->slave.dev, "Failed to alloc lli memory\n"); 81562306a36Sopenharmony_ci goto err_lli_free; 81662306a36Sopenharmony_ci } 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci v_lli->len = period_len; 81962306a36Sopenharmony_ci v_lli->para = NORMAL_WAIT; 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci if (dir == DMA_MEM_TO_DEV) { 82262306a36Sopenharmony_ci sun6i_dma_set_addr(sdev, v_lli, 82362306a36Sopenharmony_ci buf_addr + period_len * i, 82462306a36Sopenharmony_ci sconfig->dst_addr); 82562306a36Sopenharmony_ci v_lli->cfg = lli_cfg; 82662306a36Sopenharmony_ci sdev->cfg->set_drq(&v_lli->cfg, DRQ_SDRAM, vchan->port); 82762306a36Sopenharmony_ci sdev->cfg->set_mode(&v_lli->cfg, LINEAR_MODE, IO_MODE); 82862306a36Sopenharmony_ci } else { 82962306a36Sopenharmony_ci sun6i_dma_set_addr(sdev, v_lli, 83062306a36Sopenharmony_ci sconfig->src_addr, 83162306a36Sopenharmony_ci buf_addr + period_len * i); 83262306a36Sopenharmony_ci v_lli->cfg = lli_cfg; 83362306a36Sopenharmony_ci sdev->cfg->set_drq(&v_lli->cfg, vchan->port, DRQ_SDRAM); 83462306a36Sopenharmony_ci sdev->cfg->set_mode(&v_lli->cfg, IO_MODE, LINEAR_MODE); 83562306a36Sopenharmony_ci } 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_ci prev = sun6i_dma_lli_add(prev, v_lli, p_lli, txd); 83862306a36Sopenharmony_ci } 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci prev->p_lli_next = txd->p_lli; /* cyclic list */ 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci vchan->cyclic = true; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci return vchan_tx_prep(&vchan->vc, &txd->vd, flags); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cierr_lli_free: 84762306a36Sopenharmony_ci for (p_lli = txd->p_lli, v_lli = txd->v_lli; v_lli; 84862306a36Sopenharmony_ci p_lli = v_lli->p_lli_next, v_lli = v_lli->v_lli_next) 84962306a36Sopenharmony_ci dma_pool_free(sdev->pool, v_lli, p_lli); 85062306a36Sopenharmony_ci kfree(txd); 85162306a36Sopenharmony_ci return NULL; 85262306a36Sopenharmony_ci} 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_cistatic int sun6i_dma_config(struct dma_chan *chan, 85562306a36Sopenharmony_ci struct dma_slave_config *config) 85662306a36Sopenharmony_ci{ 85762306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_ci memcpy(&vchan->cfg, config, sizeof(*config)); 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci return 0; 86262306a36Sopenharmony_ci} 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_cistatic int sun6i_dma_pause(struct dma_chan *chan) 86562306a36Sopenharmony_ci{ 86662306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 86762306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 86862306a36Sopenharmony_ci struct sun6i_pchan *pchan = vchan->phy; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc); 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci if (pchan) { 87362306a36Sopenharmony_ci writel(DMA_CHAN_PAUSE_PAUSE, 87462306a36Sopenharmony_ci pchan->base + DMA_CHAN_PAUSE); 87562306a36Sopenharmony_ci } else { 87662306a36Sopenharmony_ci spin_lock(&sdev->lock); 87762306a36Sopenharmony_ci list_del_init(&vchan->node); 87862306a36Sopenharmony_ci spin_unlock(&sdev->lock); 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci return 0; 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic int sun6i_dma_resume(struct dma_chan *chan) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 88762306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 88862306a36Sopenharmony_ci struct sun6i_pchan *pchan = vchan->phy; 88962306a36Sopenharmony_ci unsigned long flags; 89062306a36Sopenharmony_ci 89162306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci spin_lock_irqsave(&vchan->vc.lock, flags); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (pchan) { 89662306a36Sopenharmony_ci writel(DMA_CHAN_PAUSE_RESUME, 89762306a36Sopenharmony_ci pchan->base + DMA_CHAN_PAUSE); 89862306a36Sopenharmony_ci } else if (!list_empty(&vchan->vc.desc_issued)) { 89962306a36Sopenharmony_ci spin_lock(&sdev->lock); 90062306a36Sopenharmony_ci list_add_tail(&vchan->node, &sdev->pending); 90162306a36Sopenharmony_ci spin_unlock(&sdev->lock); 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci spin_unlock_irqrestore(&vchan->vc.lock, flags); 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci return 0; 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic int sun6i_dma_terminate_all(struct dma_chan *chan) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 91262306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 91362306a36Sopenharmony_ci struct sun6i_pchan *pchan = vchan->phy; 91462306a36Sopenharmony_ci unsigned long flags; 91562306a36Sopenharmony_ci LIST_HEAD(head); 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_ci spin_lock(&sdev->lock); 91862306a36Sopenharmony_ci list_del_init(&vchan->node); 91962306a36Sopenharmony_ci spin_unlock(&sdev->lock); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci spin_lock_irqsave(&vchan->vc.lock, flags); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (vchan->cyclic) { 92462306a36Sopenharmony_ci vchan->cyclic = false; 92562306a36Sopenharmony_ci if (pchan && pchan->desc) { 92662306a36Sopenharmony_ci struct virt_dma_desc *vd = &pchan->desc->vd; 92762306a36Sopenharmony_ci struct virt_dma_chan *vc = &vchan->vc; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci list_add_tail(&vd->node, &vc->desc_completed); 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci vchan_get_all_descriptors(&vchan->vc, &head); 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (pchan) { 93662306a36Sopenharmony_ci writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE); 93762306a36Sopenharmony_ci writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci vchan->phy = NULL; 94062306a36Sopenharmony_ci pchan->vchan = NULL; 94162306a36Sopenharmony_ci pchan->desc = NULL; 94262306a36Sopenharmony_ci pchan->done = NULL; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci spin_unlock_irqrestore(&vchan->vc.lock, flags); 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci vchan_dma_desc_free_list(&vchan->vc, &head); 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci return 0; 95062306a36Sopenharmony_ci} 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_cistatic enum dma_status sun6i_dma_tx_status(struct dma_chan *chan, 95362306a36Sopenharmony_ci dma_cookie_t cookie, 95462306a36Sopenharmony_ci struct dma_tx_state *state) 95562306a36Sopenharmony_ci{ 95662306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 95762306a36Sopenharmony_ci struct sun6i_pchan *pchan = vchan->phy; 95862306a36Sopenharmony_ci struct sun6i_dma_lli *lli; 95962306a36Sopenharmony_ci struct virt_dma_desc *vd; 96062306a36Sopenharmony_ci struct sun6i_desc *txd; 96162306a36Sopenharmony_ci enum dma_status ret; 96262306a36Sopenharmony_ci unsigned long flags; 96362306a36Sopenharmony_ci size_t bytes = 0; 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, state); 96662306a36Sopenharmony_ci if (ret == DMA_COMPLETE || !state) 96762306a36Sopenharmony_ci return ret; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci spin_lock_irqsave(&vchan->vc.lock, flags); 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci vd = vchan_find_desc(&vchan->vc, cookie); 97262306a36Sopenharmony_ci txd = to_sun6i_desc(&vd->tx); 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci if (vd) { 97562306a36Sopenharmony_ci for (lli = txd->v_lli; lli != NULL; lli = lli->v_lli_next) 97662306a36Sopenharmony_ci bytes += lli->len; 97762306a36Sopenharmony_ci } else if (!pchan || !pchan->desc) { 97862306a36Sopenharmony_ci bytes = 0; 97962306a36Sopenharmony_ci } else { 98062306a36Sopenharmony_ci bytes = sun6i_get_chan_size(pchan); 98162306a36Sopenharmony_ci } 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_ci spin_unlock_irqrestore(&vchan->vc.lock, flags); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci dma_set_residue(state, bytes); 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci return ret; 98862306a36Sopenharmony_ci} 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_cistatic void sun6i_dma_issue_pending(struct dma_chan *chan) 99162306a36Sopenharmony_ci{ 99262306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 99362306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 99462306a36Sopenharmony_ci unsigned long flags; 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci spin_lock_irqsave(&vchan->vc.lock, flags); 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci if (vchan_issue_pending(&vchan->vc)) { 99962306a36Sopenharmony_ci spin_lock(&sdev->lock); 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci if (!vchan->phy && list_empty(&vchan->node)) { 100262306a36Sopenharmony_ci list_add_tail(&vchan->node, &sdev->pending); 100362306a36Sopenharmony_ci tasklet_schedule(&sdev->task); 100462306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "vchan %p: issued\n", 100562306a36Sopenharmony_ci &vchan->vc); 100662306a36Sopenharmony_ci } 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci spin_unlock(&sdev->lock); 100962306a36Sopenharmony_ci } else { 101062306a36Sopenharmony_ci dev_dbg(chan2dev(chan), "vchan %p: nothing to issue\n", 101162306a36Sopenharmony_ci &vchan->vc); 101262306a36Sopenharmony_ci } 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci spin_unlock_irqrestore(&vchan->vc.lock, flags); 101562306a36Sopenharmony_ci} 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_cistatic void sun6i_dma_free_chan_resources(struct dma_chan *chan) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); 102062306a36Sopenharmony_ci struct sun6i_vchan *vchan = to_sun6i_vchan(chan); 102162306a36Sopenharmony_ci unsigned long flags; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci spin_lock_irqsave(&sdev->lock, flags); 102462306a36Sopenharmony_ci list_del_init(&vchan->node); 102562306a36Sopenharmony_ci spin_unlock_irqrestore(&sdev->lock, flags); 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_ci vchan_free_chan_resources(&vchan->vc); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_cistatic struct dma_chan *sun6i_dma_of_xlate(struct of_phandle_args *dma_spec, 103162306a36Sopenharmony_ci struct of_dma *ofdma) 103262306a36Sopenharmony_ci{ 103362306a36Sopenharmony_ci struct sun6i_dma_dev *sdev = ofdma->of_dma_data; 103462306a36Sopenharmony_ci struct sun6i_vchan *vchan; 103562306a36Sopenharmony_ci struct dma_chan *chan; 103662306a36Sopenharmony_ci u8 port = dma_spec->args[0]; 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci if (port > sdev->max_request) 103962306a36Sopenharmony_ci return NULL; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci chan = dma_get_any_slave_channel(&sdev->slave); 104262306a36Sopenharmony_ci if (!chan) 104362306a36Sopenharmony_ci return NULL; 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci vchan = to_sun6i_vchan(chan); 104662306a36Sopenharmony_ci vchan->port = port; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci return chan; 104962306a36Sopenharmony_ci} 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_cistatic inline void sun6i_kill_tasklet(struct sun6i_dma_dev *sdev) 105262306a36Sopenharmony_ci{ 105362306a36Sopenharmony_ci /* Disable all interrupts from DMA */ 105462306a36Sopenharmony_ci writel(0, sdev->base + DMA_IRQ_EN(0)); 105562306a36Sopenharmony_ci writel(0, sdev->base + DMA_IRQ_EN(1)); 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci /* Prevent spurious interrupts from scheduling the tasklet */ 105862306a36Sopenharmony_ci atomic_inc(&sdev->tasklet_shutdown); 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci /* Make sure we won't have any further interrupts */ 106162306a36Sopenharmony_ci devm_free_irq(sdev->slave.dev, sdev->irq, sdev); 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* Actually prevent the tasklet from being scheduled */ 106462306a36Sopenharmony_ci tasklet_kill(&sdev->task); 106562306a36Sopenharmony_ci} 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic inline void sun6i_dma_free(struct sun6i_dma_dev *sdev) 106862306a36Sopenharmony_ci{ 106962306a36Sopenharmony_ci int i; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci for (i = 0; i < sdev->num_vchans; i++) { 107262306a36Sopenharmony_ci struct sun6i_vchan *vchan = &sdev->vchans[i]; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci list_del(&vchan->vc.chan.device_node); 107562306a36Sopenharmony_ci tasklet_kill(&vchan->vc.task); 107662306a36Sopenharmony_ci } 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_ci/* 108062306a36Sopenharmony_ci * For A31: 108162306a36Sopenharmony_ci * 108262306a36Sopenharmony_ci * There's 16 physical channels that can work in parallel. 108362306a36Sopenharmony_ci * 108462306a36Sopenharmony_ci * However we have 30 different endpoints for our requests. 108562306a36Sopenharmony_ci * 108662306a36Sopenharmony_ci * Since the channels are able to handle only an unidirectional 108762306a36Sopenharmony_ci * transfer, we need to allocate more virtual channels so that 108862306a36Sopenharmony_ci * everyone can grab one channel. 108962306a36Sopenharmony_ci * 109062306a36Sopenharmony_ci * Some devices can't work in both direction (mostly because it 109162306a36Sopenharmony_ci * wouldn't make sense), so we have a bit fewer virtual channels than 109262306a36Sopenharmony_ci * 2 channels per endpoints. 109362306a36Sopenharmony_ci */ 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_cistatic struct sun6i_dma_config sun6i_a31_dma_cfg = { 109662306a36Sopenharmony_ci .nr_max_channels = 16, 109762306a36Sopenharmony_ci .nr_max_requests = 30, 109862306a36Sopenharmony_ci .nr_max_vchans = 53, 109962306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_a31, 110062306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 110162306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 110262306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(8), 110362306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(8), 110462306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 110562306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 110662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 110762306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 110862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 110962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 111062306a36Sopenharmony_ci}; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci/* 111362306a36Sopenharmony_ci * The A23 only has 8 physical channels, a maximum DRQ port id of 24, 111462306a36Sopenharmony_ci * and a total of 37 usable source and destination endpoints. 111562306a36Sopenharmony_ci */ 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic struct sun6i_dma_config sun8i_a23_dma_cfg = { 111862306a36Sopenharmony_ci .nr_max_channels = 8, 111962306a36Sopenharmony_ci .nr_max_requests = 24, 112062306a36Sopenharmony_ci .nr_max_vchans = 37, 112162306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_a23, 112262306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_a31, 112362306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 112462306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 112562306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(8), 112662306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(8), 112762306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 112862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 112962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 113062306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 113162306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 113262306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 113362306a36Sopenharmony_ci}; 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_cistatic struct sun6i_dma_config sun8i_a83t_dma_cfg = { 113662306a36Sopenharmony_ci .nr_max_channels = 8, 113762306a36Sopenharmony_ci .nr_max_requests = 28, 113862306a36Sopenharmony_ci .nr_max_vchans = 39, 113962306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_a23, 114062306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_a31, 114162306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 114262306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 114362306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(8), 114462306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(8), 114562306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 114662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 114762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 114862306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 114962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 115062306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 115162306a36Sopenharmony_ci}; 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci/* 115462306a36Sopenharmony_ci * The H3 has 12 physical channels, a maximum DRQ port id of 27, 115562306a36Sopenharmony_ci * and a total of 34 usable source and destination endpoints. 115662306a36Sopenharmony_ci * It also supports additional burst lengths and bus widths, 115762306a36Sopenharmony_ci * and the burst length fields have different offsets. 115862306a36Sopenharmony_ci */ 115962306a36Sopenharmony_ci 116062306a36Sopenharmony_cistatic struct sun6i_dma_config sun8i_h3_dma_cfg = { 116162306a36Sopenharmony_ci .nr_max_channels = 12, 116262306a36Sopenharmony_ci .nr_max_requests = 27, 116362306a36Sopenharmony_ci .nr_max_vchans = 34, 116462306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_h3, 116562306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_h3, 116662306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 116762306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 116862306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 116962306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 117062306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 117162306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 117262306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 117362306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 117462306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 117562306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 117662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 117762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 117862306a36Sopenharmony_ci}; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci/* 118162306a36Sopenharmony_ci * The A64 binding uses the number of dma channels from the 118262306a36Sopenharmony_ci * device tree node. 118362306a36Sopenharmony_ci */ 118462306a36Sopenharmony_cistatic struct sun6i_dma_config sun50i_a64_dma_cfg = { 118562306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_h3, 118662306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_h3, 118762306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 118862306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 118962306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 119062306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 119162306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 119262306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 119362306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 119462306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 119562306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 119662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 119762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 119862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 119962306a36Sopenharmony_ci}; 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci/* 120262306a36Sopenharmony_ci * The A100 binding uses the number of dma channels from the 120362306a36Sopenharmony_ci * device tree node. 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_cistatic struct sun6i_dma_config sun50i_a100_dma_cfg = { 120662306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_h3, 120762306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_h3, 120862306a36Sopenharmony_ci .set_drq = sun6i_set_drq_h6, 120962306a36Sopenharmony_ci .set_mode = sun6i_set_mode_h6, 121062306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 121162306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 121262306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 121362306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 121462306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 121562306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 121662306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 121762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 121862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 121962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 122062306a36Sopenharmony_ci .has_high_addr = true, 122162306a36Sopenharmony_ci .has_mbus_clk = true, 122262306a36Sopenharmony_ci}; 122362306a36Sopenharmony_ci 122462306a36Sopenharmony_ci/* 122562306a36Sopenharmony_ci * The H6 binding uses the number of dma channels from the 122662306a36Sopenharmony_ci * device tree node. 122762306a36Sopenharmony_ci */ 122862306a36Sopenharmony_cistatic struct sun6i_dma_config sun50i_h6_dma_cfg = { 122962306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_h3, 123062306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_h3, 123162306a36Sopenharmony_ci .set_drq = sun6i_set_drq_h6, 123262306a36Sopenharmony_ci .set_mode = sun6i_set_mode_h6, 123362306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 123462306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(4) | BIT(8) | BIT(16), 123562306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 123662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 123762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 123862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 123962306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 124062306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 124162306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | 124262306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES), 124362306a36Sopenharmony_ci .has_mbus_clk = true, 124462306a36Sopenharmony_ci}; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci/* 124762306a36Sopenharmony_ci * The V3s have only 8 physical channels, a maximum DRQ port id of 23, 124862306a36Sopenharmony_ci * and a total of 24 usable source and destination endpoints. 124962306a36Sopenharmony_ci */ 125062306a36Sopenharmony_ci 125162306a36Sopenharmony_cistatic struct sun6i_dma_config sun8i_v3s_dma_cfg = { 125262306a36Sopenharmony_ci .nr_max_channels = 8, 125362306a36Sopenharmony_ci .nr_max_requests = 23, 125462306a36Sopenharmony_ci .nr_max_vchans = 24, 125562306a36Sopenharmony_ci .clock_autogate_enable = sun6i_enable_clock_autogate_a23, 125662306a36Sopenharmony_ci .set_burst_length = sun6i_set_burst_length_a31, 125762306a36Sopenharmony_ci .set_drq = sun6i_set_drq_a31, 125862306a36Sopenharmony_ci .set_mode = sun6i_set_mode_a31, 125962306a36Sopenharmony_ci .src_burst_lengths = BIT(1) | BIT(8), 126062306a36Sopenharmony_ci .dst_burst_lengths = BIT(1) | BIT(8), 126162306a36Sopenharmony_ci .src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 126262306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 126362306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 126462306a36Sopenharmony_ci .dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | 126562306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | 126662306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES), 126762306a36Sopenharmony_ci}; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic const struct of_device_id sun6i_dma_match[] = { 127062306a36Sopenharmony_ci { .compatible = "allwinner,sun6i-a31-dma", .data = &sun6i_a31_dma_cfg }, 127162306a36Sopenharmony_ci { .compatible = "allwinner,sun8i-a23-dma", .data = &sun8i_a23_dma_cfg }, 127262306a36Sopenharmony_ci { .compatible = "allwinner,sun8i-a83t-dma", .data = &sun8i_a83t_dma_cfg }, 127362306a36Sopenharmony_ci { .compatible = "allwinner,sun8i-h3-dma", .data = &sun8i_h3_dma_cfg }, 127462306a36Sopenharmony_ci { .compatible = "allwinner,sun8i-v3s-dma", .data = &sun8i_v3s_dma_cfg }, 127562306a36Sopenharmony_ci { .compatible = "allwinner,sun20i-d1-dma", .data = &sun50i_a100_dma_cfg }, 127662306a36Sopenharmony_ci { .compatible = "allwinner,sun50i-a64-dma", .data = &sun50i_a64_dma_cfg }, 127762306a36Sopenharmony_ci { .compatible = "allwinner,sun50i-a100-dma", .data = &sun50i_a100_dma_cfg }, 127862306a36Sopenharmony_ci { .compatible = "allwinner,sun50i-h6-dma", .data = &sun50i_h6_dma_cfg }, 127962306a36Sopenharmony_ci { /* sentinel */ } 128062306a36Sopenharmony_ci}; 128162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, sun6i_dma_match); 128262306a36Sopenharmony_ci 128362306a36Sopenharmony_cistatic int sun6i_dma_probe(struct platform_device *pdev) 128462306a36Sopenharmony_ci{ 128562306a36Sopenharmony_ci struct device_node *np = pdev->dev.of_node; 128662306a36Sopenharmony_ci struct sun6i_dma_dev *sdc; 128762306a36Sopenharmony_ci int ret, i; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci sdc = devm_kzalloc(&pdev->dev, sizeof(*sdc), GFP_KERNEL); 129062306a36Sopenharmony_ci if (!sdc) 129162306a36Sopenharmony_ci return -ENOMEM; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci sdc->cfg = of_device_get_match_data(&pdev->dev); 129462306a36Sopenharmony_ci if (!sdc->cfg) 129562306a36Sopenharmony_ci return -ENODEV; 129662306a36Sopenharmony_ci 129762306a36Sopenharmony_ci sdc->base = devm_platform_ioremap_resource(pdev, 0); 129862306a36Sopenharmony_ci if (IS_ERR(sdc->base)) 129962306a36Sopenharmony_ci return PTR_ERR(sdc->base); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci sdc->irq = platform_get_irq(pdev, 0); 130262306a36Sopenharmony_ci if (sdc->irq < 0) 130362306a36Sopenharmony_ci return sdc->irq; 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci sdc->clk = devm_clk_get(&pdev->dev, NULL); 130662306a36Sopenharmony_ci if (IS_ERR(sdc->clk)) { 130762306a36Sopenharmony_ci dev_err(&pdev->dev, "No clock specified\n"); 130862306a36Sopenharmony_ci return PTR_ERR(sdc->clk); 130962306a36Sopenharmony_ci } 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (sdc->cfg->has_mbus_clk) { 131262306a36Sopenharmony_ci sdc->clk_mbus = devm_clk_get(&pdev->dev, "mbus"); 131362306a36Sopenharmony_ci if (IS_ERR(sdc->clk_mbus)) { 131462306a36Sopenharmony_ci dev_err(&pdev->dev, "No mbus clock specified\n"); 131562306a36Sopenharmony_ci return PTR_ERR(sdc->clk_mbus); 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci } 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_ci sdc->rstc = devm_reset_control_get(&pdev->dev, NULL); 132062306a36Sopenharmony_ci if (IS_ERR(sdc->rstc)) { 132162306a36Sopenharmony_ci dev_err(&pdev->dev, "No reset controller specified\n"); 132262306a36Sopenharmony_ci return PTR_ERR(sdc->rstc); 132362306a36Sopenharmony_ci } 132462306a36Sopenharmony_ci 132562306a36Sopenharmony_ci sdc->pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev, 132662306a36Sopenharmony_ci sizeof(struct sun6i_dma_lli), 4, 0); 132762306a36Sopenharmony_ci if (!sdc->pool) { 132862306a36Sopenharmony_ci dev_err(&pdev->dev, "No memory for descriptors dma pool\n"); 132962306a36Sopenharmony_ci return -ENOMEM; 133062306a36Sopenharmony_ci } 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci platform_set_drvdata(pdev, sdc); 133362306a36Sopenharmony_ci INIT_LIST_HEAD(&sdc->pending); 133462306a36Sopenharmony_ci spin_lock_init(&sdc->lock); 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci dma_set_max_seg_size(&pdev->dev, SZ_32M - 1); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, sdc->slave.cap_mask); 133962306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, sdc->slave.cap_mask); 134062306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, sdc->slave.cap_mask); 134162306a36Sopenharmony_ci dma_cap_set(DMA_CYCLIC, sdc->slave.cap_mask); 134262306a36Sopenharmony_ci 134362306a36Sopenharmony_ci INIT_LIST_HEAD(&sdc->slave.channels); 134462306a36Sopenharmony_ci sdc->slave.device_free_chan_resources = sun6i_dma_free_chan_resources; 134562306a36Sopenharmony_ci sdc->slave.device_tx_status = sun6i_dma_tx_status; 134662306a36Sopenharmony_ci sdc->slave.device_issue_pending = sun6i_dma_issue_pending; 134762306a36Sopenharmony_ci sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg; 134862306a36Sopenharmony_ci sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy; 134962306a36Sopenharmony_ci sdc->slave.device_prep_dma_cyclic = sun6i_dma_prep_dma_cyclic; 135062306a36Sopenharmony_ci sdc->slave.copy_align = DMAENGINE_ALIGN_4_BYTES; 135162306a36Sopenharmony_ci sdc->slave.device_config = sun6i_dma_config; 135262306a36Sopenharmony_ci sdc->slave.device_pause = sun6i_dma_pause; 135362306a36Sopenharmony_ci sdc->slave.device_resume = sun6i_dma_resume; 135462306a36Sopenharmony_ci sdc->slave.device_terminate_all = sun6i_dma_terminate_all; 135562306a36Sopenharmony_ci sdc->slave.src_addr_widths = sdc->cfg->src_addr_widths; 135662306a36Sopenharmony_ci sdc->slave.dst_addr_widths = sdc->cfg->dst_addr_widths; 135762306a36Sopenharmony_ci sdc->slave.directions = BIT(DMA_DEV_TO_MEM) | 135862306a36Sopenharmony_ci BIT(DMA_MEM_TO_DEV); 135962306a36Sopenharmony_ci sdc->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 136062306a36Sopenharmony_ci sdc->slave.dev = &pdev->dev; 136162306a36Sopenharmony_ci 136262306a36Sopenharmony_ci sdc->num_pchans = sdc->cfg->nr_max_channels; 136362306a36Sopenharmony_ci sdc->num_vchans = sdc->cfg->nr_max_vchans; 136462306a36Sopenharmony_ci sdc->max_request = sdc->cfg->nr_max_requests; 136562306a36Sopenharmony_ci 136662306a36Sopenharmony_ci ret = of_property_read_u32(np, "dma-channels", &sdc->num_pchans); 136762306a36Sopenharmony_ci if (ret && !sdc->num_pchans) { 136862306a36Sopenharmony_ci dev_err(&pdev->dev, "Can't get dma-channels.\n"); 136962306a36Sopenharmony_ci return ret; 137062306a36Sopenharmony_ci } 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci ret = of_property_read_u32(np, "dma-requests", &sdc->max_request); 137362306a36Sopenharmony_ci if (ret && !sdc->max_request) { 137462306a36Sopenharmony_ci dev_info(&pdev->dev, "Missing dma-requests, using %u.\n", 137562306a36Sopenharmony_ci DMA_CHAN_MAX_DRQ_A31); 137662306a36Sopenharmony_ci sdc->max_request = DMA_CHAN_MAX_DRQ_A31; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* 138062306a36Sopenharmony_ci * If the number of vchans is not specified, derive it from the 138162306a36Sopenharmony_ci * highest port number, at most one channel per port and direction. 138262306a36Sopenharmony_ci */ 138362306a36Sopenharmony_ci if (!sdc->num_vchans) 138462306a36Sopenharmony_ci sdc->num_vchans = 2 * (sdc->max_request + 1); 138562306a36Sopenharmony_ci 138662306a36Sopenharmony_ci sdc->pchans = devm_kcalloc(&pdev->dev, sdc->num_pchans, 138762306a36Sopenharmony_ci sizeof(struct sun6i_pchan), GFP_KERNEL); 138862306a36Sopenharmony_ci if (!sdc->pchans) 138962306a36Sopenharmony_ci return -ENOMEM; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci sdc->vchans = devm_kcalloc(&pdev->dev, sdc->num_vchans, 139262306a36Sopenharmony_ci sizeof(struct sun6i_vchan), GFP_KERNEL); 139362306a36Sopenharmony_ci if (!sdc->vchans) 139462306a36Sopenharmony_ci return -ENOMEM; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci tasklet_setup(&sdc->task, sun6i_dma_tasklet); 139762306a36Sopenharmony_ci 139862306a36Sopenharmony_ci for (i = 0; i < sdc->num_pchans; i++) { 139962306a36Sopenharmony_ci struct sun6i_pchan *pchan = &sdc->pchans[i]; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci pchan->idx = i; 140262306a36Sopenharmony_ci pchan->base = sdc->base + 0x100 + i * 0x40; 140362306a36Sopenharmony_ci } 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci for (i = 0; i < sdc->num_vchans; i++) { 140662306a36Sopenharmony_ci struct sun6i_vchan *vchan = &sdc->vchans[i]; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci INIT_LIST_HEAD(&vchan->node); 140962306a36Sopenharmony_ci vchan->vc.desc_free = sun6i_dma_free_desc; 141062306a36Sopenharmony_ci vchan_init(&vchan->vc, &sdc->slave); 141162306a36Sopenharmony_ci } 141262306a36Sopenharmony_ci 141362306a36Sopenharmony_ci ret = reset_control_deassert(sdc->rstc); 141462306a36Sopenharmony_ci if (ret) { 141562306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't deassert the device from reset\n"); 141662306a36Sopenharmony_ci goto err_chan_free; 141762306a36Sopenharmony_ci } 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci ret = clk_prepare_enable(sdc->clk); 142062306a36Sopenharmony_ci if (ret) { 142162306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't enable the clock\n"); 142262306a36Sopenharmony_ci goto err_reset_assert; 142362306a36Sopenharmony_ci } 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci if (sdc->cfg->has_mbus_clk) { 142662306a36Sopenharmony_ci ret = clk_prepare_enable(sdc->clk_mbus); 142762306a36Sopenharmony_ci if (ret) { 142862306a36Sopenharmony_ci dev_err(&pdev->dev, "Couldn't enable mbus clock\n"); 142962306a36Sopenharmony_ci goto err_clk_disable; 143062306a36Sopenharmony_ci } 143162306a36Sopenharmony_ci } 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, sdc->irq, sun6i_dma_interrupt, 0, 143462306a36Sopenharmony_ci dev_name(&pdev->dev), sdc); 143562306a36Sopenharmony_ci if (ret) { 143662306a36Sopenharmony_ci dev_err(&pdev->dev, "Cannot request IRQ\n"); 143762306a36Sopenharmony_ci goto err_mbus_clk_disable; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci ret = dma_async_device_register(&sdc->slave); 144162306a36Sopenharmony_ci if (ret) { 144262306a36Sopenharmony_ci dev_warn(&pdev->dev, "Failed to register DMA engine device\n"); 144362306a36Sopenharmony_ci goto err_irq_disable; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci ret = of_dma_controller_register(pdev->dev.of_node, sun6i_dma_of_xlate, 144762306a36Sopenharmony_ci sdc); 144862306a36Sopenharmony_ci if (ret) { 144962306a36Sopenharmony_ci dev_err(&pdev->dev, "of_dma_controller_register failed\n"); 145062306a36Sopenharmony_ci goto err_dma_unregister; 145162306a36Sopenharmony_ci } 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci if (sdc->cfg->clock_autogate_enable) 145462306a36Sopenharmony_ci sdc->cfg->clock_autogate_enable(sdc); 145562306a36Sopenharmony_ci 145662306a36Sopenharmony_ci return 0; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_cierr_dma_unregister: 145962306a36Sopenharmony_ci dma_async_device_unregister(&sdc->slave); 146062306a36Sopenharmony_cierr_irq_disable: 146162306a36Sopenharmony_ci sun6i_kill_tasklet(sdc); 146262306a36Sopenharmony_cierr_mbus_clk_disable: 146362306a36Sopenharmony_ci clk_disable_unprepare(sdc->clk_mbus); 146462306a36Sopenharmony_cierr_clk_disable: 146562306a36Sopenharmony_ci clk_disable_unprepare(sdc->clk); 146662306a36Sopenharmony_cierr_reset_assert: 146762306a36Sopenharmony_ci reset_control_assert(sdc->rstc); 146862306a36Sopenharmony_cierr_chan_free: 146962306a36Sopenharmony_ci sun6i_dma_free(sdc); 147062306a36Sopenharmony_ci return ret; 147162306a36Sopenharmony_ci} 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_cistatic int sun6i_dma_remove(struct platform_device *pdev) 147462306a36Sopenharmony_ci{ 147562306a36Sopenharmony_ci struct sun6i_dma_dev *sdc = platform_get_drvdata(pdev); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci of_dma_controller_free(pdev->dev.of_node); 147862306a36Sopenharmony_ci dma_async_device_unregister(&sdc->slave); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci sun6i_kill_tasklet(sdc); 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci clk_disable_unprepare(sdc->clk_mbus); 148362306a36Sopenharmony_ci clk_disable_unprepare(sdc->clk); 148462306a36Sopenharmony_ci reset_control_assert(sdc->rstc); 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_ci sun6i_dma_free(sdc); 148762306a36Sopenharmony_ci 148862306a36Sopenharmony_ci return 0; 148962306a36Sopenharmony_ci} 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_cistatic struct platform_driver sun6i_dma_driver = { 149262306a36Sopenharmony_ci .probe = sun6i_dma_probe, 149362306a36Sopenharmony_ci .remove = sun6i_dma_remove, 149462306a36Sopenharmony_ci .driver = { 149562306a36Sopenharmony_ci .name = "sun6i-dma", 149662306a36Sopenharmony_ci .of_match_table = sun6i_dma_match, 149762306a36Sopenharmony_ci }, 149862306a36Sopenharmony_ci}; 149962306a36Sopenharmony_cimodule_platform_driver(sun6i_dma_driver); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ciMODULE_DESCRIPTION("Allwinner A31 DMA Controller Driver"); 150262306a36Sopenharmony_ciMODULE_AUTHOR("Sugar <shuge@allwinnertech.com>"); 150362306a36Sopenharmony_ciMODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>"); 150462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1505