162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * DMA driver for NVIDIA Tegra GPC DMA controller. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2014-2022, NVIDIA CORPORATION. All rights reserved. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/dmaengine.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/interrupt.h> 1262306a36Sopenharmony_ci#include <linux/iommu.h> 1362306a36Sopenharmony_ci#include <linux/iopoll.h> 1462306a36Sopenharmony_ci#include <linux/minmax.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/of.h> 1762306a36Sopenharmony_ci#include <linux/of_dma.h> 1862306a36Sopenharmony_ci#include <linux/platform_device.h> 1962306a36Sopenharmony_ci#include <linux/reset.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci#include <dt-bindings/memory/tegra186-mc.h> 2262306a36Sopenharmony_ci#include "virt-dma.h" 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci/* CSR register */ 2562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSR 0x00 2662306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_ENB BIT(31) 2762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_IE_EOC BIT(30) 2862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_ONCE BIT(27) 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE GENMASK(25, 24) 3162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_NO_MMIO \ 3262306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 0) 3362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_ONE_MMIO \ 3462306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 1) 3562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_TWO_MMIO \ 3662306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 2) 3762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_FC_MODE_FOUR_MMIO \ 3862306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_FC_MODE, 3) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA GENMASK(23, 21) 4162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_IO2MEM_NO_FC \ 4262306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 0) 4362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_IO2MEM_FC \ 4462306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 1) 4562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2IO_NO_FC \ 4662306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 2) 4762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2IO_FC \ 4862306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 3) 4962306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_MEM2MEM \ 5062306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 4) 5162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_DMA_FIXED_PAT \ 5262306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_DMA, 6) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_REQ_SEL_MASK GENMASK(20, 16) 5562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED \ 5662306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, 4) 5762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_IRQ_MASK BIT(15) 5862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CSR_WEIGHT GENMASK(13, 10) 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/* STATUS register */ 6162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_STATUS 0x004 6262306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_BUSY BIT(31) 6362306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_ISE_EOC BIT(30) 6462306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_PING_PONG BIT(28) 6562306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_DMA_ACTIVITY BIT(27) 6662306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_PAUSE BIT(26) 6762306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_RX BIT(25) 6862306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_CHANNEL_TX BIT(24) 6962306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_INTR_STA BIT(23) 7062306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_STA BIT(21) 7162306a36Sopenharmony_ci#define TEGRA_GPCDMA_STATUS_IRQ_TRIG_STA BIT(20) 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSRE 0x008 7462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_CSRE_PAUSE BIT(31) 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci/* Source address */ 7762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SRC_PTR 0x00C 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci/* Destination address */ 8062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_DST_PTR 0x010 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* High address pointer */ 8362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR 0x014 8462306a36Sopenharmony_ci#define TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR GENMASK(7, 0) 8562306a36Sopenharmony_ci#define TEGRA_GPCDMA_HIGH_ADDR_DST_PTR GENMASK(23, 16) 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci/* MC sequence register */ 8862306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_MCSEQ 0x18 8962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_DATA_SWAP BIT(31) 9062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_REQ_COUNT GENMASK(30, 25) 9162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST GENMASK(24, 23) 9262306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST_2 \ 9362306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_MCSEQ_BURST, 0) 9462306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_BURST_16 \ 9562306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_MCSEQ_BURST, 3) 9662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP1 GENMASK(22, 20) 9762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP0 GENMASK(19, 17) 9862306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_WRAP_NONE 0 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK GENMASK(13, 7) 10162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK GENMASK(6, 0) 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci/* MMIO sequence register */ 10462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_MMIOSEQ 0x01c 10562306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_DBL_BUF BIT(31) 10662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH GENMASK(30, 28) 10762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8 \ 10862306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 0) 10962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_16 \ 11062306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 1) 11162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_32 \ 11262306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH, 2) 11362306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_DATA_SWAP BIT(27) 11462306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_SHIFT 23 11562306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_MIN 2U 11662306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST_MAX 32U 11762306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_BURST(bs) \ 11862306a36Sopenharmony_ci (GENMASK((fls(bs) - 2), 0) << TEGRA_GPCDMA_MMIOSEQ_BURST_SHIFT) 11962306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_MASTER_ID GENMASK(22, 19) 12062306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD GENMASK(18, 16) 12162306a36Sopenharmony_ci#define TEGRA_GPCDMA_MMIOSEQ_MMIO_PROT GENMASK(8, 7) 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci/* Channel WCOUNT */ 12462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_WCOUNT 0x20 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci/* Transfer count */ 12762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_XFER_COUNT 0x24 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci/* DMA byte count status */ 13062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS 0x28 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci/* Error Status Register */ 13362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_STATUS 0x30 13462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT 8 13562306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK 0xF 13662306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_ERR_TYPE(err) ( \ 13762306a36Sopenharmony_ci ((err) >> TEGRA_GPCDMA_CHAN_ERR_TYPE_SHIFT) & \ 13862306a36Sopenharmony_ci TEGRA_GPCDMA_CHAN_ERR_TYPE_MASK) 13962306a36Sopenharmony_ci#define TEGRA_DMA_BM_FIFO_FULL_ERR 0xF 14062306a36Sopenharmony_ci#define TEGRA_DMA_PERIPH_FIFO_FULL_ERR 0xE 14162306a36Sopenharmony_ci#define TEGRA_DMA_PERIPH_ID_ERR 0xD 14262306a36Sopenharmony_ci#define TEGRA_DMA_STREAM_ID_ERR 0xC 14362306a36Sopenharmony_ci#define TEGRA_DMA_MC_SLAVE_ERR 0xB 14462306a36Sopenharmony_ci#define TEGRA_DMA_MMIO_SLAVE_ERR 0xA 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci/* Fixed Pattern */ 14762306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_FIXED_PATTERN 0x34 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ 0x38 15062306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ_MMIO_PROT_1 BIT(0) 15162306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_TZ_MC_PROT_1 BIT(1) 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SPARE 0x3c 15462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHAN_SPARE_EN_LEGACY_FC BIT(16) 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* 15762306a36Sopenharmony_ci * If any burst is in flight and DMA paused then this is the time to complete 15862306a36Sopenharmony_ci * on-flight burst and update DMA status register. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci#define TEGRA_GPCDMA_BURST_COMPLETE_TIME 10 16162306a36Sopenharmony_ci#define TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT 5000 /* 5 msec */ 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* Channel base address offset from GPCDMA base address */ 16462306a36Sopenharmony_ci#define TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET 0x10000 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci/* Default channel mask reserving channel0 */ 16762306a36Sopenharmony_ci#define TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK 0xfffffffe 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistruct tegra_dma; 17062306a36Sopenharmony_cistruct tegra_dma_channel; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci/* 17362306a36Sopenharmony_ci * tegra_dma_chip_data Tegra chip specific DMA data 17462306a36Sopenharmony_ci * @nr_channels: Number of channels available in the controller. 17562306a36Sopenharmony_ci * @channel_reg_size: Channel register size. 17662306a36Sopenharmony_ci * @max_dma_count: Maximum DMA transfer count supported by DMA controller. 17762306a36Sopenharmony_ci * @hw_support_pause: DMA HW engine support pause of the channel. 17862306a36Sopenharmony_ci */ 17962306a36Sopenharmony_cistruct tegra_dma_chip_data { 18062306a36Sopenharmony_ci bool hw_support_pause; 18162306a36Sopenharmony_ci unsigned int nr_channels; 18262306a36Sopenharmony_ci unsigned int channel_reg_size; 18362306a36Sopenharmony_ci unsigned int max_dma_count; 18462306a36Sopenharmony_ci int (*terminate)(struct tegra_dma_channel *tdc); 18562306a36Sopenharmony_ci}; 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_ci/* DMA channel registers */ 18862306a36Sopenharmony_cistruct tegra_dma_channel_regs { 18962306a36Sopenharmony_ci u32 csr; 19062306a36Sopenharmony_ci u32 src_ptr; 19162306a36Sopenharmony_ci u32 dst_ptr; 19262306a36Sopenharmony_ci u32 high_addr_ptr; 19362306a36Sopenharmony_ci u32 mc_seq; 19462306a36Sopenharmony_ci u32 mmio_seq; 19562306a36Sopenharmony_ci u32 wcount; 19662306a36Sopenharmony_ci u32 fixed_pattern; 19762306a36Sopenharmony_ci}; 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci/* 20062306a36Sopenharmony_ci * tegra_dma_sg_req: DMA request details to configure hardware. This 20162306a36Sopenharmony_ci * contains the details for one transfer to configure DMA hw. 20262306a36Sopenharmony_ci * The client's request for data transfer can be broken into multiple 20362306a36Sopenharmony_ci * sub-transfer as per requester details and hw support. This sub transfer 20462306a36Sopenharmony_ci * get added as an array in Tegra DMA desc which manages the transfer details. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_cistruct tegra_dma_sg_req { 20762306a36Sopenharmony_ci unsigned int len; 20862306a36Sopenharmony_ci struct tegra_dma_channel_regs ch_regs; 20962306a36Sopenharmony_ci}; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci/* 21262306a36Sopenharmony_ci * tegra_dma_desc: Tegra DMA descriptors which uses virt_dma_desc to 21362306a36Sopenharmony_ci * manage client request and keep track of transfer status, callbacks 21462306a36Sopenharmony_ci * and request counts etc. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_cistruct tegra_dma_desc { 21762306a36Sopenharmony_ci bool cyclic; 21862306a36Sopenharmony_ci unsigned int bytes_req; 21962306a36Sopenharmony_ci unsigned int bytes_xfer; 22062306a36Sopenharmony_ci unsigned int sg_idx; 22162306a36Sopenharmony_ci unsigned int sg_count; 22262306a36Sopenharmony_ci struct virt_dma_desc vd; 22362306a36Sopenharmony_ci struct tegra_dma_channel *tdc; 22462306a36Sopenharmony_ci struct tegra_dma_sg_req sg_req[]; 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci/* 22862306a36Sopenharmony_ci * tegra_dma_channel: Channel specific information 22962306a36Sopenharmony_ci */ 23062306a36Sopenharmony_cistruct tegra_dma_channel { 23162306a36Sopenharmony_ci bool config_init; 23262306a36Sopenharmony_ci char name[30]; 23362306a36Sopenharmony_ci enum dma_transfer_direction sid_dir; 23462306a36Sopenharmony_ci int id; 23562306a36Sopenharmony_ci int irq; 23662306a36Sopenharmony_ci int slave_id; 23762306a36Sopenharmony_ci struct tegra_dma *tdma; 23862306a36Sopenharmony_ci struct virt_dma_chan vc; 23962306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 24062306a36Sopenharmony_ci struct dma_slave_config dma_sconfig; 24162306a36Sopenharmony_ci unsigned int stream_id; 24262306a36Sopenharmony_ci unsigned long chan_base_offset; 24362306a36Sopenharmony_ci}; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci/* 24662306a36Sopenharmony_ci * tegra_dma: Tegra DMA specific information 24762306a36Sopenharmony_ci */ 24862306a36Sopenharmony_cistruct tegra_dma { 24962306a36Sopenharmony_ci const struct tegra_dma_chip_data *chip_data; 25062306a36Sopenharmony_ci unsigned long sid_m2d_reserved; 25162306a36Sopenharmony_ci unsigned long sid_d2m_reserved; 25262306a36Sopenharmony_ci u32 chan_mask; 25362306a36Sopenharmony_ci void __iomem *base_addr; 25462306a36Sopenharmony_ci struct device *dev; 25562306a36Sopenharmony_ci struct dma_device dma_dev; 25662306a36Sopenharmony_ci struct reset_control *rst; 25762306a36Sopenharmony_ci struct tegra_dma_channel channels[]; 25862306a36Sopenharmony_ci}; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_cistatic inline void tdc_write(struct tegra_dma_channel *tdc, 26162306a36Sopenharmony_ci u32 reg, u32 val) 26262306a36Sopenharmony_ci{ 26362306a36Sopenharmony_ci writel_relaxed(val, tdc->tdma->base_addr + tdc->chan_base_offset + reg); 26462306a36Sopenharmony_ci} 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_cistatic inline u32 tdc_read(struct tegra_dma_channel *tdc, u32 reg) 26762306a36Sopenharmony_ci{ 26862306a36Sopenharmony_ci return readl_relaxed(tdc->tdma->base_addr + tdc->chan_base_offset + reg); 26962306a36Sopenharmony_ci} 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_cistatic inline struct tegra_dma_channel *to_tegra_dma_chan(struct dma_chan *dc) 27262306a36Sopenharmony_ci{ 27362306a36Sopenharmony_ci return container_of(dc, struct tegra_dma_channel, vc.chan); 27462306a36Sopenharmony_ci} 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_cistatic inline struct tegra_dma_desc *vd_to_tegra_dma_desc(struct virt_dma_desc *vd) 27762306a36Sopenharmony_ci{ 27862306a36Sopenharmony_ci return container_of(vd, struct tegra_dma_desc, vd); 27962306a36Sopenharmony_ci} 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic inline struct device *tdc2dev(struct tegra_dma_channel *tdc) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci return tdc->vc.chan.device->dev; 28462306a36Sopenharmony_ci} 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_cistatic void tegra_dma_dump_chan_regs(struct tegra_dma_channel *tdc) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "DMA Channel %d name %s register dump:\n", 28962306a36Sopenharmony_ci tdc->id, tdc->name); 29062306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "CSR %x STA %x CSRE %x SRC %x DST %x\n", 29162306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR), 29262306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS), 29362306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE), 29462306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR), 29562306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_DST_PTR) 29662306a36Sopenharmony_ci ); 29762306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "MCSEQ %x IOSEQ %x WCNT %x XFER %x BSTA %x\n", 29862306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ), 29962306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ), 30062306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_WCOUNT), 30162306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT), 30262306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_DMA_BYTE_STATUS) 30362306a36Sopenharmony_ci ); 30462306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "DMA ERR_STA %x\n", 30562306a36Sopenharmony_ci tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS)); 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic int tegra_dma_sid_reserve(struct tegra_dma_channel *tdc, 30962306a36Sopenharmony_ci enum dma_transfer_direction direction) 31062306a36Sopenharmony_ci{ 31162306a36Sopenharmony_ci struct tegra_dma *tdma = tdc->tdma; 31262306a36Sopenharmony_ci int sid = tdc->slave_id; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci if (!is_slave_direction(direction)) 31562306a36Sopenharmony_ci return 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci switch (direction) { 31862306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 31962306a36Sopenharmony_ci if (test_and_set_bit(sid, &tdma->sid_m2d_reserved)) { 32062306a36Sopenharmony_ci dev_err(tdma->dev, "slave id already in use\n"); 32162306a36Sopenharmony_ci return -EINVAL; 32262306a36Sopenharmony_ci } 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 32562306a36Sopenharmony_ci if (test_and_set_bit(sid, &tdma->sid_d2m_reserved)) { 32662306a36Sopenharmony_ci dev_err(tdma->dev, "slave id already in use\n"); 32762306a36Sopenharmony_ci return -EINVAL; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci break; 33062306a36Sopenharmony_ci default: 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci tdc->sid_dir = direction; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci return 0; 33762306a36Sopenharmony_ci} 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_cistatic void tegra_dma_sid_free(struct tegra_dma_channel *tdc) 34062306a36Sopenharmony_ci{ 34162306a36Sopenharmony_ci struct tegra_dma *tdma = tdc->tdma; 34262306a36Sopenharmony_ci int sid = tdc->slave_id; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci switch (tdc->sid_dir) { 34562306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 34662306a36Sopenharmony_ci clear_bit(sid, &tdma->sid_m2d_reserved); 34762306a36Sopenharmony_ci break; 34862306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 34962306a36Sopenharmony_ci clear_bit(sid, &tdma->sid_d2m_reserved); 35062306a36Sopenharmony_ci break; 35162306a36Sopenharmony_ci default: 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci } 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci tdc->sid_dir = DMA_TRANS_NONE; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void tegra_dma_desc_free(struct virt_dma_desc *vd) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci kfree(container_of(vd, struct tegra_dma_desc, vd)); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic int tegra_dma_slave_config(struct dma_chan *dc, 36462306a36Sopenharmony_ci struct dma_slave_config *sconfig) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci memcpy(&tdc->dma_sconfig, sconfig, sizeof(*sconfig)); 36962306a36Sopenharmony_ci tdc->config_init = true; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci return 0; 37262306a36Sopenharmony_ci} 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_cistatic int tegra_dma_pause(struct tegra_dma_channel *tdc) 37562306a36Sopenharmony_ci{ 37662306a36Sopenharmony_ci int ret; 37762306a36Sopenharmony_ci u32 val; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE); 38062306a36Sopenharmony_ci val |= TEGRA_GPCDMA_CHAN_CSRE_PAUSE; 38162306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* Wait until busy bit is de-asserted */ 38462306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + 38562306a36Sopenharmony_ci tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS, 38662306a36Sopenharmony_ci val, 38762306a36Sopenharmony_ci !(val & TEGRA_GPCDMA_STATUS_BUSY), 38862306a36Sopenharmony_ci TEGRA_GPCDMA_BURST_COMPLETE_TIME, 38962306a36Sopenharmony_ci TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT); 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci if (ret) { 39262306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "DMA pause timed out\n"); 39362306a36Sopenharmony_ci tegra_dma_dump_chan_regs(tdc); 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return ret; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic int tegra_dma_device_pause(struct dma_chan *dc) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 40262306a36Sopenharmony_ci unsigned long flags; 40362306a36Sopenharmony_ci int ret; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci if (!tdc->tdma->chip_data->hw_support_pause) 40662306a36Sopenharmony_ci return -ENOSYS; 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci spin_lock_irqsave(&tdc->vc.lock, flags); 40962306a36Sopenharmony_ci ret = tegra_dma_pause(tdc); 41062306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci return ret; 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic void tegra_dma_resume(struct tegra_dma_channel *tdc) 41662306a36Sopenharmony_ci{ 41762306a36Sopenharmony_ci u32 val; 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSRE); 42062306a36Sopenharmony_ci val &= ~TEGRA_GPCDMA_CHAN_CSRE_PAUSE; 42162306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSRE, val); 42262306a36Sopenharmony_ci} 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_cistatic int tegra_dma_device_resume(struct dma_chan *dc) 42562306a36Sopenharmony_ci{ 42662306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 42762306a36Sopenharmony_ci unsigned long flags; 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci if (!tdc->tdma->chip_data->hw_support_pause) 43062306a36Sopenharmony_ci return -ENOSYS; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci spin_lock_irqsave(&tdc->vc.lock, flags); 43362306a36Sopenharmony_ci tegra_dma_resume(tdc); 43462306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic inline int tegra_dma_pause_noerr(struct tegra_dma_channel *tdc) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci /* Return 0 irrespective of PAUSE status. 44262306a36Sopenharmony_ci * This is useful to recover channels that can exit out of flush 44362306a36Sopenharmony_ci * state when the channel is disabled. 44462306a36Sopenharmony_ci */ 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci tegra_dma_pause(tdc); 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_cistatic void tegra_dma_disable(struct tegra_dma_channel *tdc) 45162306a36Sopenharmony_ci{ 45262306a36Sopenharmony_ci u32 csr, status; 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ci csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* Disable interrupts */ 45762306a36Sopenharmony_ci csr &= ~TEGRA_GPCDMA_CSR_IE_EOC; 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci /* Disable DMA */ 46062306a36Sopenharmony_ci csr &= ~TEGRA_GPCDMA_CSR_ENB; 46162306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci /* Clear interrupt status if it is there */ 46462306a36Sopenharmony_ci status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); 46562306a36Sopenharmony_ci if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) { 46662306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "%s():clearing interrupt\n", __func__); 46762306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, status); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci} 47062306a36Sopenharmony_ci 47162306a36Sopenharmony_cistatic void tegra_dma_configure_next_sg(struct tegra_dma_channel *tdc) 47262306a36Sopenharmony_ci{ 47362306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc = tdc->dma_desc; 47462306a36Sopenharmony_ci struct tegra_dma_channel_regs *ch_regs; 47562306a36Sopenharmony_ci int ret; 47662306a36Sopenharmony_ci u32 val; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci dma_desc->sg_idx++; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci /* Reset the sg index for cyclic transfers */ 48162306a36Sopenharmony_ci if (dma_desc->sg_idx == dma_desc->sg_count) 48262306a36Sopenharmony_ci dma_desc->sg_idx = 0; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci /* Configure next transfer immediately after DMA is busy */ 48562306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + 48662306a36Sopenharmony_ci tdc->chan_base_offset + TEGRA_GPCDMA_CHAN_STATUS, 48762306a36Sopenharmony_ci val, 48862306a36Sopenharmony_ci (val & TEGRA_GPCDMA_STATUS_BUSY), 0, 48962306a36Sopenharmony_ci TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT); 49062306a36Sopenharmony_ci if (ret) 49162306a36Sopenharmony_ci return; 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs; 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount); 49662306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr); 49762306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr); 49862306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr); 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci /* Start DMA */ 50162306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 50262306a36Sopenharmony_ci ch_regs->csr | TEGRA_GPCDMA_CSR_ENB); 50362306a36Sopenharmony_ci} 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_cistatic void tegra_dma_start(struct tegra_dma_channel *tdc) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc = tdc->dma_desc; 50862306a36Sopenharmony_ci struct tegra_dma_channel_regs *ch_regs; 50962306a36Sopenharmony_ci struct virt_dma_desc *vdesc; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci if (!dma_desc) { 51262306a36Sopenharmony_ci vdesc = vchan_next_desc(&tdc->vc); 51362306a36Sopenharmony_ci if (!vdesc) 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci dma_desc = vd_to_tegra_dma_desc(vdesc); 51762306a36Sopenharmony_ci list_del(&vdesc->node); 51862306a36Sopenharmony_ci dma_desc->tdc = tdc; 51962306a36Sopenharmony_ci tdc->dma_desc = dma_desc; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci tegra_dma_resume(tdc); 52262306a36Sopenharmony_ci } 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ch_regs = &dma_desc->sg_req[dma_desc->sg_idx].ch_regs; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_WCOUNT, ch_regs->wcount); 52762306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 0); 52862306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_SRC_PTR, ch_regs->src_ptr); 52962306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_DST_PTR, ch_regs->dst_ptr); 53062306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_HIGH_ADDR_PTR, ch_regs->high_addr_ptr); 53162306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_FIXED_PATTERN, ch_regs->fixed_pattern); 53262306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_MMIOSEQ, ch_regs->mmio_seq); 53362306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, ch_regs->mc_seq); 53462306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, ch_regs->csr); 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci /* Start DMA */ 53762306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, 53862306a36Sopenharmony_ci ch_regs->csr | TEGRA_GPCDMA_CSR_ENB); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_cistatic void tegra_dma_xfer_complete(struct tegra_dma_channel *tdc) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci vchan_cookie_complete(&tdc->dma_desc->vd); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci tegra_dma_sid_free(tdc); 54662306a36Sopenharmony_ci tdc->dma_desc = NULL; 54762306a36Sopenharmony_ci} 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_cistatic void tegra_dma_chan_decode_error(struct tegra_dma_channel *tdc, 55062306a36Sopenharmony_ci unsigned int err_status) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci switch (TEGRA_GPCDMA_CHAN_ERR_TYPE(err_status)) { 55362306a36Sopenharmony_ci case TEGRA_DMA_BM_FIFO_FULL_ERR: 55462306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 55562306a36Sopenharmony_ci "GPCDMA CH%d bm fifo full\n", tdc->id); 55662306a36Sopenharmony_ci break; 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci case TEGRA_DMA_PERIPH_FIFO_FULL_ERR: 55962306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 56062306a36Sopenharmony_ci "GPCDMA CH%d peripheral fifo full\n", tdc->id); 56162306a36Sopenharmony_ci break; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci case TEGRA_DMA_PERIPH_ID_ERR: 56462306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 56562306a36Sopenharmony_ci "GPCDMA CH%d illegal peripheral id\n", tdc->id); 56662306a36Sopenharmony_ci break; 56762306a36Sopenharmony_ci 56862306a36Sopenharmony_ci case TEGRA_DMA_STREAM_ID_ERR: 56962306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 57062306a36Sopenharmony_ci "GPCDMA CH%d illegal stream id\n", tdc->id); 57162306a36Sopenharmony_ci break; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci case TEGRA_DMA_MC_SLAVE_ERR: 57462306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 57562306a36Sopenharmony_ci "GPCDMA CH%d mc slave error\n", tdc->id); 57662306a36Sopenharmony_ci break; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci case TEGRA_DMA_MMIO_SLAVE_ERR: 57962306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 58062306a36Sopenharmony_ci "GPCDMA CH%d mmio slave error\n", tdc->id); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci default: 58462306a36Sopenharmony_ci dev_err(tdc->tdma->dev, 58562306a36Sopenharmony_ci "GPCDMA CH%d security violation %x\n", tdc->id, 58662306a36Sopenharmony_ci err_status); 58762306a36Sopenharmony_ci } 58862306a36Sopenharmony_ci} 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_cistatic irqreturn_t tegra_dma_isr(int irq, void *dev_id) 59162306a36Sopenharmony_ci{ 59262306a36Sopenharmony_ci struct tegra_dma_channel *tdc = dev_id; 59362306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc = tdc->dma_desc; 59462306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req; 59562306a36Sopenharmony_ci u32 status; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci /* Check channel error status register */ 59862306a36Sopenharmony_ci status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS); 59962306a36Sopenharmony_ci if (status) { 60062306a36Sopenharmony_ci tegra_dma_chan_decode_error(tdc, status); 60162306a36Sopenharmony_ci tegra_dma_dump_chan_regs(tdc); 60262306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_ERR_STATUS, 0xFFFFFFFF); 60362306a36Sopenharmony_ci } 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci spin_lock(&tdc->vc.lock); 60662306a36Sopenharmony_ci status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); 60762306a36Sopenharmony_ci if (!(status & TEGRA_GPCDMA_STATUS_ISE_EOC)) 60862306a36Sopenharmony_ci goto irq_done; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_STATUS, 61162306a36Sopenharmony_ci TEGRA_GPCDMA_STATUS_ISE_EOC); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (!dma_desc) 61462306a36Sopenharmony_ci goto irq_done; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci sg_req = dma_desc->sg_req; 61762306a36Sopenharmony_ci dma_desc->bytes_xfer += sg_req[dma_desc->sg_idx].len; 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci if (dma_desc->cyclic) { 62062306a36Sopenharmony_ci vchan_cyclic_callback(&dma_desc->vd); 62162306a36Sopenharmony_ci tegra_dma_configure_next_sg(tdc); 62262306a36Sopenharmony_ci } else { 62362306a36Sopenharmony_ci dma_desc->sg_idx++; 62462306a36Sopenharmony_ci if (dma_desc->sg_idx == dma_desc->sg_count) 62562306a36Sopenharmony_ci tegra_dma_xfer_complete(tdc); 62662306a36Sopenharmony_ci else 62762306a36Sopenharmony_ci tegra_dma_start(tdc); 62862306a36Sopenharmony_ci } 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ciirq_done: 63162306a36Sopenharmony_ci spin_unlock(&tdc->vc.lock); 63262306a36Sopenharmony_ci return IRQ_HANDLED; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void tegra_dma_issue_pending(struct dma_chan *dc) 63662306a36Sopenharmony_ci{ 63762306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 63862306a36Sopenharmony_ci unsigned long flags; 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (tdc->dma_desc) 64162306a36Sopenharmony_ci return; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci spin_lock_irqsave(&tdc->vc.lock, flags); 64462306a36Sopenharmony_ci if (vchan_issue_pending(&tdc->vc)) 64562306a36Sopenharmony_ci tegra_dma_start(tdc); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci /* 64862306a36Sopenharmony_ci * For cyclic DMA transfers, program the second 64962306a36Sopenharmony_ci * transfer parameters as soon as the first DMA 65062306a36Sopenharmony_ci * transfer is started inorder for the DMA 65162306a36Sopenharmony_ci * controller to trigger the second transfer 65262306a36Sopenharmony_ci * with the correct parameters. 65362306a36Sopenharmony_ci */ 65462306a36Sopenharmony_ci if (tdc->dma_desc && tdc->dma_desc->cyclic) 65562306a36Sopenharmony_ci tegra_dma_configure_next_sg(tdc); 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 65862306a36Sopenharmony_ci} 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_cistatic int tegra_dma_stop_client(struct tegra_dma_channel *tdc) 66162306a36Sopenharmony_ci{ 66262306a36Sopenharmony_ci int ret; 66362306a36Sopenharmony_ci u32 status, csr; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci /* 66662306a36Sopenharmony_ci * Change the client associated with the DMA channel 66762306a36Sopenharmony_ci * to stop DMA engine from starting any more bursts for 66862306a36Sopenharmony_ci * the given client and wait for in flight bursts to complete 66962306a36Sopenharmony_ci */ 67062306a36Sopenharmony_ci csr = tdc_read(tdc, TEGRA_GPCDMA_CHAN_CSR); 67162306a36Sopenharmony_ci csr &= ~(TEGRA_GPCDMA_CSR_REQ_SEL_MASK); 67262306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_REQ_SEL_UNUSED; 67362306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_CSR, csr); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci /* Wait for in flight data transfer to finish */ 67662306a36Sopenharmony_ci udelay(TEGRA_GPCDMA_BURST_COMPLETE_TIME); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci /* If TX/RX path is still active wait till it becomes 67962306a36Sopenharmony_ci * inactive 68062306a36Sopenharmony_ci */ 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci ret = readl_relaxed_poll_timeout_atomic(tdc->tdma->base_addr + 68362306a36Sopenharmony_ci tdc->chan_base_offset + 68462306a36Sopenharmony_ci TEGRA_GPCDMA_CHAN_STATUS, 68562306a36Sopenharmony_ci status, 68662306a36Sopenharmony_ci !(status & (TEGRA_GPCDMA_STATUS_CHANNEL_TX | 68762306a36Sopenharmony_ci TEGRA_GPCDMA_STATUS_CHANNEL_RX)), 68862306a36Sopenharmony_ci 5, 68962306a36Sopenharmony_ci TEGRA_GPCDMA_BURST_COMPLETION_TIMEOUT); 69062306a36Sopenharmony_ci if (ret) { 69162306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "Timeout waiting for DMA burst completion!\n"); 69262306a36Sopenharmony_ci tegra_dma_dump_chan_regs(tdc); 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return ret; 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_cistatic int tegra_dma_terminate_all(struct dma_chan *dc) 69962306a36Sopenharmony_ci{ 70062306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 70162306a36Sopenharmony_ci unsigned long flags; 70262306a36Sopenharmony_ci LIST_HEAD(head); 70362306a36Sopenharmony_ci int err; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci spin_lock_irqsave(&tdc->vc.lock, flags); 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci if (tdc->dma_desc) { 70862306a36Sopenharmony_ci err = tdc->tdma->chip_data->terminate(tdc); 70962306a36Sopenharmony_ci if (err) { 71062306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 71162306a36Sopenharmony_ci return err; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci vchan_terminate_vdesc(&tdc->dma_desc->vd); 71562306a36Sopenharmony_ci tegra_dma_disable(tdc); 71662306a36Sopenharmony_ci tdc->dma_desc = NULL; 71762306a36Sopenharmony_ci } 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci tegra_dma_sid_free(tdc); 72062306a36Sopenharmony_ci vchan_get_all_descriptors(&tdc->vc, &head); 72162306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci vchan_dma_desc_free_list(&tdc->vc, &head); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci return 0; 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_cistatic int tegra_dma_get_residual(struct tegra_dma_channel *tdc) 72962306a36Sopenharmony_ci{ 73062306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc = tdc->dma_desc; 73162306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req = dma_desc->sg_req; 73262306a36Sopenharmony_ci unsigned int bytes_xfer, residual; 73362306a36Sopenharmony_ci u32 wcount = 0, status; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci wcount = tdc_read(tdc, TEGRA_GPCDMA_CHAN_XFER_COUNT); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* 73862306a36Sopenharmony_ci * Set wcount = 0 if EOC bit is set. The transfer would have 73962306a36Sopenharmony_ci * already completed and the CHAN_XFER_COUNT could have updated 74062306a36Sopenharmony_ci * for the next transfer, specifically in case of cyclic transfers. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_ci status = tdc_read(tdc, TEGRA_GPCDMA_CHAN_STATUS); 74362306a36Sopenharmony_ci if (status & TEGRA_GPCDMA_STATUS_ISE_EOC) 74462306a36Sopenharmony_ci wcount = 0; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci bytes_xfer = dma_desc->bytes_xfer + 74762306a36Sopenharmony_ci sg_req[dma_desc->sg_idx].len - (wcount * 4); 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci residual = dma_desc->bytes_req - (bytes_xfer % dma_desc->bytes_req); 75062306a36Sopenharmony_ci 75162306a36Sopenharmony_ci return residual; 75262306a36Sopenharmony_ci} 75362306a36Sopenharmony_ci 75462306a36Sopenharmony_cistatic enum dma_status tegra_dma_tx_status(struct dma_chan *dc, 75562306a36Sopenharmony_ci dma_cookie_t cookie, 75662306a36Sopenharmony_ci struct dma_tx_state *txstate) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 75962306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 76062306a36Sopenharmony_ci struct virt_dma_desc *vd; 76162306a36Sopenharmony_ci unsigned int residual; 76262306a36Sopenharmony_ci unsigned long flags; 76362306a36Sopenharmony_ci enum dma_status ret; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci ret = dma_cookie_status(dc, cookie, txstate); 76662306a36Sopenharmony_ci if (ret == DMA_COMPLETE) 76762306a36Sopenharmony_ci return ret; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci spin_lock_irqsave(&tdc->vc.lock, flags); 77062306a36Sopenharmony_ci vd = vchan_find_desc(&tdc->vc, cookie); 77162306a36Sopenharmony_ci if (vd) { 77262306a36Sopenharmony_ci dma_desc = vd_to_tegra_dma_desc(vd); 77362306a36Sopenharmony_ci residual = dma_desc->bytes_req; 77462306a36Sopenharmony_ci dma_set_residue(txstate, residual); 77562306a36Sopenharmony_ci } else if (tdc->dma_desc && tdc->dma_desc->vd.tx.cookie == cookie) { 77662306a36Sopenharmony_ci residual = tegra_dma_get_residual(tdc); 77762306a36Sopenharmony_ci dma_set_residue(txstate, residual); 77862306a36Sopenharmony_ci } else { 77962306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "cookie %d is not found\n", cookie); 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci spin_unlock_irqrestore(&tdc->vc.lock, flags); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci return ret; 78462306a36Sopenharmony_ci} 78562306a36Sopenharmony_ci 78662306a36Sopenharmony_cistatic inline int get_bus_width(struct tegra_dma_channel *tdc, 78762306a36Sopenharmony_ci enum dma_slave_buswidth slave_bw) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci switch (slave_bw) { 79062306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_1_BYTE: 79162306a36Sopenharmony_ci return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_8; 79262306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_2_BYTES: 79362306a36Sopenharmony_ci return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_16; 79462306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_4_BYTES: 79562306a36Sopenharmony_ci return TEGRA_GPCDMA_MMIOSEQ_BUS_WIDTH_32; 79662306a36Sopenharmony_ci default: 79762306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "given slave bus width is not supported\n"); 79862306a36Sopenharmony_ci return -EINVAL; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_cistatic unsigned int get_burst_size(struct tegra_dma_channel *tdc, 80362306a36Sopenharmony_ci u32 burst_size, enum dma_slave_buswidth slave_bw, 80462306a36Sopenharmony_ci int len) 80562306a36Sopenharmony_ci{ 80662306a36Sopenharmony_ci unsigned int burst_mmio_width, burst_byte; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci /* 80962306a36Sopenharmony_ci * burst_size from client is in terms of the bus_width. 81062306a36Sopenharmony_ci * convert that into words. 81162306a36Sopenharmony_ci * If burst_size is not specified from client, then use 81262306a36Sopenharmony_ci * len to calculate the optimum burst size 81362306a36Sopenharmony_ci */ 81462306a36Sopenharmony_ci burst_byte = burst_size ? burst_size * slave_bw : len; 81562306a36Sopenharmony_ci burst_mmio_width = burst_byte / 4; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci if (burst_mmio_width < TEGRA_GPCDMA_MMIOSEQ_BURST_MIN) 81862306a36Sopenharmony_ci return 0; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci burst_mmio_width = min(burst_mmio_width, TEGRA_GPCDMA_MMIOSEQ_BURST_MAX); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci return TEGRA_GPCDMA_MMIOSEQ_BURST(burst_mmio_width); 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_cistatic int get_transfer_param(struct tegra_dma_channel *tdc, 82662306a36Sopenharmony_ci enum dma_transfer_direction direction, 82762306a36Sopenharmony_ci u32 *apb_addr, 82862306a36Sopenharmony_ci u32 *mmio_seq, 82962306a36Sopenharmony_ci u32 *csr, 83062306a36Sopenharmony_ci unsigned int *burst_size, 83162306a36Sopenharmony_ci enum dma_slave_buswidth *slave_bw) 83262306a36Sopenharmony_ci{ 83362306a36Sopenharmony_ci switch (direction) { 83462306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 83562306a36Sopenharmony_ci *apb_addr = tdc->dma_sconfig.dst_addr; 83662306a36Sopenharmony_ci *mmio_seq = get_bus_width(tdc, tdc->dma_sconfig.dst_addr_width); 83762306a36Sopenharmony_ci *burst_size = tdc->dma_sconfig.dst_maxburst; 83862306a36Sopenharmony_ci *slave_bw = tdc->dma_sconfig.dst_addr_width; 83962306a36Sopenharmony_ci *csr = TEGRA_GPCDMA_CSR_DMA_MEM2IO_FC; 84062306a36Sopenharmony_ci return 0; 84162306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 84262306a36Sopenharmony_ci *apb_addr = tdc->dma_sconfig.src_addr; 84362306a36Sopenharmony_ci *mmio_seq = get_bus_width(tdc, tdc->dma_sconfig.src_addr_width); 84462306a36Sopenharmony_ci *burst_size = tdc->dma_sconfig.src_maxburst; 84562306a36Sopenharmony_ci *slave_bw = tdc->dma_sconfig.src_addr_width; 84662306a36Sopenharmony_ci *csr = TEGRA_GPCDMA_CSR_DMA_IO2MEM_FC; 84762306a36Sopenharmony_ci return 0; 84862306a36Sopenharmony_ci default: 84962306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "DMA direction is not supported\n"); 85062306a36Sopenharmony_ci } 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci return -EINVAL; 85362306a36Sopenharmony_ci} 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 85662306a36Sopenharmony_citegra_dma_prep_dma_memset(struct dma_chan *dc, dma_addr_t dest, int value, 85762306a36Sopenharmony_ci size_t len, unsigned long flags) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 86062306a36Sopenharmony_ci unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count; 86162306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req; 86262306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 86362306a36Sopenharmony_ci u32 csr, mc_seq; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci if ((len & 3) || (dest & 3) || len > max_dma_count) { 86662306a36Sopenharmony_ci dev_err(tdc2dev(tdc), 86762306a36Sopenharmony_ci "DMA length/memory address is not supported\n"); 86862306a36Sopenharmony_ci return NULL; 86962306a36Sopenharmony_ci } 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* Set DMA mode to fixed pattern */ 87262306a36Sopenharmony_ci csr = TEGRA_GPCDMA_CSR_DMA_FIXED_PAT; 87362306a36Sopenharmony_ci /* Enable once or continuous mode */ 87462306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_ONCE; 87562306a36Sopenharmony_ci /* Enable IRQ mask */ 87662306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IRQ_MASK; 87762306a36Sopenharmony_ci /* Enable the DMA interrupt */ 87862306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 87962306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IE_EOC; 88062306a36Sopenharmony_ci /* Configure default priority weight for the channel */ 88162306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); 88262306a36Sopenharmony_ci 88362306a36Sopenharmony_ci mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); 88462306a36Sopenharmony_ci /* retain stream-id and clean rest */ 88562306a36Sopenharmony_ci mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; 88662306a36Sopenharmony_ci 88762306a36Sopenharmony_ci /* Set the address wrapping */ 88862306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0, 88962306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 89062306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1, 89162306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci /* Program outstanding MC requests */ 89462306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1); 89562306a36Sopenharmony_ci /* Set burst size */ 89662306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci dma_desc = kzalloc(struct_size(dma_desc, sg_req, 1), GFP_NOWAIT); 89962306a36Sopenharmony_ci if (!dma_desc) 90062306a36Sopenharmony_ci return NULL; 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci dma_desc->bytes_req = len; 90362306a36Sopenharmony_ci dma_desc->sg_count = 1; 90462306a36Sopenharmony_ci sg_req = dma_desc->sg_req; 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci sg_req[0].ch_regs.src_ptr = 0; 90762306a36Sopenharmony_ci sg_req[0].ch_regs.dst_ptr = dest; 90862306a36Sopenharmony_ci sg_req[0].ch_regs.high_addr_ptr = 90962306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32)); 91062306a36Sopenharmony_ci sg_req[0].ch_regs.fixed_pattern = value; 91162306a36Sopenharmony_ci /* Word count reg takes value as (N +1) words */ 91262306a36Sopenharmony_ci sg_req[0].ch_regs.wcount = ((len - 4) >> 2); 91362306a36Sopenharmony_ci sg_req[0].ch_regs.csr = csr; 91462306a36Sopenharmony_ci sg_req[0].ch_regs.mmio_seq = 0; 91562306a36Sopenharmony_ci sg_req[0].ch_regs.mc_seq = mc_seq; 91662306a36Sopenharmony_ci sg_req[0].len = len; 91762306a36Sopenharmony_ci 91862306a36Sopenharmony_ci dma_desc->cyclic = false; 91962306a36Sopenharmony_ci return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags); 92062306a36Sopenharmony_ci} 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 92362306a36Sopenharmony_citegra_dma_prep_dma_memcpy(struct dma_chan *dc, dma_addr_t dest, 92462306a36Sopenharmony_ci dma_addr_t src, size_t len, unsigned long flags) 92562306a36Sopenharmony_ci{ 92662306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 92762306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req; 92862306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 92962306a36Sopenharmony_ci unsigned int max_dma_count; 93062306a36Sopenharmony_ci u32 csr, mc_seq; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci max_dma_count = tdc->tdma->chip_data->max_dma_count; 93362306a36Sopenharmony_ci if ((len & 3) || (src & 3) || (dest & 3) || len > max_dma_count) { 93462306a36Sopenharmony_ci dev_err(tdc2dev(tdc), 93562306a36Sopenharmony_ci "DMA length/memory address is not supported\n"); 93662306a36Sopenharmony_ci return NULL; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* Set DMA mode to memory to memory transfer */ 94062306a36Sopenharmony_ci csr = TEGRA_GPCDMA_CSR_DMA_MEM2MEM; 94162306a36Sopenharmony_ci /* Enable once or continuous mode */ 94262306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_ONCE; 94362306a36Sopenharmony_ci /* Enable IRQ mask */ 94462306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IRQ_MASK; 94562306a36Sopenharmony_ci /* Enable the DMA interrupt */ 94662306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 94762306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IE_EOC; 94862306a36Sopenharmony_ci /* Configure default priority weight for the channel */ 94962306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_ci mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); 95262306a36Sopenharmony_ci /* retain stream-id and clean rest */ 95362306a36Sopenharmony_ci mc_seq &= (TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK) | 95462306a36Sopenharmony_ci (TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK); 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci /* Set the address wrapping */ 95762306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0, 95862306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 95962306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1, 96062306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci /* Program outstanding MC requests */ 96362306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1); 96462306a36Sopenharmony_ci /* Set burst size */ 96562306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16; 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci dma_desc = kzalloc(struct_size(dma_desc, sg_req, 1), GFP_NOWAIT); 96862306a36Sopenharmony_ci if (!dma_desc) 96962306a36Sopenharmony_ci return NULL; 97062306a36Sopenharmony_ci 97162306a36Sopenharmony_ci dma_desc->bytes_req = len; 97262306a36Sopenharmony_ci dma_desc->sg_count = 1; 97362306a36Sopenharmony_ci sg_req = dma_desc->sg_req; 97462306a36Sopenharmony_ci 97562306a36Sopenharmony_ci sg_req[0].ch_regs.src_ptr = src; 97662306a36Sopenharmony_ci sg_req[0].ch_regs.dst_ptr = dest; 97762306a36Sopenharmony_ci sg_req[0].ch_regs.high_addr_ptr = 97862306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (src >> 32)); 97962306a36Sopenharmony_ci sg_req[0].ch_regs.high_addr_ptr |= 98062306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (dest >> 32)); 98162306a36Sopenharmony_ci /* Word count reg takes value as (N +1) words */ 98262306a36Sopenharmony_ci sg_req[0].ch_regs.wcount = ((len - 4) >> 2); 98362306a36Sopenharmony_ci sg_req[0].ch_regs.csr = csr; 98462306a36Sopenharmony_ci sg_req[0].ch_regs.mmio_seq = 0; 98562306a36Sopenharmony_ci sg_req[0].ch_regs.mc_seq = mc_seq; 98662306a36Sopenharmony_ci sg_req[0].len = len; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci dma_desc->cyclic = false; 98962306a36Sopenharmony_ci return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags); 99062306a36Sopenharmony_ci} 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 99362306a36Sopenharmony_citegra_dma_prep_slave_sg(struct dma_chan *dc, struct scatterlist *sgl, 99462306a36Sopenharmony_ci unsigned int sg_len, enum dma_transfer_direction direction, 99562306a36Sopenharmony_ci unsigned long flags, void *context) 99662306a36Sopenharmony_ci{ 99762306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 99862306a36Sopenharmony_ci unsigned int max_dma_count = tdc->tdma->chip_data->max_dma_count; 99962306a36Sopenharmony_ci enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED; 100062306a36Sopenharmony_ci u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0; 100162306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req; 100262306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 100362306a36Sopenharmony_ci struct scatterlist *sg; 100462306a36Sopenharmony_ci u32 burst_size; 100562306a36Sopenharmony_ci unsigned int i; 100662306a36Sopenharmony_ci int ret; 100762306a36Sopenharmony_ci 100862306a36Sopenharmony_ci if (!tdc->config_init) { 100962306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "DMA channel is not configured\n"); 101062306a36Sopenharmony_ci return NULL; 101162306a36Sopenharmony_ci } 101262306a36Sopenharmony_ci if (sg_len < 1) { 101362306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "Invalid segment length %d\n", sg_len); 101462306a36Sopenharmony_ci return NULL; 101562306a36Sopenharmony_ci } 101662306a36Sopenharmony_ci 101762306a36Sopenharmony_ci ret = tegra_dma_sid_reserve(tdc, direction); 101862306a36Sopenharmony_ci if (ret) 101962306a36Sopenharmony_ci return NULL; 102062306a36Sopenharmony_ci 102162306a36Sopenharmony_ci ret = get_transfer_param(tdc, direction, &apb_ptr, &mmio_seq, &csr, 102262306a36Sopenharmony_ci &burst_size, &slave_bw); 102362306a36Sopenharmony_ci if (ret < 0) 102462306a36Sopenharmony_ci return NULL; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci /* Enable once or continuous mode */ 102762306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_ONCE; 102862306a36Sopenharmony_ci /* Program the slave id in requestor select */ 102962306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, tdc->slave_id); 103062306a36Sopenharmony_ci /* Enable IRQ mask */ 103162306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IRQ_MASK; 103262306a36Sopenharmony_ci /* Configure default priority weight for the channel*/ 103362306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci /* Enable the DMA interrupt */ 103662306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 103762306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IE_EOC; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); 104062306a36Sopenharmony_ci /* retain stream-id and clean rest */ 104162306a36Sopenharmony_ci mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* Set the address wrapping on both MC and MMIO side */ 104462306a36Sopenharmony_ci 104562306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0, 104662306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 104762306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1, 104862306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 104962306a36Sopenharmony_ci mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1); 105062306a36Sopenharmony_ci 105162306a36Sopenharmony_ci /* Program 2 MC outstanding requests by default. */ 105262306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci /* Setting MC burst size depending on MMIO burst size */ 105562306a36Sopenharmony_ci if (burst_size == 64) 105662306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16; 105762306a36Sopenharmony_ci else 105862306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_2; 105962306a36Sopenharmony_ci 106062306a36Sopenharmony_ci dma_desc = kzalloc(struct_size(dma_desc, sg_req, sg_len), GFP_NOWAIT); 106162306a36Sopenharmony_ci if (!dma_desc) 106262306a36Sopenharmony_ci return NULL; 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci dma_desc->sg_count = sg_len; 106562306a36Sopenharmony_ci sg_req = dma_desc->sg_req; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci /* Make transfer requests */ 106862306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 106962306a36Sopenharmony_ci u32 len; 107062306a36Sopenharmony_ci dma_addr_t mem; 107162306a36Sopenharmony_ci 107262306a36Sopenharmony_ci mem = sg_dma_address(sg); 107362306a36Sopenharmony_ci len = sg_dma_len(sg); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci if ((len & 3) || (mem & 3) || len > max_dma_count) { 107662306a36Sopenharmony_ci dev_err(tdc2dev(tdc), 107762306a36Sopenharmony_ci "DMA length/memory address is not supported\n"); 107862306a36Sopenharmony_ci kfree(dma_desc); 107962306a36Sopenharmony_ci return NULL; 108062306a36Sopenharmony_ci } 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len); 108362306a36Sopenharmony_ci dma_desc->bytes_req += len; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci if (direction == DMA_MEM_TO_DEV) { 108662306a36Sopenharmony_ci sg_req[i].ch_regs.src_ptr = mem; 108762306a36Sopenharmony_ci sg_req[i].ch_regs.dst_ptr = apb_ptr; 108862306a36Sopenharmony_ci sg_req[i].ch_regs.high_addr_ptr = 108962306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32)); 109062306a36Sopenharmony_ci } else if (direction == DMA_DEV_TO_MEM) { 109162306a36Sopenharmony_ci sg_req[i].ch_regs.src_ptr = apb_ptr; 109262306a36Sopenharmony_ci sg_req[i].ch_regs.dst_ptr = mem; 109362306a36Sopenharmony_ci sg_req[i].ch_regs.high_addr_ptr = 109462306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32)); 109562306a36Sopenharmony_ci } 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci /* 109862306a36Sopenharmony_ci * Word count register takes input in words. Writing a value 109962306a36Sopenharmony_ci * of N into word count register means a req of (N+1) words. 110062306a36Sopenharmony_ci */ 110162306a36Sopenharmony_ci sg_req[i].ch_regs.wcount = ((len - 4) >> 2); 110262306a36Sopenharmony_ci sg_req[i].ch_regs.csr = csr; 110362306a36Sopenharmony_ci sg_req[i].ch_regs.mmio_seq = mmio_seq; 110462306a36Sopenharmony_ci sg_req[i].ch_regs.mc_seq = mc_seq; 110562306a36Sopenharmony_ci sg_req[i].len = len; 110662306a36Sopenharmony_ci } 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci dma_desc->cyclic = false; 110962306a36Sopenharmony_ci return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags); 111062306a36Sopenharmony_ci} 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 111362306a36Sopenharmony_citegra_dma_prep_dma_cyclic(struct dma_chan *dc, dma_addr_t buf_addr, size_t buf_len, 111462306a36Sopenharmony_ci size_t period_len, enum dma_transfer_direction direction, 111562306a36Sopenharmony_ci unsigned long flags) 111662306a36Sopenharmony_ci{ 111762306a36Sopenharmony_ci enum dma_slave_buswidth slave_bw = DMA_SLAVE_BUSWIDTH_UNDEFINED; 111862306a36Sopenharmony_ci u32 csr, mc_seq, apb_ptr = 0, mmio_seq = 0, burst_size; 111962306a36Sopenharmony_ci unsigned int max_dma_count, len, period_count, i; 112062306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 112162306a36Sopenharmony_ci struct tegra_dma_desc *dma_desc; 112262306a36Sopenharmony_ci struct tegra_dma_sg_req *sg_req; 112362306a36Sopenharmony_ci dma_addr_t mem = buf_addr; 112462306a36Sopenharmony_ci int ret; 112562306a36Sopenharmony_ci 112662306a36Sopenharmony_ci if (!buf_len || !period_len) { 112762306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "Invalid buffer/period len\n"); 112862306a36Sopenharmony_ci return NULL; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (!tdc->config_init) { 113262306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "DMA slave is not configured\n"); 113362306a36Sopenharmony_ci return NULL; 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci ret = tegra_dma_sid_reserve(tdc, direction); 113762306a36Sopenharmony_ci if (ret) 113862306a36Sopenharmony_ci return NULL; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci /* 114162306a36Sopenharmony_ci * We only support cycle transfer when buf_len is multiple of 114262306a36Sopenharmony_ci * period_len. 114362306a36Sopenharmony_ci */ 114462306a36Sopenharmony_ci if (buf_len % period_len) { 114562306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "buf_len is not multiple of period_len\n"); 114662306a36Sopenharmony_ci return NULL; 114762306a36Sopenharmony_ci } 114862306a36Sopenharmony_ci 114962306a36Sopenharmony_ci len = period_len; 115062306a36Sopenharmony_ci max_dma_count = tdc->tdma->chip_data->max_dma_count; 115162306a36Sopenharmony_ci if ((len & 3) || (buf_addr & 3) || len > max_dma_count) { 115262306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "Req len/mem address is not correct\n"); 115362306a36Sopenharmony_ci return NULL; 115462306a36Sopenharmony_ci } 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_ci ret = get_transfer_param(tdc, direction, &apb_ptr, &mmio_seq, &csr, 115762306a36Sopenharmony_ci &burst_size, &slave_bw); 115862306a36Sopenharmony_ci if (ret < 0) 115962306a36Sopenharmony_ci return NULL; 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci /* Enable once or continuous mode */ 116262306a36Sopenharmony_ci csr &= ~TEGRA_GPCDMA_CSR_ONCE; 116362306a36Sopenharmony_ci /* Program the slave id in requestor select */ 116462306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_REQ_SEL_MASK, tdc->slave_id); 116562306a36Sopenharmony_ci /* Enable IRQ mask */ 116662306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IRQ_MASK; 116762306a36Sopenharmony_ci /* Configure default priority weight for the channel*/ 116862306a36Sopenharmony_ci csr |= FIELD_PREP(TEGRA_GPCDMA_CSR_WEIGHT, 1); 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci /* Enable the DMA interrupt */ 117162306a36Sopenharmony_ci if (flags & DMA_PREP_INTERRUPT) 117262306a36Sopenharmony_ci csr |= TEGRA_GPCDMA_CSR_IE_EOC; 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci mmio_seq |= FIELD_PREP(TEGRA_GPCDMA_MMIOSEQ_WRAP_WORD, 1); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci mc_seq = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); 117762306a36Sopenharmony_ci /* retain stream-id and clean rest */ 117862306a36Sopenharmony_ci mc_seq &= TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK; 117962306a36Sopenharmony_ci 118062306a36Sopenharmony_ci /* Set the address wrapping on both MC and MMIO side */ 118162306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP0, 118262306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 118362306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_WRAP1, 118462306a36Sopenharmony_ci TEGRA_GPCDMA_MCSEQ_WRAP_NONE); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* Program 2 MC outstanding requests by default. */ 118762306a36Sopenharmony_ci mc_seq |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_REQ_COUNT, 1); 118862306a36Sopenharmony_ci /* Setting MC burst size depending on MMIO burst size */ 118962306a36Sopenharmony_ci if (burst_size == 64) 119062306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_16; 119162306a36Sopenharmony_ci else 119262306a36Sopenharmony_ci mc_seq |= TEGRA_GPCDMA_MCSEQ_BURST_2; 119362306a36Sopenharmony_ci 119462306a36Sopenharmony_ci period_count = buf_len / period_len; 119562306a36Sopenharmony_ci dma_desc = kzalloc(struct_size(dma_desc, sg_req, period_count), 119662306a36Sopenharmony_ci GFP_NOWAIT); 119762306a36Sopenharmony_ci if (!dma_desc) 119862306a36Sopenharmony_ci return NULL; 119962306a36Sopenharmony_ci 120062306a36Sopenharmony_ci dma_desc->bytes_req = buf_len; 120162306a36Sopenharmony_ci dma_desc->sg_count = period_count; 120262306a36Sopenharmony_ci sg_req = dma_desc->sg_req; 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci /* Split transfer equal to period size */ 120562306a36Sopenharmony_ci for (i = 0; i < period_count; i++) { 120662306a36Sopenharmony_ci mmio_seq |= get_burst_size(tdc, burst_size, slave_bw, len); 120762306a36Sopenharmony_ci if (direction == DMA_MEM_TO_DEV) { 120862306a36Sopenharmony_ci sg_req[i].ch_regs.src_ptr = mem; 120962306a36Sopenharmony_ci sg_req[i].ch_regs.dst_ptr = apb_ptr; 121062306a36Sopenharmony_ci sg_req[i].ch_regs.high_addr_ptr = 121162306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_SRC_PTR, (mem >> 32)); 121262306a36Sopenharmony_ci } else if (direction == DMA_DEV_TO_MEM) { 121362306a36Sopenharmony_ci sg_req[i].ch_regs.src_ptr = apb_ptr; 121462306a36Sopenharmony_ci sg_req[i].ch_regs.dst_ptr = mem; 121562306a36Sopenharmony_ci sg_req[i].ch_regs.high_addr_ptr = 121662306a36Sopenharmony_ci FIELD_PREP(TEGRA_GPCDMA_HIGH_ADDR_DST_PTR, (mem >> 32)); 121762306a36Sopenharmony_ci } 121862306a36Sopenharmony_ci /* 121962306a36Sopenharmony_ci * Word count register takes input in words. Writing a value 122062306a36Sopenharmony_ci * of N into word count register means a req of (N+1) words. 122162306a36Sopenharmony_ci */ 122262306a36Sopenharmony_ci sg_req[i].ch_regs.wcount = ((len - 4) >> 2); 122362306a36Sopenharmony_ci sg_req[i].ch_regs.csr = csr; 122462306a36Sopenharmony_ci sg_req[i].ch_regs.mmio_seq = mmio_seq; 122562306a36Sopenharmony_ci sg_req[i].ch_regs.mc_seq = mc_seq; 122662306a36Sopenharmony_ci sg_req[i].len = len; 122762306a36Sopenharmony_ci 122862306a36Sopenharmony_ci mem += len; 122962306a36Sopenharmony_ci } 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci dma_desc->cyclic = true; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci return vchan_tx_prep(&tdc->vc, &dma_desc->vd, flags); 123462306a36Sopenharmony_ci} 123562306a36Sopenharmony_ci 123662306a36Sopenharmony_cistatic int tegra_dma_alloc_chan_resources(struct dma_chan *dc) 123762306a36Sopenharmony_ci{ 123862306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 123962306a36Sopenharmony_ci int ret; 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci ret = request_irq(tdc->irq, tegra_dma_isr, 0, tdc->name, tdc); 124262306a36Sopenharmony_ci if (ret) { 124362306a36Sopenharmony_ci dev_err(tdc2dev(tdc), "request_irq failed for %s\n", tdc->name); 124462306a36Sopenharmony_ci return ret; 124562306a36Sopenharmony_ci } 124662306a36Sopenharmony_ci 124762306a36Sopenharmony_ci dma_cookie_init(&tdc->vc.chan); 124862306a36Sopenharmony_ci tdc->config_init = false; 124962306a36Sopenharmony_ci return 0; 125062306a36Sopenharmony_ci} 125162306a36Sopenharmony_ci 125262306a36Sopenharmony_cistatic void tegra_dma_chan_synchronize(struct dma_chan *dc) 125362306a36Sopenharmony_ci{ 125462306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci synchronize_irq(tdc->irq); 125762306a36Sopenharmony_ci vchan_synchronize(&tdc->vc); 125862306a36Sopenharmony_ci} 125962306a36Sopenharmony_ci 126062306a36Sopenharmony_cistatic void tegra_dma_free_chan_resources(struct dma_chan *dc) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci dev_dbg(tdc2dev(tdc), "Freeing channel %d\n", tdc->id); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci tegra_dma_terminate_all(dc); 126762306a36Sopenharmony_ci synchronize_irq(tdc->irq); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci tasklet_kill(&tdc->vc.task); 127062306a36Sopenharmony_ci tdc->config_init = false; 127162306a36Sopenharmony_ci tdc->slave_id = -1; 127262306a36Sopenharmony_ci tdc->sid_dir = DMA_TRANS_NONE; 127362306a36Sopenharmony_ci free_irq(tdc->irq, tdc); 127462306a36Sopenharmony_ci 127562306a36Sopenharmony_ci vchan_free_chan_resources(&tdc->vc); 127662306a36Sopenharmony_ci} 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_cistatic struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec, 127962306a36Sopenharmony_ci struct of_dma *ofdma) 128062306a36Sopenharmony_ci{ 128162306a36Sopenharmony_ci struct tegra_dma *tdma = ofdma->of_dma_data; 128262306a36Sopenharmony_ci struct tegra_dma_channel *tdc; 128362306a36Sopenharmony_ci struct dma_chan *chan; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci chan = dma_get_any_slave_channel(&tdma->dma_dev); 128662306a36Sopenharmony_ci if (!chan) 128762306a36Sopenharmony_ci return NULL; 128862306a36Sopenharmony_ci 128962306a36Sopenharmony_ci tdc = to_tegra_dma_chan(chan); 129062306a36Sopenharmony_ci tdc->slave_id = dma_spec->args[0]; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci return chan; 129362306a36Sopenharmony_ci} 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra186_dma_chip_data = { 129662306a36Sopenharmony_ci .nr_channels = 32, 129762306a36Sopenharmony_ci .channel_reg_size = SZ_64K, 129862306a36Sopenharmony_ci .max_dma_count = SZ_1G, 129962306a36Sopenharmony_ci .hw_support_pause = false, 130062306a36Sopenharmony_ci .terminate = tegra_dma_stop_client, 130162306a36Sopenharmony_ci}; 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra194_dma_chip_data = { 130462306a36Sopenharmony_ci .nr_channels = 32, 130562306a36Sopenharmony_ci .channel_reg_size = SZ_64K, 130662306a36Sopenharmony_ci .max_dma_count = SZ_1G, 130762306a36Sopenharmony_ci .hw_support_pause = true, 130862306a36Sopenharmony_ci .terminate = tegra_dma_pause, 130962306a36Sopenharmony_ci}; 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic const struct tegra_dma_chip_data tegra234_dma_chip_data = { 131262306a36Sopenharmony_ci .nr_channels = 32, 131362306a36Sopenharmony_ci .channel_reg_size = SZ_64K, 131462306a36Sopenharmony_ci .max_dma_count = SZ_1G, 131562306a36Sopenharmony_ci .hw_support_pause = true, 131662306a36Sopenharmony_ci .terminate = tegra_dma_pause_noerr, 131762306a36Sopenharmony_ci}; 131862306a36Sopenharmony_ci 131962306a36Sopenharmony_cistatic const struct of_device_id tegra_dma_of_match[] = { 132062306a36Sopenharmony_ci { 132162306a36Sopenharmony_ci .compatible = "nvidia,tegra186-gpcdma", 132262306a36Sopenharmony_ci .data = &tegra186_dma_chip_data, 132362306a36Sopenharmony_ci }, { 132462306a36Sopenharmony_ci .compatible = "nvidia,tegra194-gpcdma", 132562306a36Sopenharmony_ci .data = &tegra194_dma_chip_data, 132662306a36Sopenharmony_ci }, { 132762306a36Sopenharmony_ci .compatible = "nvidia,tegra234-gpcdma", 132862306a36Sopenharmony_ci .data = &tegra234_dma_chip_data, 132962306a36Sopenharmony_ci }, { 133062306a36Sopenharmony_ci }, 133162306a36Sopenharmony_ci}; 133262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, tegra_dma_of_match); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_cistatic int tegra_dma_program_sid(struct tegra_dma_channel *tdc, int stream_id) 133562306a36Sopenharmony_ci{ 133662306a36Sopenharmony_ci unsigned int reg_val = tdc_read(tdc, TEGRA_GPCDMA_CHAN_MCSEQ); 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK); 133962306a36Sopenharmony_ci reg_val &= ~(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID0_MASK, stream_id); 134262306a36Sopenharmony_ci reg_val |= FIELD_PREP(TEGRA_GPCDMA_MCSEQ_STREAM_ID1_MASK, stream_id); 134362306a36Sopenharmony_ci 134462306a36Sopenharmony_ci tdc_write(tdc, TEGRA_GPCDMA_CHAN_MCSEQ, reg_val); 134562306a36Sopenharmony_ci return 0; 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic int tegra_dma_probe(struct platform_device *pdev) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci const struct tegra_dma_chip_data *cdata = NULL; 135162306a36Sopenharmony_ci struct iommu_fwspec *iommu_spec; 135262306a36Sopenharmony_ci unsigned int stream_id, i; 135362306a36Sopenharmony_ci struct tegra_dma *tdma; 135462306a36Sopenharmony_ci int ret; 135562306a36Sopenharmony_ci 135662306a36Sopenharmony_ci cdata = of_device_get_match_data(&pdev->dev); 135762306a36Sopenharmony_ci 135862306a36Sopenharmony_ci tdma = devm_kzalloc(&pdev->dev, 135962306a36Sopenharmony_ci struct_size(tdma, channels, cdata->nr_channels), 136062306a36Sopenharmony_ci GFP_KERNEL); 136162306a36Sopenharmony_ci if (!tdma) 136262306a36Sopenharmony_ci return -ENOMEM; 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci tdma->dev = &pdev->dev; 136562306a36Sopenharmony_ci tdma->chip_data = cdata; 136662306a36Sopenharmony_ci platform_set_drvdata(pdev, tdma); 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci tdma->base_addr = devm_platform_ioremap_resource(pdev, 0); 136962306a36Sopenharmony_ci if (IS_ERR(tdma->base_addr)) 137062306a36Sopenharmony_ci return PTR_ERR(tdma->base_addr); 137162306a36Sopenharmony_ci 137262306a36Sopenharmony_ci tdma->rst = devm_reset_control_get_exclusive(&pdev->dev, "gpcdma"); 137362306a36Sopenharmony_ci if (IS_ERR(tdma->rst)) { 137462306a36Sopenharmony_ci return dev_err_probe(&pdev->dev, PTR_ERR(tdma->rst), 137562306a36Sopenharmony_ci "Missing controller reset\n"); 137662306a36Sopenharmony_ci } 137762306a36Sopenharmony_ci reset_control_reset(tdma->rst); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci tdma->dma_dev.dev = &pdev->dev; 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci iommu_spec = dev_iommu_fwspec_get(&pdev->dev); 138262306a36Sopenharmony_ci if (!iommu_spec) { 138362306a36Sopenharmony_ci dev_err(&pdev->dev, "Missing iommu stream-id\n"); 138462306a36Sopenharmony_ci return -EINVAL; 138562306a36Sopenharmony_ci } 138662306a36Sopenharmony_ci stream_id = iommu_spec->ids[0] & 0xffff; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci ret = device_property_read_u32(&pdev->dev, "dma-channel-mask", 138962306a36Sopenharmony_ci &tdma->chan_mask); 139062306a36Sopenharmony_ci if (ret) { 139162306a36Sopenharmony_ci dev_warn(&pdev->dev, 139262306a36Sopenharmony_ci "Missing dma-channel-mask property, using default channel mask %#x\n", 139362306a36Sopenharmony_ci TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK); 139462306a36Sopenharmony_ci tdma->chan_mask = TEGRA_GPCDMA_DEFAULT_CHANNEL_MASK; 139562306a36Sopenharmony_ci } 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci INIT_LIST_HEAD(&tdma->dma_dev.channels); 139862306a36Sopenharmony_ci for (i = 0; i < cdata->nr_channels; i++) { 139962306a36Sopenharmony_ci struct tegra_dma_channel *tdc = &tdma->channels[i]; 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci /* Check for channel mask */ 140262306a36Sopenharmony_ci if (!(tdma->chan_mask & BIT(i))) 140362306a36Sopenharmony_ci continue; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci tdc->irq = platform_get_irq(pdev, i); 140662306a36Sopenharmony_ci if (tdc->irq < 0) 140762306a36Sopenharmony_ci return tdc->irq; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci tdc->chan_base_offset = TEGRA_GPCDMA_CHANNEL_BASE_ADDR_OFFSET + 141062306a36Sopenharmony_ci i * cdata->channel_reg_size; 141162306a36Sopenharmony_ci snprintf(tdc->name, sizeof(tdc->name), "gpcdma.%d", i); 141262306a36Sopenharmony_ci tdc->tdma = tdma; 141362306a36Sopenharmony_ci tdc->id = i; 141462306a36Sopenharmony_ci tdc->slave_id = -1; 141562306a36Sopenharmony_ci 141662306a36Sopenharmony_ci vchan_init(&tdc->vc, &tdma->dma_dev); 141762306a36Sopenharmony_ci tdc->vc.desc_free = tegra_dma_desc_free; 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci /* program stream-id for this channel */ 142062306a36Sopenharmony_ci tegra_dma_program_sid(tdc, stream_id); 142162306a36Sopenharmony_ci tdc->stream_id = stream_id; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, tdma->dma_dev.cap_mask); 142562306a36Sopenharmony_ci dma_cap_set(DMA_PRIVATE, tdma->dma_dev.cap_mask); 142662306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, tdma->dma_dev.cap_mask); 142762306a36Sopenharmony_ci dma_cap_set(DMA_MEMSET, tdma->dma_dev.cap_mask); 142862306a36Sopenharmony_ci dma_cap_set(DMA_CYCLIC, tdma->dma_dev.cap_mask); 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_ci /* 143162306a36Sopenharmony_ci * Only word aligned transfers are supported. Set the copy 143262306a36Sopenharmony_ci * alignment shift. 143362306a36Sopenharmony_ci */ 143462306a36Sopenharmony_ci tdma->dma_dev.copy_align = 2; 143562306a36Sopenharmony_ci tdma->dma_dev.fill_align = 2; 143662306a36Sopenharmony_ci tdma->dma_dev.device_alloc_chan_resources = 143762306a36Sopenharmony_ci tegra_dma_alloc_chan_resources; 143862306a36Sopenharmony_ci tdma->dma_dev.device_free_chan_resources = 143962306a36Sopenharmony_ci tegra_dma_free_chan_resources; 144062306a36Sopenharmony_ci tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg; 144162306a36Sopenharmony_ci tdma->dma_dev.device_prep_dma_memcpy = tegra_dma_prep_dma_memcpy; 144262306a36Sopenharmony_ci tdma->dma_dev.device_prep_dma_memset = tegra_dma_prep_dma_memset; 144362306a36Sopenharmony_ci tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic; 144462306a36Sopenharmony_ci tdma->dma_dev.device_config = tegra_dma_slave_config; 144562306a36Sopenharmony_ci tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all; 144662306a36Sopenharmony_ci tdma->dma_dev.device_tx_status = tegra_dma_tx_status; 144762306a36Sopenharmony_ci tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending; 144862306a36Sopenharmony_ci tdma->dma_dev.device_pause = tegra_dma_device_pause; 144962306a36Sopenharmony_ci tdma->dma_dev.device_resume = tegra_dma_device_resume; 145062306a36Sopenharmony_ci tdma->dma_dev.device_synchronize = tegra_dma_chan_synchronize; 145162306a36Sopenharmony_ci tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci ret = dma_async_device_register(&tdma->dma_dev); 145462306a36Sopenharmony_ci if (ret < 0) { 145562306a36Sopenharmony_ci dev_err_probe(&pdev->dev, ret, 145662306a36Sopenharmony_ci "GPC DMA driver registration failed\n"); 145762306a36Sopenharmony_ci return ret; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci ret = of_dma_controller_register(pdev->dev.of_node, 146162306a36Sopenharmony_ci tegra_dma_of_xlate, tdma); 146262306a36Sopenharmony_ci if (ret < 0) { 146362306a36Sopenharmony_ci dev_err_probe(&pdev->dev, ret, 146462306a36Sopenharmony_ci "GPC DMA OF registration failed\n"); 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_ci dma_async_device_unregister(&tdma->dma_dev); 146762306a36Sopenharmony_ci return ret; 146862306a36Sopenharmony_ci } 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci dev_info(&pdev->dev, "GPC DMA driver register %lu channels\n", 147162306a36Sopenharmony_ci hweight_long(tdma->chan_mask)); 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cistatic int tegra_dma_remove(struct platform_device *pdev) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci struct tegra_dma *tdma = platform_get_drvdata(pdev); 147962306a36Sopenharmony_ci 148062306a36Sopenharmony_ci of_dma_controller_free(pdev->dev.of_node); 148162306a36Sopenharmony_ci dma_async_device_unregister(&tdma->dma_dev); 148262306a36Sopenharmony_ci 148362306a36Sopenharmony_ci return 0; 148462306a36Sopenharmony_ci} 148562306a36Sopenharmony_ci 148662306a36Sopenharmony_cistatic int __maybe_unused tegra_dma_pm_suspend(struct device *dev) 148762306a36Sopenharmony_ci{ 148862306a36Sopenharmony_ci struct tegra_dma *tdma = dev_get_drvdata(dev); 148962306a36Sopenharmony_ci unsigned int i; 149062306a36Sopenharmony_ci 149162306a36Sopenharmony_ci for (i = 0; i < tdma->chip_data->nr_channels; i++) { 149262306a36Sopenharmony_ci struct tegra_dma_channel *tdc = &tdma->channels[i]; 149362306a36Sopenharmony_ci 149462306a36Sopenharmony_ci if (!(tdma->chan_mask & BIT(i))) 149562306a36Sopenharmony_ci continue; 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci if (tdc->dma_desc) { 149862306a36Sopenharmony_ci dev_err(tdma->dev, "channel %u busy\n", i); 149962306a36Sopenharmony_ci return -EBUSY; 150062306a36Sopenharmony_ci } 150162306a36Sopenharmony_ci } 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci return 0; 150462306a36Sopenharmony_ci} 150562306a36Sopenharmony_ci 150662306a36Sopenharmony_cistatic int __maybe_unused tegra_dma_pm_resume(struct device *dev) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci struct tegra_dma *tdma = dev_get_drvdata(dev); 150962306a36Sopenharmony_ci unsigned int i; 151062306a36Sopenharmony_ci 151162306a36Sopenharmony_ci reset_control_reset(tdma->rst); 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci for (i = 0; i < tdma->chip_data->nr_channels; i++) { 151462306a36Sopenharmony_ci struct tegra_dma_channel *tdc = &tdma->channels[i]; 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_ci if (!(tdma->chan_mask & BIT(i))) 151762306a36Sopenharmony_ci continue; 151862306a36Sopenharmony_ci 151962306a36Sopenharmony_ci tegra_dma_program_sid(tdc, tdc->stream_id); 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_ci return 0; 152362306a36Sopenharmony_ci} 152462306a36Sopenharmony_ci 152562306a36Sopenharmony_cistatic const struct dev_pm_ops tegra_dma_dev_pm_ops = { 152662306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(tegra_dma_pm_suspend, tegra_dma_pm_resume) 152762306a36Sopenharmony_ci}; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_cistatic struct platform_driver tegra_dma_driver = { 153062306a36Sopenharmony_ci .driver = { 153162306a36Sopenharmony_ci .name = "tegra-gpcdma", 153262306a36Sopenharmony_ci .pm = &tegra_dma_dev_pm_ops, 153362306a36Sopenharmony_ci .of_match_table = tegra_dma_of_match, 153462306a36Sopenharmony_ci }, 153562306a36Sopenharmony_ci .probe = tegra_dma_probe, 153662306a36Sopenharmony_ci .remove = tegra_dma_remove, 153762306a36Sopenharmony_ci}; 153862306a36Sopenharmony_ci 153962306a36Sopenharmony_cimodule_platform_driver(tegra_dma_driver); 154062306a36Sopenharmony_ci 154162306a36Sopenharmony_ciMODULE_DESCRIPTION("NVIDIA Tegra GPC DMA Controller driver"); 154262306a36Sopenharmony_ciMODULE_AUTHOR("Pavan Kunapuli <pkunapuli@nvidia.com>"); 154362306a36Sopenharmony_ciMODULE_AUTHOR("Rajesh Gumasta <rgumasta@nvidia.com>"); 154462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 1545