162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * TI EDMA DMA engine driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2012 Texas Instruments 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/dmaengine.h> 962306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1062306a36Sopenharmony_ci#include <linux/bitmap.h> 1162306a36Sopenharmony_ci#include <linux/err.h> 1262306a36Sopenharmony_ci#include <linux/init.h> 1362306a36Sopenharmony_ci#include <linux/interrupt.h> 1462306a36Sopenharmony_ci#include <linux/list.h> 1562306a36Sopenharmony_ci#include <linux/module.h> 1662306a36Sopenharmony_ci#include <linux/platform_device.h> 1762306a36Sopenharmony_ci#include <linux/slab.h> 1862306a36Sopenharmony_ci#include <linux/spinlock.h> 1962306a36Sopenharmony_ci#include <linux/of.h> 2062306a36Sopenharmony_ci#include <linux/of_dma.h> 2162306a36Sopenharmony_ci#include <linux/of_irq.h> 2262306a36Sopenharmony_ci#include <linux/of_address.h> 2362306a36Sopenharmony_ci#include <linux/pm_runtime.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include <linux/platform_data/edma.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "../dmaengine.h" 2862306a36Sopenharmony_ci#include "../virt-dma.h" 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Offsets matching "struct edmacc_param" */ 3162306a36Sopenharmony_ci#define PARM_OPT 0x00 3262306a36Sopenharmony_ci#define PARM_SRC 0x04 3362306a36Sopenharmony_ci#define PARM_A_B_CNT 0x08 3462306a36Sopenharmony_ci#define PARM_DST 0x0c 3562306a36Sopenharmony_ci#define PARM_SRC_DST_BIDX 0x10 3662306a36Sopenharmony_ci#define PARM_LINK_BCNTRLD 0x14 3762306a36Sopenharmony_ci#define PARM_SRC_DST_CIDX 0x18 3862306a36Sopenharmony_ci#define PARM_CCNT 0x1c 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#define PARM_SIZE 0x20 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci/* Offsets for EDMA CC global channel registers and their shadows */ 4362306a36Sopenharmony_ci#define SH_ER 0x00 /* 64 bits */ 4462306a36Sopenharmony_ci#define SH_ECR 0x08 /* 64 bits */ 4562306a36Sopenharmony_ci#define SH_ESR 0x10 /* 64 bits */ 4662306a36Sopenharmony_ci#define SH_CER 0x18 /* 64 bits */ 4762306a36Sopenharmony_ci#define SH_EER 0x20 /* 64 bits */ 4862306a36Sopenharmony_ci#define SH_EECR 0x28 /* 64 bits */ 4962306a36Sopenharmony_ci#define SH_EESR 0x30 /* 64 bits */ 5062306a36Sopenharmony_ci#define SH_SER 0x38 /* 64 bits */ 5162306a36Sopenharmony_ci#define SH_SECR 0x40 /* 64 bits */ 5262306a36Sopenharmony_ci#define SH_IER 0x50 /* 64 bits */ 5362306a36Sopenharmony_ci#define SH_IECR 0x58 /* 64 bits */ 5462306a36Sopenharmony_ci#define SH_IESR 0x60 /* 64 bits */ 5562306a36Sopenharmony_ci#define SH_IPR 0x68 /* 64 bits */ 5662306a36Sopenharmony_ci#define SH_ICR 0x70 /* 64 bits */ 5762306a36Sopenharmony_ci#define SH_IEVAL 0x78 5862306a36Sopenharmony_ci#define SH_QER 0x80 5962306a36Sopenharmony_ci#define SH_QEER 0x84 6062306a36Sopenharmony_ci#define SH_QEECR 0x88 6162306a36Sopenharmony_ci#define SH_QEESR 0x8c 6262306a36Sopenharmony_ci#define SH_QSER 0x90 6362306a36Sopenharmony_ci#define SH_QSECR 0x94 6462306a36Sopenharmony_ci#define SH_SIZE 0x200 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci/* Offsets for EDMA CC global registers */ 6762306a36Sopenharmony_ci#define EDMA_REV 0x0000 6862306a36Sopenharmony_ci#define EDMA_CCCFG 0x0004 6962306a36Sopenharmony_ci#define EDMA_QCHMAP 0x0200 /* 8 registers */ 7062306a36Sopenharmony_ci#define EDMA_DMAQNUM 0x0240 /* 8 registers (4 on OMAP-L1xx) */ 7162306a36Sopenharmony_ci#define EDMA_QDMAQNUM 0x0260 7262306a36Sopenharmony_ci#define EDMA_QUETCMAP 0x0280 7362306a36Sopenharmony_ci#define EDMA_QUEPRI 0x0284 7462306a36Sopenharmony_ci#define EDMA_EMR 0x0300 /* 64 bits */ 7562306a36Sopenharmony_ci#define EDMA_EMCR 0x0308 /* 64 bits */ 7662306a36Sopenharmony_ci#define EDMA_QEMR 0x0310 7762306a36Sopenharmony_ci#define EDMA_QEMCR 0x0314 7862306a36Sopenharmony_ci#define EDMA_CCERR 0x0318 7962306a36Sopenharmony_ci#define EDMA_CCERRCLR 0x031c 8062306a36Sopenharmony_ci#define EDMA_EEVAL 0x0320 8162306a36Sopenharmony_ci#define EDMA_DRAE 0x0340 /* 4 x 64 bits*/ 8262306a36Sopenharmony_ci#define EDMA_QRAE 0x0380 /* 4 registers */ 8362306a36Sopenharmony_ci#define EDMA_QUEEVTENTRY 0x0400 /* 2 x 16 registers */ 8462306a36Sopenharmony_ci#define EDMA_QSTAT 0x0600 /* 2 registers */ 8562306a36Sopenharmony_ci#define EDMA_QWMTHRA 0x0620 8662306a36Sopenharmony_ci#define EDMA_QWMTHRB 0x0624 8762306a36Sopenharmony_ci#define EDMA_CCSTAT 0x0640 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci#define EDMA_M 0x1000 /* global channel registers */ 9062306a36Sopenharmony_ci#define EDMA_ECR 0x1008 9162306a36Sopenharmony_ci#define EDMA_ECRH 0x100C 9262306a36Sopenharmony_ci#define EDMA_SHADOW0 0x2000 /* 4 shadow regions */ 9362306a36Sopenharmony_ci#define EDMA_PARM 0x4000 /* PaRAM entries */ 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci#define PARM_OFFSET(param_no) (EDMA_PARM + ((param_no) << 5)) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define EDMA_DCHMAP 0x0100 /* 64 registers */ 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* CCCFG register */ 10062306a36Sopenharmony_ci#define GET_NUM_DMACH(x) (x & 0x7) /* bits 0-2 */ 10162306a36Sopenharmony_ci#define GET_NUM_QDMACH(x) ((x & 0x70) >> 4) /* bits 4-6 */ 10262306a36Sopenharmony_ci#define GET_NUM_PAENTRY(x) ((x & 0x7000) >> 12) /* bits 12-14 */ 10362306a36Sopenharmony_ci#define GET_NUM_EVQUE(x) ((x & 0x70000) >> 16) /* bits 16-18 */ 10462306a36Sopenharmony_ci#define GET_NUM_REGN(x) ((x & 0x300000) >> 20) /* bits 20-21 */ 10562306a36Sopenharmony_ci#define CHMAP_EXIST BIT(24) 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci/* CCSTAT register */ 10862306a36Sopenharmony_ci#define EDMA_CCSTAT_ACTV BIT(4) 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci/* 11162306a36Sopenharmony_ci * Max of 20 segments per channel to conserve PaRAM slots 11262306a36Sopenharmony_ci * Also note that MAX_NR_SG should be at least the no.of periods 11362306a36Sopenharmony_ci * that are required for ASoC, otherwise DMA prep calls will 11462306a36Sopenharmony_ci * fail. Today davinci-pcm is the only user of this driver and 11562306a36Sopenharmony_ci * requires at least 17 slots, so we setup the default to 20. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci#define MAX_NR_SG 20 11862306a36Sopenharmony_ci#define EDMA_MAX_SLOTS MAX_NR_SG 11962306a36Sopenharmony_ci#define EDMA_DESCRIPTORS 16 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define EDMA_CHANNEL_ANY -1 /* for edma_alloc_channel() */ 12262306a36Sopenharmony_ci#define EDMA_SLOT_ANY -1 /* for edma_alloc_slot() */ 12362306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_ANY 1001 12462306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_FIXED_EXACT 1002 12562306a36Sopenharmony_ci#define EDMA_CONT_PARAMS_FIXED_NOT_EXACT 1003 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* 12862306a36Sopenharmony_ci * 64bit array registers are split into two 32bit registers: 12962306a36Sopenharmony_ci * reg0: channel/event 0-31 13062306a36Sopenharmony_ci * reg1: channel/event 32-63 13162306a36Sopenharmony_ci * 13262306a36Sopenharmony_ci * bit 5 in the channel number tells the array index (0/1) 13362306a36Sopenharmony_ci * bit 0-4 (0x1f) is the bit offset within the register 13462306a36Sopenharmony_ci */ 13562306a36Sopenharmony_ci#define EDMA_REG_ARRAY_INDEX(channel) ((channel) >> 5) 13662306a36Sopenharmony_ci#define EDMA_CHANNEL_BIT(channel) (BIT((channel) & 0x1f)) 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci/* PaRAM slots are laid out like this */ 13962306a36Sopenharmony_cistruct edmacc_param { 14062306a36Sopenharmony_ci u32 opt; 14162306a36Sopenharmony_ci u32 src; 14262306a36Sopenharmony_ci u32 a_b_cnt; 14362306a36Sopenharmony_ci u32 dst; 14462306a36Sopenharmony_ci u32 src_dst_bidx; 14562306a36Sopenharmony_ci u32 link_bcntrld; 14662306a36Sopenharmony_ci u32 src_dst_cidx; 14762306a36Sopenharmony_ci u32 ccnt; 14862306a36Sopenharmony_ci} __packed; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci/* fields in edmacc_param.opt */ 15162306a36Sopenharmony_ci#define SAM BIT(0) 15262306a36Sopenharmony_ci#define DAM BIT(1) 15362306a36Sopenharmony_ci#define SYNCDIM BIT(2) 15462306a36Sopenharmony_ci#define STATIC BIT(3) 15562306a36Sopenharmony_ci#define EDMA_FWID (0x07 << 8) 15662306a36Sopenharmony_ci#define TCCMODE BIT(11) 15762306a36Sopenharmony_ci#define EDMA_TCC(t) ((t) << 12) 15862306a36Sopenharmony_ci#define TCINTEN BIT(20) 15962306a36Sopenharmony_ci#define ITCINTEN BIT(21) 16062306a36Sopenharmony_ci#define TCCHEN BIT(22) 16162306a36Sopenharmony_ci#define ITCCHEN BIT(23) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct edma_pset { 16462306a36Sopenharmony_ci u32 len; 16562306a36Sopenharmony_ci dma_addr_t addr; 16662306a36Sopenharmony_ci struct edmacc_param param; 16762306a36Sopenharmony_ci}; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_cistruct edma_desc { 17062306a36Sopenharmony_ci struct virt_dma_desc vdesc; 17162306a36Sopenharmony_ci struct list_head node; 17262306a36Sopenharmony_ci enum dma_transfer_direction direction; 17362306a36Sopenharmony_ci int cyclic; 17462306a36Sopenharmony_ci bool polled; 17562306a36Sopenharmony_ci int absync; 17662306a36Sopenharmony_ci int pset_nr; 17762306a36Sopenharmony_ci struct edma_chan *echan; 17862306a36Sopenharmony_ci int processed; 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci /* 18162306a36Sopenharmony_ci * The following 4 elements are used for residue accounting. 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * - processed_stat: the number of SG elements we have traversed 18462306a36Sopenharmony_ci * so far to cover accounting. This is updated directly to processed 18562306a36Sopenharmony_ci * during edma_callback and is always <= processed, because processed 18662306a36Sopenharmony_ci * refers to the number of pending transfer (programmed to EDMA 18762306a36Sopenharmony_ci * controller), where as processed_stat tracks number of transfers 18862306a36Sopenharmony_ci * accounted for so far. 18962306a36Sopenharmony_ci * 19062306a36Sopenharmony_ci * - residue: The amount of bytes we have left to transfer for this desc 19162306a36Sopenharmony_ci * 19262306a36Sopenharmony_ci * - residue_stat: The residue in bytes of data we have covered 19362306a36Sopenharmony_ci * so far for accounting. This is updated directly to residue 19462306a36Sopenharmony_ci * during callbacks to keep it current. 19562306a36Sopenharmony_ci * 19662306a36Sopenharmony_ci * - sg_len: Tracks the length of the current intermediate transfer, 19762306a36Sopenharmony_ci * this is required to update the residue during intermediate transfer 19862306a36Sopenharmony_ci * completion callback. 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci int processed_stat; 20162306a36Sopenharmony_ci u32 sg_len; 20262306a36Sopenharmony_ci u32 residue; 20362306a36Sopenharmony_ci u32 residue_stat; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci struct edma_pset pset[]; 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistruct edma_cc; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_cistruct edma_tc { 21162306a36Sopenharmony_ci struct device_node *node; 21262306a36Sopenharmony_ci u16 id; 21362306a36Sopenharmony_ci}; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistruct edma_chan { 21662306a36Sopenharmony_ci struct virt_dma_chan vchan; 21762306a36Sopenharmony_ci struct list_head node; 21862306a36Sopenharmony_ci struct edma_desc *edesc; 21962306a36Sopenharmony_ci struct edma_cc *ecc; 22062306a36Sopenharmony_ci struct edma_tc *tc; 22162306a36Sopenharmony_ci int ch_num; 22262306a36Sopenharmony_ci bool alloced; 22362306a36Sopenharmony_ci bool hw_triggered; 22462306a36Sopenharmony_ci int slot[EDMA_MAX_SLOTS]; 22562306a36Sopenharmony_ci int missed; 22662306a36Sopenharmony_ci struct dma_slave_config cfg; 22762306a36Sopenharmony_ci}; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistruct edma_cc { 23062306a36Sopenharmony_ci struct device *dev; 23162306a36Sopenharmony_ci struct edma_soc_info *info; 23262306a36Sopenharmony_ci void __iomem *base; 23362306a36Sopenharmony_ci int id; 23462306a36Sopenharmony_ci bool legacy_mode; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci /* eDMA3 resource information */ 23762306a36Sopenharmony_ci unsigned num_channels; 23862306a36Sopenharmony_ci unsigned num_qchannels; 23962306a36Sopenharmony_ci unsigned num_region; 24062306a36Sopenharmony_ci unsigned num_slots; 24162306a36Sopenharmony_ci unsigned num_tc; 24262306a36Sopenharmony_ci bool chmap_exist; 24362306a36Sopenharmony_ci enum dma_event_q default_queue; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci unsigned int ccint; 24662306a36Sopenharmony_ci unsigned int ccerrint; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * The slot_inuse bit for each PaRAM slot is clear unless the slot is 25062306a36Sopenharmony_ci * in use by Linux or if it is allocated to be used by DSP. 25162306a36Sopenharmony_ci */ 25262306a36Sopenharmony_ci unsigned long *slot_inuse; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci /* 25562306a36Sopenharmony_ci * For tracking reserved channels used by DSP. 25662306a36Sopenharmony_ci * If the bit is cleared, the channel is allocated to be used by DSP 25762306a36Sopenharmony_ci * and Linux must not touch it. 25862306a36Sopenharmony_ci */ 25962306a36Sopenharmony_ci unsigned long *channels_mask; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci struct dma_device dma_slave; 26262306a36Sopenharmony_ci struct dma_device *dma_memcpy; 26362306a36Sopenharmony_ci struct edma_chan *slave_chans; 26462306a36Sopenharmony_ci struct edma_tc *tc_list; 26562306a36Sopenharmony_ci int dummy_slot; 26662306a36Sopenharmony_ci}; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci/* dummy param set used to (re)initialize parameter RAM slots */ 26962306a36Sopenharmony_cistatic const struct edmacc_param dummy_paramset = { 27062306a36Sopenharmony_ci .link_bcntrld = 0xffff, 27162306a36Sopenharmony_ci .ccnt = 1, 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci#define EDMA_BINDING_LEGACY 0 27562306a36Sopenharmony_ci#define EDMA_BINDING_TPCC 1 27662306a36Sopenharmony_cistatic const u32 edma_binding_type[] = { 27762306a36Sopenharmony_ci [EDMA_BINDING_LEGACY] = EDMA_BINDING_LEGACY, 27862306a36Sopenharmony_ci [EDMA_BINDING_TPCC] = EDMA_BINDING_TPCC, 27962306a36Sopenharmony_ci}; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cistatic const struct of_device_id edma_of_ids[] = { 28262306a36Sopenharmony_ci { 28362306a36Sopenharmony_ci .compatible = "ti,edma3", 28462306a36Sopenharmony_ci .data = &edma_binding_type[EDMA_BINDING_LEGACY], 28562306a36Sopenharmony_ci }, 28662306a36Sopenharmony_ci { 28762306a36Sopenharmony_ci .compatible = "ti,edma3-tpcc", 28862306a36Sopenharmony_ci .data = &edma_binding_type[EDMA_BINDING_TPCC], 28962306a36Sopenharmony_ci }, 29062306a36Sopenharmony_ci {} 29162306a36Sopenharmony_ci}; 29262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, edma_of_ids); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_cistatic const struct of_device_id edma_tptc_of_ids[] = { 29562306a36Sopenharmony_ci { .compatible = "ti,edma3-tptc", }, 29662306a36Sopenharmony_ci {} 29762306a36Sopenharmony_ci}; 29862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, edma_tptc_of_ids); 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic inline unsigned int edma_read(struct edma_cc *ecc, int offset) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci return (unsigned int)__raw_readl(ecc->base + offset); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic inline void edma_write(struct edma_cc *ecc, int offset, int val) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci __raw_writel(val, ecc->base + offset); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic inline void edma_modify(struct edma_cc *ecc, int offset, unsigned and, 31162306a36Sopenharmony_ci unsigned or) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci unsigned val = edma_read(ecc, offset); 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci val &= and; 31662306a36Sopenharmony_ci val |= or; 31762306a36Sopenharmony_ci edma_write(ecc, offset, val); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic inline void edma_or(struct edma_cc *ecc, int offset, unsigned or) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci unsigned val = edma_read(ecc, offset); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci val |= or; 32562306a36Sopenharmony_ci edma_write(ecc, offset, val); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic inline unsigned int edma_read_array(struct edma_cc *ecc, int offset, 32962306a36Sopenharmony_ci int i) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci return edma_read(ecc, offset + (i << 2)); 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic inline void edma_write_array(struct edma_cc *ecc, int offset, int i, 33562306a36Sopenharmony_ci unsigned val) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci edma_write(ecc, offset + (i << 2), val); 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic inline void edma_modify_array(struct edma_cc *ecc, int offset, int i, 34162306a36Sopenharmony_ci unsigned and, unsigned or) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci edma_modify(ecc, offset + (i << 2), and, or); 34462306a36Sopenharmony_ci} 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic inline void edma_or_array2(struct edma_cc *ecc, int offset, int i, int j, 34762306a36Sopenharmony_ci unsigned or) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci edma_or(ecc, offset + ((i * 2 + j) << 2), or); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic inline void edma_write_array2(struct edma_cc *ecc, int offset, int i, 35362306a36Sopenharmony_ci int j, unsigned val) 35462306a36Sopenharmony_ci{ 35562306a36Sopenharmony_ci edma_write(ecc, offset + ((i * 2 + j) << 2), val); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic inline unsigned int edma_shadow0_read_array(struct edma_cc *ecc, 35962306a36Sopenharmony_ci int offset, int i) 36062306a36Sopenharmony_ci{ 36162306a36Sopenharmony_ci return edma_read(ecc, EDMA_SHADOW0 + offset + (i << 2)); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic inline void edma_shadow0_write(struct edma_cc *ecc, int offset, 36562306a36Sopenharmony_ci unsigned val) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci edma_write(ecc, EDMA_SHADOW0 + offset, val); 36862306a36Sopenharmony_ci} 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_cistatic inline void edma_shadow0_write_array(struct edma_cc *ecc, int offset, 37162306a36Sopenharmony_ci int i, unsigned val) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci edma_write(ecc, EDMA_SHADOW0 + offset + (i << 2), val); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic inline void edma_param_modify(struct edma_cc *ecc, int offset, 37762306a36Sopenharmony_ci int param_no, unsigned and, unsigned or) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci edma_modify(ecc, EDMA_PARM + offset + (param_no << 5), and, or); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void edma_assign_priority_to_queue(struct edma_cc *ecc, int queue_no, 38362306a36Sopenharmony_ci int priority) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int bit = queue_no * 4; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci edma_modify(ecc, EDMA_QUEPRI, ~(0x7 << bit), ((priority & 0x7) << bit)); 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic void edma_set_chmap(struct edma_chan *echan, int slot) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 39362306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci if (ecc->chmap_exist) { 39662306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 39762306a36Sopenharmony_ci edma_write_array(ecc, EDMA_DCHMAP, channel, (slot << 5)); 39862306a36Sopenharmony_ci } 39962306a36Sopenharmony_ci} 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_cistatic void edma_setup_interrupt(struct edma_chan *echan, bool enable) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 40462306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 40562306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 40662306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci if (enable) { 40962306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); 41062306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_IESR, idx, ch_bit); 41162306a36Sopenharmony_ci } else { 41262306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_IECR, idx, ch_bit); 41362306a36Sopenharmony_ci } 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci/* 41762306a36Sopenharmony_ci * paRAM slot management functions 41862306a36Sopenharmony_ci */ 41962306a36Sopenharmony_cistatic void edma_write_slot(struct edma_cc *ecc, unsigned slot, 42062306a36Sopenharmony_ci const struct edmacc_param *param) 42162306a36Sopenharmony_ci{ 42262306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 42362306a36Sopenharmony_ci if (slot >= ecc->num_slots) 42462306a36Sopenharmony_ci return; 42562306a36Sopenharmony_ci memcpy_toio(ecc->base + PARM_OFFSET(slot), param, PARM_SIZE); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_cistatic int edma_read_slot(struct edma_cc *ecc, unsigned slot, 42962306a36Sopenharmony_ci struct edmacc_param *param) 43062306a36Sopenharmony_ci{ 43162306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 43262306a36Sopenharmony_ci if (slot >= ecc->num_slots) 43362306a36Sopenharmony_ci return -EINVAL; 43462306a36Sopenharmony_ci memcpy_fromio(param, ecc->base + PARM_OFFSET(slot), PARM_SIZE); 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return 0; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/** 44062306a36Sopenharmony_ci * edma_alloc_slot - allocate DMA parameter RAM 44162306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct 44262306a36Sopenharmony_ci * @slot: specific slot to allocate; negative for "any unused slot" 44362306a36Sopenharmony_ci * 44462306a36Sopenharmony_ci * This allocates a parameter RAM slot, initializing it to hold a 44562306a36Sopenharmony_ci * dummy transfer. Slots allocated using this routine have not been 44662306a36Sopenharmony_ci * mapped to a hardware DMA channel, and will normally be used by 44762306a36Sopenharmony_ci * linking to them from a slot associated with a DMA channel. 44862306a36Sopenharmony_ci * 44962306a36Sopenharmony_ci * Normal use is to pass EDMA_SLOT_ANY as the @slot, but specific 45062306a36Sopenharmony_ci * slots may be allocated on behalf of DSP firmware. 45162306a36Sopenharmony_ci * 45262306a36Sopenharmony_ci * Returns the number of the slot, else negative errno. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_cistatic int edma_alloc_slot(struct edma_cc *ecc, int slot) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci if (slot >= 0) { 45762306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 45862306a36Sopenharmony_ci /* Requesting entry paRAM slot for a HW triggered channel. */ 45962306a36Sopenharmony_ci if (ecc->chmap_exist && slot < ecc->num_channels) 46062306a36Sopenharmony_ci slot = EDMA_SLOT_ANY; 46162306a36Sopenharmony_ci } 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci if (slot < 0) { 46462306a36Sopenharmony_ci if (ecc->chmap_exist) 46562306a36Sopenharmony_ci slot = 0; 46662306a36Sopenharmony_ci else 46762306a36Sopenharmony_ci slot = ecc->num_channels; 46862306a36Sopenharmony_ci for (;;) { 46962306a36Sopenharmony_ci slot = find_next_zero_bit(ecc->slot_inuse, 47062306a36Sopenharmony_ci ecc->num_slots, 47162306a36Sopenharmony_ci slot); 47262306a36Sopenharmony_ci if (slot == ecc->num_slots) 47362306a36Sopenharmony_ci return -ENOMEM; 47462306a36Sopenharmony_ci if (!test_and_set_bit(slot, ecc->slot_inuse)) 47562306a36Sopenharmony_ci break; 47662306a36Sopenharmony_ci } 47762306a36Sopenharmony_ci } else if (slot >= ecc->num_slots) { 47862306a36Sopenharmony_ci return -EINVAL; 47962306a36Sopenharmony_ci } else if (test_and_set_bit(slot, ecc->slot_inuse)) { 48062306a36Sopenharmony_ci return -EBUSY; 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci edma_write_slot(ecc, slot, &dummy_paramset); 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci return EDMA_CTLR_CHAN(ecc->id, slot); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic void edma_free_slot(struct edma_cc *ecc, unsigned slot) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 49162306a36Sopenharmony_ci if (slot >= ecc->num_slots) 49262306a36Sopenharmony_ci return; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci edma_write_slot(ecc, slot, &dummy_paramset); 49562306a36Sopenharmony_ci clear_bit(slot, ecc->slot_inuse); 49662306a36Sopenharmony_ci} 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci/** 49962306a36Sopenharmony_ci * edma_link - link one parameter RAM slot to another 50062306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct 50162306a36Sopenharmony_ci * @from: parameter RAM slot originating the link 50262306a36Sopenharmony_ci * @to: parameter RAM slot which is the link target 50362306a36Sopenharmony_ci * 50462306a36Sopenharmony_ci * The originating slot should not be part of any active DMA transfer. 50562306a36Sopenharmony_ci */ 50662306a36Sopenharmony_cistatic void edma_link(struct edma_cc *ecc, unsigned from, unsigned to) 50762306a36Sopenharmony_ci{ 50862306a36Sopenharmony_ci if (unlikely(EDMA_CTLR(from) != EDMA_CTLR(to))) 50962306a36Sopenharmony_ci dev_warn(ecc->dev, "Ignoring eDMA instance for linking\n"); 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci from = EDMA_CHAN_SLOT(from); 51262306a36Sopenharmony_ci to = EDMA_CHAN_SLOT(to); 51362306a36Sopenharmony_ci if (from >= ecc->num_slots || to >= ecc->num_slots) 51462306a36Sopenharmony_ci return; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci edma_param_modify(ecc, PARM_LINK_BCNTRLD, from, 0xffff0000, 51762306a36Sopenharmony_ci PARM_OFFSET(to)); 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/** 52162306a36Sopenharmony_ci * edma_get_position - returns the current transfer point 52262306a36Sopenharmony_ci * @ecc: pointer to edma_cc struct 52362306a36Sopenharmony_ci * @slot: parameter RAM slot being examined 52462306a36Sopenharmony_ci * @dst: true selects the dest position, false the source 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci * Returns the position of the current active slot 52762306a36Sopenharmony_ci */ 52862306a36Sopenharmony_cistatic dma_addr_t edma_get_position(struct edma_cc *ecc, unsigned slot, 52962306a36Sopenharmony_ci bool dst) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u32 offs; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci slot = EDMA_CHAN_SLOT(slot); 53462306a36Sopenharmony_ci offs = PARM_OFFSET(slot); 53562306a36Sopenharmony_ci offs += dst ? PARM_DST : PARM_SRC; 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci return edma_read(ecc, offs); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci/* 54162306a36Sopenharmony_ci * Channels with event associations will be triggered by their hardware 54262306a36Sopenharmony_ci * events, and channels without such associations will be triggered by 54362306a36Sopenharmony_ci * software. (At this writing there is no interface for using software 54462306a36Sopenharmony_ci * triggers except with channels that don't support hardware triggers.) 54562306a36Sopenharmony_ci */ 54662306a36Sopenharmony_cistatic void edma_start(struct edma_chan *echan) 54762306a36Sopenharmony_ci{ 54862306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 54962306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 55062306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 55162306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci if (!echan->hw_triggered) { 55462306a36Sopenharmony_ci /* EDMA channels without event association */ 55562306a36Sopenharmony_ci dev_dbg(ecc->dev, "ESR%d %08x\n", idx, 55662306a36Sopenharmony_ci edma_shadow0_read_array(ecc, SH_ESR, idx)); 55762306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); 55862306a36Sopenharmony_ci } else { 55962306a36Sopenharmony_ci /* EDMA channel with event association */ 56062306a36Sopenharmony_ci dev_dbg(ecc->dev, "ER%d %08x\n", idx, 56162306a36Sopenharmony_ci edma_shadow0_read_array(ecc, SH_ER, idx)); 56262306a36Sopenharmony_ci /* Clear any pending event or error */ 56362306a36Sopenharmony_ci edma_write_array(ecc, EDMA_ECR, idx, ch_bit); 56462306a36Sopenharmony_ci edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); 56562306a36Sopenharmony_ci /* Clear any SER */ 56662306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); 56762306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_EESR, idx, ch_bit); 56862306a36Sopenharmony_ci dev_dbg(ecc->dev, "EER%d %08x\n", idx, 56962306a36Sopenharmony_ci edma_shadow0_read_array(ecc, SH_EER, idx)); 57062306a36Sopenharmony_ci } 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_cistatic void edma_stop(struct edma_chan *echan) 57462306a36Sopenharmony_ci{ 57562306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 57662306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 57762306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 57862306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_EECR, idx, ch_bit); 58162306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); 58262306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); 58362306a36Sopenharmony_ci edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci /* clear possibly pending completion interrupt */ 58662306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ICR, idx, ch_bit); 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci dev_dbg(ecc->dev, "EER%d %08x\n", idx, 58962306a36Sopenharmony_ci edma_shadow0_read_array(ecc, SH_EER, idx)); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci /* REVISIT: consider guarding against inappropriate event 59262306a36Sopenharmony_ci * chaining by overwriting with dummy_paramset. 59362306a36Sopenharmony_ci */ 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/* 59762306a36Sopenharmony_ci * Temporarily disable EDMA hardware events on the specified channel, 59862306a36Sopenharmony_ci * preventing them from triggering new transfers 59962306a36Sopenharmony_ci */ 60062306a36Sopenharmony_cistatic void edma_pause(struct edma_chan *echan) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci edma_shadow0_write_array(echan->ecc, SH_EECR, 60562306a36Sopenharmony_ci EDMA_REG_ARRAY_INDEX(channel), 60662306a36Sopenharmony_ci EDMA_CHANNEL_BIT(channel)); 60762306a36Sopenharmony_ci} 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci/* Re-enable EDMA hardware events on the specified channel. */ 61062306a36Sopenharmony_cistatic void edma_resume(struct edma_chan *echan) 61162306a36Sopenharmony_ci{ 61262306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_ci edma_shadow0_write_array(echan->ecc, SH_EESR, 61562306a36Sopenharmony_ci EDMA_REG_ARRAY_INDEX(channel), 61662306a36Sopenharmony_ci EDMA_CHANNEL_BIT(channel)); 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic void edma_trigger_channel(struct edma_chan *echan) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 62262306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 62362306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 62462306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ESR, idx, ch_bit); 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci dev_dbg(ecc->dev, "ESR%d %08x\n", idx, 62962306a36Sopenharmony_ci edma_shadow0_read_array(ecc, SH_ESR, idx)); 63062306a36Sopenharmony_ci} 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_cistatic void edma_clean_channel(struct edma_chan *echan) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 63562306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 63662306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 63762306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci dev_dbg(ecc->dev, "EMR%d %08x\n", idx, 64062306a36Sopenharmony_ci edma_read_array(ecc, EDMA_EMR, idx)); 64162306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ECR, idx, ch_bit); 64262306a36Sopenharmony_ci /* Clear the corresponding EMR bits */ 64362306a36Sopenharmony_ci edma_write_array(ecc, EDMA_EMCR, idx, ch_bit); 64462306a36Sopenharmony_ci /* Clear any SER */ 64562306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_SECR, idx, ch_bit); 64662306a36Sopenharmony_ci edma_write(ecc, EDMA_CCERRCLR, BIT(16) | BIT(1) | BIT(0)); 64762306a36Sopenharmony_ci} 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci/* Move channel to a specific event queue */ 65062306a36Sopenharmony_cistatic void edma_assign_channel_eventq(struct edma_chan *echan, 65162306a36Sopenharmony_ci enum dma_event_q eventq_no) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 65462306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 65562306a36Sopenharmony_ci int bit = (channel & 0x7) * 4; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci /* default to low priority queue */ 65862306a36Sopenharmony_ci if (eventq_no == EVENTQ_DEFAULT) 65962306a36Sopenharmony_ci eventq_no = ecc->default_queue; 66062306a36Sopenharmony_ci if (eventq_no >= ecc->num_tc) 66162306a36Sopenharmony_ci return; 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci eventq_no &= 7; 66462306a36Sopenharmony_ci edma_modify_array(ecc, EDMA_DMAQNUM, (channel >> 3), ~(0x7 << bit), 66562306a36Sopenharmony_ci eventq_no << bit); 66662306a36Sopenharmony_ci} 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_cistatic int edma_alloc_channel(struct edma_chan *echan, 66962306a36Sopenharmony_ci enum dma_event_q eventq_no) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 67262306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci if (!test_bit(echan->ch_num, ecc->channels_mask)) { 67562306a36Sopenharmony_ci dev_err(ecc->dev, "Channel%d is reserved, can not be used!\n", 67662306a36Sopenharmony_ci echan->ch_num); 67762306a36Sopenharmony_ci return -EINVAL; 67862306a36Sopenharmony_ci } 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* ensure access through shadow region 0 */ 68162306a36Sopenharmony_ci edma_or_array2(ecc, EDMA_DRAE, 0, EDMA_REG_ARRAY_INDEX(channel), 68262306a36Sopenharmony_ci EDMA_CHANNEL_BIT(channel)); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci /* ensure no events are pending */ 68562306a36Sopenharmony_ci edma_stop(echan); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci edma_setup_interrupt(echan, true); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci edma_assign_channel_eventq(echan, eventq_no); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return 0; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic void edma_free_channel(struct edma_chan *echan) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci /* ensure no events are pending */ 69762306a36Sopenharmony_ci edma_stop(echan); 69862306a36Sopenharmony_ci /* REVISIT should probably take out of shadow region 0 */ 69962306a36Sopenharmony_ci edma_setup_interrupt(echan, false); 70062306a36Sopenharmony_ci} 70162306a36Sopenharmony_ci 70262306a36Sopenharmony_cistatic inline struct edma_chan *to_edma_chan(struct dma_chan *c) 70362306a36Sopenharmony_ci{ 70462306a36Sopenharmony_ci return container_of(c, struct edma_chan, vchan.chan); 70562306a36Sopenharmony_ci} 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_cistatic inline struct edma_desc *to_edma_desc(struct dma_async_tx_descriptor *tx) 70862306a36Sopenharmony_ci{ 70962306a36Sopenharmony_ci return container_of(tx, struct edma_desc, vdesc.tx); 71062306a36Sopenharmony_ci} 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_cistatic void edma_desc_free(struct virt_dma_desc *vdesc) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci kfree(container_of(vdesc, struct edma_desc, vdesc)); 71562306a36Sopenharmony_ci} 71662306a36Sopenharmony_ci 71762306a36Sopenharmony_ci/* Dispatch a queued descriptor to the controller (caller holds lock) */ 71862306a36Sopenharmony_cistatic void edma_execute(struct edma_chan *echan) 71962306a36Sopenharmony_ci{ 72062306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 72162306a36Sopenharmony_ci struct virt_dma_desc *vdesc; 72262306a36Sopenharmony_ci struct edma_desc *edesc; 72362306a36Sopenharmony_ci struct device *dev = echan->vchan.chan.device->dev; 72462306a36Sopenharmony_ci int i, j, left, nslots; 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci if (!echan->edesc) { 72762306a36Sopenharmony_ci /* Setup is needed for the first transfer */ 72862306a36Sopenharmony_ci vdesc = vchan_next_desc(&echan->vchan); 72962306a36Sopenharmony_ci if (!vdesc) 73062306a36Sopenharmony_ci return; 73162306a36Sopenharmony_ci list_del(&vdesc->node); 73262306a36Sopenharmony_ci echan->edesc = to_edma_desc(&vdesc->tx); 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci edesc = echan->edesc; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* Find out how many left */ 73862306a36Sopenharmony_ci left = edesc->pset_nr - edesc->processed; 73962306a36Sopenharmony_ci nslots = min(MAX_NR_SG, left); 74062306a36Sopenharmony_ci edesc->sg_len = 0; 74162306a36Sopenharmony_ci 74262306a36Sopenharmony_ci /* Write descriptor PaRAM set(s) */ 74362306a36Sopenharmony_ci for (i = 0; i < nslots; i++) { 74462306a36Sopenharmony_ci j = i + edesc->processed; 74562306a36Sopenharmony_ci edma_write_slot(ecc, echan->slot[i], &edesc->pset[j].param); 74662306a36Sopenharmony_ci edesc->sg_len += edesc->pset[j].len; 74762306a36Sopenharmony_ci dev_vdbg(dev, 74862306a36Sopenharmony_ci "\n pset[%d]:\n" 74962306a36Sopenharmony_ci " chnum\t%d\n" 75062306a36Sopenharmony_ci " slot\t%d\n" 75162306a36Sopenharmony_ci " opt\t%08x\n" 75262306a36Sopenharmony_ci " src\t%08x\n" 75362306a36Sopenharmony_ci " dst\t%08x\n" 75462306a36Sopenharmony_ci " abcnt\t%08x\n" 75562306a36Sopenharmony_ci " ccnt\t%08x\n" 75662306a36Sopenharmony_ci " bidx\t%08x\n" 75762306a36Sopenharmony_ci " cidx\t%08x\n" 75862306a36Sopenharmony_ci " lkrld\t%08x\n", 75962306a36Sopenharmony_ci j, echan->ch_num, echan->slot[i], 76062306a36Sopenharmony_ci edesc->pset[j].param.opt, 76162306a36Sopenharmony_ci edesc->pset[j].param.src, 76262306a36Sopenharmony_ci edesc->pset[j].param.dst, 76362306a36Sopenharmony_ci edesc->pset[j].param.a_b_cnt, 76462306a36Sopenharmony_ci edesc->pset[j].param.ccnt, 76562306a36Sopenharmony_ci edesc->pset[j].param.src_dst_bidx, 76662306a36Sopenharmony_ci edesc->pset[j].param.src_dst_cidx, 76762306a36Sopenharmony_ci edesc->pset[j].param.link_bcntrld); 76862306a36Sopenharmony_ci /* Link to the previous slot if not the last set */ 76962306a36Sopenharmony_ci if (i != (nslots - 1)) 77062306a36Sopenharmony_ci edma_link(ecc, echan->slot[i], echan->slot[i + 1]); 77162306a36Sopenharmony_ci } 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci edesc->processed += nslots; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci /* 77662306a36Sopenharmony_ci * If this is either the last set in a set of SG-list transactions 77762306a36Sopenharmony_ci * then setup a link to the dummy slot, this results in all future 77862306a36Sopenharmony_ci * events being absorbed and that's OK because we're done 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci if (edesc->processed == edesc->pset_nr) { 78162306a36Sopenharmony_ci if (edesc->cyclic) 78262306a36Sopenharmony_ci edma_link(ecc, echan->slot[nslots - 1], echan->slot[1]); 78362306a36Sopenharmony_ci else 78462306a36Sopenharmony_ci edma_link(ecc, echan->slot[nslots - 1], 78562306a36Sopenharmony_ci echan->ecc->dummy_slot); 78662306a36Sopenharmony_ci } 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (echan->missed) { 78962306a36Sopenharmony_ci /* 79062306a36Sopenharmony_ci * This happens due to setup times between intermediate 79162306a36Sopenharmony_ci * transfers in long SG lists which have to be broken up into 79262306a36Sopenharmony_ci * transfers of MAX_NR_SG 79362306a36Sopenharmony_ci */ 79462306a36Sopenharmony_ci dev_dbg(dev, "missed event on channel %d\n", echan->ch_num); 79562306a36Sopenharmony_ci edma_clean_channel(echan); 79662306a36Sopenharmony_ci edma_stop(echan); 79762306a36Sopenharmony_ci edma_start(echan); 79862306a36Sopenharmony_ci edma_trigger_channel(echan); 79962306a36Sopenharmony_ci echan->missed = 0; 80062306a36Sopenharmony_ci } else if (edesc->processed <= MAX_NR_SG) { 80162306a36Sopenharmony_ci dev_dbg(dev, "first transfer starting on channel %d\n", 80262306a36Sopenharmony_ci echan->ch_num); 80362306a36Sopenharmony_ci edma_start(echan); 80462306a36Sopenharmony_ci } else { 80562306a36Sopenharmony_ci dev_dbg(dev, "chan: %d: completed %d elements, resuming\n", 80662306a36Sopenharmony_ci echan->ch_num, edesc->processed); 80762306a36Sopenharmony_ci edma_resume(echan); 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci} 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_cistatic int edma_terminate_all(struct dma_chan *chan) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 81462306a36Sopenharmony_ci unsigned long flags; 81562306a36Sopenharmony_ci LIST_HEAD(head); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci spin_lock_irqsave(&echan->vchan.lock, flags); 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* 82062306a36Sopenharmony_ci * Stop DMA activity: we assume the callback will not be called 82162306a36Sopenharmony_ci * after edma_dma() returns (even if it does, it will see 82262306a36Sopenharmony_ci * echan->edesc is NULL and exit.) 82362306a36Sopenharmony_ci */ 82462306a36Sopenharmony_ci if (echan->edesc) { 82562306a36Sopenharmony_ci edma_stop(echan); 82662306a36Sopenharmony_ci /* Move the cyclic channel back to default queue */ 82762306a36Sopenharmony_ci if (!echan->tc && echan->edesc->cyclic) 82862306a36Sopenharmony_ci edma_assign_channel_eventq(echan, EVENTQ_DEFAULT); 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ci vchan_terminate_vdesc(&echan->edesc->vdesc); 83162306a36Sopenharmony_ci echan->edesc = NULL; 83262306a36Sopenharmony_ci } 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci vchan_get_all_descriptors(&echan->vchan, &head); 83562306a36Sopenharmony_ci spin_unlock_irqrestore(&echan->vchan.lock, flags); 83662306a36Sopenharmony_ci vchan_dma_desc_free_list(&echan->vchan, &head); 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_ci return 0; 83962306a36Sopenharmony_ci} 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cistatic void edma_synchronize(struct dma_chan *chan) 84262306a36Sopenharmony_ci{ 84362306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 84462306a36Sopenharmony_ci 84562306a36Sopenharmony_ci vchan_synchronize(&echan->vchan); 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cistatic int edma_slave_config(struct dma_chan *chan, 84962306a36Sopenharmony_ci struct dma_slave_config *cfg) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES || 85462306a36Sopenharmony_ci cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES) 85562306a36Sopenharmony_ci return -EINVAL; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (cfg->src_maxburst > chan->device->max_burst || 85862306a36Sopenharmony_ci cfg->dst_maxburst > chan->device->max_burst) 85962306a36Sopenharmony_ci return -EINVAL; 86062306a36Sopenharmony_ci 86162306a36Sopenharmony_ci memcpy(&echan->cfg, cfg, sizeof(echan->cfg)); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci return 0; 86462306a36Sopenharmony_ci} 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_cistatic int edma_dma_pause(struct dma_chan *chan) 86762306a36Sopenharmony_ci{ 86862306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci if (!echan->edesc) 87162306a36Sopenharmony_ci return -EINVAL; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci edma_pause(echan); 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_cistatic int edma_dma_resume(struct dma_chan *chan) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci edma_resume(echan); 88262306a36Sopenharmony_ci return 0; 88362306a36Sopenharmony_ci} 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci/* 88662306a36Sopenharmony_ci * A PaRAM set configuration abstraction used by other modes 88762306a36Sopenharmony_ci * @chan: Channel who's PaRAM set we're configuring 88862306a36Sopenharmony_ci * @pset: PaRAM set to initialize and setup. 88962306a36Sopenharmony_ci * @src_addr: Source address of the DMA 89062306a36Sopenharmony_ci * @dst_addr: Destination address of the DMA 89162306a36Sopenharmony_ci * @burst: In units of dev_width, how much to send 89262306a36Sopenharmony_ci * @dev_width: How much is the dev_width 89362306a36Sopenharmony_ci * @dma_length: Total length of the DMA transfer 89462306a36Sopenharmony_ci * @direction: Direction of the transfer 89562306a36Sopenharmony_ci */ 89662306a36Sopenharmony_cistatic int edma_config_pset(struct dma_chan *chan, struct edma_pset *epset, 89762306a36Sopenharmony_ci dma_addr_t src_addr, dma_addr_t dst_addr, u32 burst, 89862306a36Sopenharmony_ci unsigned int acnt, unsigned int dma_length, 89962306a36Sopenharmony_ci enum dma_transfer_direction direction) 90062306a36Sopenharmony_ci{ 90162306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 90262306a36Sopenharmony_ci struct device *dev = chan->device->dev; 90362306a36Sopenharmony_ci struct edmacc_param *param = &epset->param; 90462306a36Sopenharmony_ci int bcnt, ccnt, cidx; 90562306a36Sopenharmony_ci int src_bidx, dst_bidx, src_cidx, dst_cidx; 90662306a36Sopenharmony_ci int absync; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* src/dst_maxburst == 0 is the same case as src/dst_maxburst == 1 */ 90962306a36Sopenharmony_ci if (!burst) 91062306a36Sopenharmony_ci burst = 1; 91162306a36Sopenharmony_ci /* 91262306a36Sopenharmony_ci * If the maxburst is equal to the fifo width, use 91362306a36Sopenharmony_ci * A-synced transfers. This allows for large contiguous 91462306a36Sopenharmony_ci * buffer transfers using only one PaRAM set. 91562306a36Sopenharmony_ci */ 91662306a36Sopenharmony_ci if (burst == 1) { 91762306a36Sopenharmony_ci /* 91862306a36Sopenharmony_ci * For the A-sync case, bcnt and ccnt are the remainder 91962306a36Sopenharmony_ci * and quotient respectively of the division of: 92062306a36Sopenharmony_ci * (dma_length / acnt) by (SZ_64K -1). This is so 92162306a36Sopenharmony_ci * that in case bcnt over flows, we have ccnt to use. 92262306a36Sopenharmony_ci * Note: In A-sync transfer only, bcntrld is used, but it 92362306a36Sopenharmony_ci * only applies for sg_dma_len(sg) >= SZ_64K. 92462306a36Sopenharmony_ci * In this case, the best way adopted is- bccnt for the 92562306a36Sopenharmony_ci * first frame will be the remainder below. Then for 92662306a36Sopenharmony_ci * every successive frame, bcnt will be SZ_64K-1. This 92762306a36Sopenharmony_ci * is assured as bcntrld = 0xffff in end of function. 92862306a36Sopenharmony_ci */ 92962306a36Sopenharmony_ci absync = false; 93062306a36Sopenharmony_ci ccnt = dma_length / acnt / (SZ_64K - 1); 93162306a36Sopenharmony_ci bcnt = dma_length / acnt - ccnt * (SZ_64K - 1); 93262306a36Sopenharmony_ci /* 93362306a36Sopenharmony_ci * If bcnt is non-zero, we have a remainder and hence an 93462306a36Sopenharmony_ci * extra frame to transfer, so increment ccnt. 93562306a36Sopenharmony_ci */ 93662306a36Sopenharmony_ci if (bcnt) 93762306a36Sopenharmony_ci ccnt++; 93862306a36Sopenharmony_ci else 93962306a36Sopenharmony_ci bcnt = SZ_64K - 1; 94062306a36Sopenharmony_ci cidx = acnt; 94162306a36Sopenharmony_ci } else { 94262306a36Sopenharmony_ci /* 94362306a36Sopenharmony_ci * If maxburst is greater than the fifo address_width, 94462306a36Sopenharmony_ci * use AB-synced transfers where A count is the fifo 94562306a36Sopenharmony_ci * address_width and B count is the maxburst. In this 94662306a36Sopenharmony_ci * case, we are limited to transfers of C count frames 94762306a36Sopenharmony_ci * of (address_width * maxburst) where C count is limited 94862306a36Sopenharmony_ci * to SZ_64K-1. This places an upper bound on the length 94962306a36Sopenharmony_ci * of an SG segment that can be handled. 95062306a36Sopenharmony_ci */ 95162306a36Sopenharmony_ci absync = true; 95262306a36Sopenharmony_ci bcnt = burst; 95362306a36Sopenharmony_ci ccnt = dma_length / (acnt * bcnt); 95462306a36Sopenharmony_ci if (ccnt > (SZ_64K - 1)) { 95562306a36Sopenharmony_ci dev_err(dev, "Exceeded max SG segment size\n"); 95662306a36Sopenharmony_ci return -EINVAL; 95762306a36Sopenharmony_ci } 95862306a36Sopenharmony_ci cidx = acnt * bcnt; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci epset->len = dma_length; 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (direction == DMA_MEM_TO_DEV) { 96462306a36Sopenharmony_ci src_bidx = acnt; 96562306a36Sopenharmony_ci src_cidx = cidx; 96662306a36Sopenharmony_ci dst_bidx = 0; 96762306a36Sopenharmony_ci dst_cidx = 0; 96862306a36Sopenharmony_ci epset->addr = src_addr; 96962306a36Sopenharmony_ci } else if (direction == DMA_DEV_TO_MEM) { 97062306a36Sopenharmony_ci src_bidx = 0; 97162306a36Sopenharmony_ci src_cidx = 0; 97262306a36Sopenharmony_ci dst_bidx = acnt; 97362306a36Sopenharmony_ci dst_cidx = cidx; 97462306a36Sopenharmony_ci epset->addr = dst_addr; 97562306a36Sopenharmony_ci } else if (direction == DMA_MEM_TO_MEM) { 97662306a36Sopenharmony_ci src_bidx = acnt; 97762306a36Sopenharmony_ci src_cidx = cidx; 97862306a36Sopenharmony_ci dst_bidx = acnt; 97962306a36Sopenharmony_ci dst_cidx = cidx; 98062306a36Sopenharmony_ci epset->addr = src_addr; 98162306a36Sopenharmony_ci } else { 98262306a36Sopenharmony_ci dev_err(dev, "%s: direction not implemented yet\n", __func__); 98362306a36Sopenharmony_ci return -EINVAL; 98462306a36Sopenharmony_ci } 98562306a36Sopenharmony_ci 98662306a36Sopenharmony_ci param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num)); 98762306a36Sopenharmony_ci /* Configure A or AB synchronized transfers */ 98862306a36Sopenharmony_ci if (absync) 98962306a36Sopenharmony_ci param->opt |= SYNCDIM; 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci param->src = src_addr; 99262306a36Sopenharmony_ci param->dst = dst_addr; 99362306a36Sopenharmony_ci 99462306a36Sopenharmony_ci param->src_dst_bidx = (dst_bidx << 16) | src_bidx; 99562306a36Sopenharmony_ci param->src_dst_cidx = (dst_cidx << 16) | src_cidx; 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci param->a_b_cnt = bcnt << 16 | acnt; 99862306a36Sopenharmony_ci param->ccnt = ccnt; 99962306a36Sopenharmony_ci /* 100062306a36Sopenharmony_ci * Only time when (bcntrld) auto reload is required is for 100162306a36Sopenharmony_ci * A-sync case, and in this case, a requirement of reload value 100262306a36Sopenharmony_ci * of SZ_64K-1 only is assured. 'link' is initially set to NULL 100362306a36Sopenharmony_ci * and then later will be populated by edma_execute. 100462306a36Sopenharmony_ci */ 100562306a36Sopenharmony_ci param->link_bcntrld = 0xffffffff; 100662306a36Sopenharmony_ci return absync; 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_slave_sg( 101062306a36Sopenharmony_ci struct dma_chan *chan, struct scatterlist *sgl, 101162306a36Sopenharmony_ci unsigned int sg_len, enum dma_transfer_direction direction, 101262306a36Sopenharmony_ci unsigned long tx_flags, void *context) 101362306a36Sopenharmony_ci{ 101462306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 101562306a36Sopenharmony_ci struct device *dev = chan->device->dev; 101662306a36Sopenharmony_ci struct edma_desc *edesc; 101762306a36Sopenharmony_ci dma_addr_t src_addr = 0, dst_addr = 0; 101862306a36Sopenharmony_ci enum dma_slave_buswidth dev_width; 101962306a36Sopenharmony_ci u32 burst; 102062306a36Sopenharmony_ci struct scatterlist *sg; 102162306a36Sopenharmony_ci int i, nslots, ret; 102262306a36Sopenharmony_ci 102362306a36Sopenharmony_ci if (unlikely(!echan || !sgl || !sg_len)) 102462306a36Sopenharmony_ci return NULL; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci if (direction == DMA_DEV_TO_MEM) { 102762306a36Sopenharmony_ci src_addr = echan->cfg.src_addr; 102862306a36Sopenharmony_ci dev_width = echan->cfg.src_addr_width; 102962306a36Sopenharmony_ci burst = echan->cfg.src_maxburst; 103062306a36Sopenharmony_ci } else if (direction == DMA_MEM_TO_DEV) { 103162306a36Sopenharmony_ci dst_addr = echan->cfg.dst_addr; 103262306a36Sopenharmony_ci dev_width = echan->cfg.dst_addr_width; 103362306a36Sopenharmony_ci burst = echan->cfg.dst_maxburst; 103462306a36Sopenharmony_ci } else { 103562306a36Sopenharmony_ci dev_err(dev, "%s: bad direction: %d\n", __func__, direction); 103662306a36Sopenharmony_ci return NULL; 103762306a36Sopenharmony_ci } 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { 104062306a36Sopenharmony_ci dev_err(dev, "%s: Undefined slave buswidth\n", __func__); 104162306a36Sopenharmony_ci return NULL; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci edesc = kzalloc(struct_size(edesc, pset, sg_len), GFP_ATOMIC); 104562306a36Sopenharmony_ci if (!edesc) 104662306a36Sopenharmony_ci return NULL; 104762306a36Sopenharmony_ci 104862306a36Sopenharmony_ci edesc->pset_nr = sg_len; 104962306a36Sopenharmony_ci edesc->residue = 0; 105062306a36Sopenharmony_ci edesc->direction = direction; 105162306a36Sopenharmony_ci edesc->echan = echan; 105262306a36Sopenharmony_ci 105362306a36Sopenharmony_ci /* Allocate a PaRAM slot, if needed */ 105462306a36Sopenharmony_ci nslots = min_t(unsigned, MAX_NR_SG, sg_len); 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci for (i = 0; i < nslots; i++) { 105762306a36Sopenharmony_ci if (echan->slot[i] < 0) { 105862306a36Sopenharmony_ci echan->slot[i] = 105962306a36Sopenharmony_ci edma_alloc_slot(echan->ecc, EDMA_SLOT_ANY); 106062306a36Sopenharmony_ci if (echan->slot[i] < 0) { 106162306a36Sopenharmony_ci kfree(edesc); 106262306a36Sopenharmony_ci dev_err(dev, "%s: Failed to allocate slot\n", 106362306a36Sopenharmony_ci __func__); 106462306a36Sopenharmony_ci return NULL; 106562306a36Sopenharmony_ci } 106662306a36Sopenharmony_ci } 106762306a36Sopenharmony_ci } 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci /* Configure PaRAM sets for each SG */ 107062306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 107162306a36Sopenharmony_ci /* Get address for each SG */ 107262306a36Sopenharmony_ci if (direction == DMA_DEV_TO_MEM) 107362306a36Sopenharmony_ci dst_addr = sg_dma_address(sg); 107462306a36Sopenharmony_ci else 107562306a36Sopenharmony_ci src_addr = sg_dma_address(sg); 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci ret = edma_config_pset(chan, &edesc->pset[i], src_addr, 107862306a36Sopenharmony_ci dst_addr, burst, dev_width, 107962306a36Sopenharmony_ci sg_dma_len(sg), direction); 108062306a36Sopenharmony_ci if (ret < 0) { 108162306a36Sopenharmony_ci kfree(edesc); 108262306a36Sopenharmony_ci return NULL; 108362306a36Sopenharmony_ci } 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci edesc->absync = ret; 108662306a36Sopenharmony_ci edesc->residue += sg_dma_len(sg); 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (i == sg_len - 1) 108962306a36Sopenharmony_ci /* Enable completion interrupt */ 109062306a36Sopenharmony_ci edesc->pset[i].param.opt |= TCINTEN; 109162306a36Sopenharmony_ci else if (!((i+1) % MAX_NR_SG)) 109262306a36Sopenharmony_ci /* 109362306a36Sopenharmony_ci * Enable early completion interrupt for the 109462306a36Sopenharmony_ci * intermediateset. In this case the driver will be 109562306a36Sopenharmony_ci * notified when the paRAM set is submitted to TC. This 109662306a36Sopenharmony_ci * will allow more time to set up the next set of slots. 109762306a36Sopenharmony_ci */ 109862306a36Sopenharmony_ci edesc->pset[i].param.opt |= (TCINTEN | TCCMODE); 109962306a36Sopenharmony_ci } 110062306a36Sopenharmony_ci edesc->residue_stat = edesc->residue; 110162306a36Sopenharmony_ci 110262306a36Sopenharmony_ci return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); 110362306a36Sopenharmony_ci} 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_dma_memcpy( 110662306a36Sopenharmony_ci struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, 110762306a36Sopenharmony_ci size_t len, unsigned long tx_flags) 110862306a36Sopenharmony_ci{ 110962306a36Sopenharmony_ci int ret, nslots; 111062306a36Sopenharmony_ci struct edma_desc *edesc; 111162306a36Sopenharmony_ci struct device *dev = chan->device->dev; 111262306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 111362306a36Sopenharmony_ci unsigned int width, pset_len, array_size; 111462306a36Sopenharmony_ci 111562306a36Sopenharmony_ci if (unlikely(!echan || !len)) 111662306a36Sopenharmony_ci return NULL; 111762306a36Sopenharmony_ci 111862306a36Sopenharmony_ci /* Align the array size (acnt block) with the transfer properties */ 111962306a36Sopenharmony_ci switch (__ffs((src | dest | len))) { 112062306a36Sopenharmony_ci case 0: 112162306a36Sopenharmony_ci array_size = SZ_32K - 1; 112262306a36Sopenharmony_ci break; 112362306a36Sopenharmony_ci case 1: 112462306a36Sopenharmony_ci array_size = SZ_32K - 2; 112562306a36Sopenharmony_ci break; 112662306a36Sopenharmony_ci default: 112762306a36Sopenharmony_ci array_size = SZ_32K - 4; 112862306a36Sopenharmony_ci break; 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci if (len < SZ_64K) { 113262306a36Sopenharmony_ci /* 113362306a36Sopenharmony_ci * Transfer size less than 64K can be handled with one paRAM 113462306a36Sopenharmony_ci * slot and with one burst. 113562306a36Sopenharmony_ci * ACNT = length 113662306a36Sopenharmony_ci */ 113762306a36Sopenharmony_ci width = len; 113862306a36Sopenharmony_ci pset_len = len; 113962306a36Sopenharmony_ci nslots = 1; 114062306a36Sopenharmony_ci } else { 114162306a36Sopenharmony_ci /* 114262306a36Sopenharmony_ci * Transfer size bigger than 64K will be handled with maximum of 114362306a36Sopenharmony_ci * two paRAM slots. 114462306a36Sopenharmony_ci * slot1: (full_length / 32767) times 32767 bytes bursts. 114562306a36Sopenharmony_ci * ACNT = 32767, length1: (full_length / 32767) * 32767 114662306a36Sopenharmony_ci * slot2: the remaining amount of data after slot1. 114762306a36Sopenharmony_ci * ACNT = full_length - length1, length2 = ACNT 114862306a36Sopenharmony_ci * 114962306a36Sopenharmony_ci * When the full_length is a multiple of 32767 one slot can be 115062306a36Sopenharmony_ci * used to complete the transfer. 115162306a36Sopenharmony_ci */ 115262306a36Sopenharmony_ci width = array_size; 115362306a36Sopenharmony_ci pset_len = rounddown(len, width); 115462306a36Sopenharmony_ci /* One slot is enough for lengths multiple of (SZ_32K -1) */ 115562306a36Sopenharmony_ci if (unlikely(pset_len == len)) 115662306a36Sopenharmony_ci nslots = 1; 115762306a36Sopenharmony_ci else 115862306a36Sopenharmony_ci nslots = 2; 115962306a36Sopenharmony_ci } 116062306a36Sopenharmony_ci 116162306a36Sopenharmony_ci edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC); 116262306a36Sopenharmony_ci if (!edesc) 116362306a36Sopenharmony_ci return NULL; 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci edesc->pset_nr = nslots; 116662306a36Sopenharmony_ci edesc->residue = edesc->residue_stat = len; 116762306a36Sopenharmony_ci edesc->direction = DMA_MEM_TO_MEM; 116862306a36Sopenharmony_ci edesc->echan = echan; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci ret = edma_config_pset(chan, &edesc->pset[0], src, dest, 1, 117162306a36Sopenharmony_ci width, pset_len, DMA_MEM_TO_MEM); 117262306a36Sopenharmony_ci if (ret < 0) { 117362306a36Sopenharmony_ci kfree(edesc); 117462306a36Sopenharmony_ci return NULL; 117562306a36Sopenharmony_ci } 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ci edesc->absync = ret; 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_ci edesc->pset[0].param.opt |= ITCCHEN; 118062306a36Sopenharmony_ci if (nslots == 1) { 118162306a36Sopenharmony_ci /* Enable transfer complete interrupt if requested */ 118262306a36Sopenharmony_ci if (tx_flags & DMA_PREP_INTERRUPT) 118362306a36Sopenharmony_ci edesc->pset[0].param.opt |= TCINTEN; 118462306a36Sopenharmony_ci } else { 118562306a36Sopenharmony_ci /* Enable transfer complete chaining for the first slot */ 118662306a36Sopenharmony_ci edesc->pset[0].param.opt |= TCCHEN; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci if (echan->slot[1] < 0) { 118962306a36Sopenharmony_ci echan->slot[1] = edma_alloc_slot(echan->ecc, 119062306a36Sopenharmony_ci EDMA_SLOT_ANY); 119162306a36Sopenharmony_ci if (echan->slot[1] < 0) { 119262306a36Sopenharmony_ci kfree(edesc); 119362306a36Sopenharmony_ci dev_err(dev, "%s: Failed to allocate slot\n", 119462306a36Sopenharmony_ci __func__); 119562306a36Sopenharmony_ci return NULL; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci dest += pset_len; 119962306a36Sopenharmony_ci src += pset_len; 120062306a36Sopenharmony_ci pset_len = width = len % array_size; 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci ret = edma_config_pset(chan, &edesc->pset[1], src, dest, 1, 120362306a36Sopenharmony_ci width, pset_len, DMA_MEM_TO_MEM); 120462306a36Sopenharmony_ci if (ret < 0) { 120562306a36Sopenharmony_ci kfree(edesc); 120662306a36Sopenharmony_ci return NULL; 120762306a36Sopenharmony_ci } 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci edesc->pset[1].param.opt |= ITCCHEN; 121062306a36Sopenharmony_ci /* Enable transfer complete interrupt if requested */ 121162306a36Sopenharmony_ci if (tx_flags & DMA_PREP_INTERRUPT) 121262306a36Sopenharmony_ci edesc->pset[1].param.opt |= TCINTEN; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci 121562306a36Sopenharmony_ci if (!(tx_flags & DMA_PREP_INTERRUPT)) 121662306a36Sopenharmony_ci edesc->polled = true; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 122262306a36Sopenharmony_ciedma_prep_dma_interleaved(struct dma_chan *chan, 122362306a36Sopenharmony_ci struct dma_interleaved_template *xt, 122462306a36Sopenharmony_ci unsigned long tx_flags) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct device *dev = chan->device->dev; 122762306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 122862306a36Sopenharmony_ci struct edmacc_param *param; 122962306a36Sopenharmony_ci struct edma_desc *edesc; 123062306a36Sopenharmony_ci size_t src_icg, dst_icg; 123162306a36Sopenharmony_ci int src_bidx, dst_bidx; 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci /* Slave mode is not supported */ 123462306a36Sopenharmony_ci if (is_slave_direction(xt->dir)) 123562306a36Sopenharmony_ci return NULL; 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci if (xt->frame_size != 1 || xt->numf == 0) 123862306a36Sopenharmony_ci return NULL; 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci if (xt->sgl[0].size > SZ_64K || xt->numf > SZ_64K) 124162306a36Sopenharmony_ci return NULL; 124262306a36Sopenharmony_ci 124362306a36Sopenharmony_ci src_icg = dmaengine_get_src_icg(xt, &xt->sgl[0]); 124462306a36Sopenharmony_ci if (src_icg) { 124562306a36Sopenharmony_ci src_bidx = src_icg + xt->sgl[0].size; 124662306a36Sopenharmony_ci } else if (xt->src_inc) { 124762306a36Sopenharmony_ci src_bidx = xt->sgl[0].size; 124862306a36Sopenharmony_ci } else { 124962306a36Sopenharmony_ci dev_err(dev, "%s: SRC constant addressing is not supported\n", 125062306a36Sopenharmony_ci __func__); 125162306a36Sopenharmony_ci return NULL; 125262306a36Sopenharmony_ci } 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci dst_icg = dmaengine_get_dst_icg(xt, &xt->sgl[0]); 125562306a36Sopenharmony_ci if (dst_icg) { 125662306a36Sopenharmony_ci dst_bidx = dst_icg + xt->sgl[0].size; 125762306a36Sopenharmony_ci } else if (xt->dst_inc) { 125862306a36Sopenharmony_ci dst_bidx = xt->sgl[0].size; 125962306a36Sopenharmony_ci } else { 126062306a36Sopenharmony_ci dev_err(dev, "%s: DST constant addressing is not supported\n", 126162306a36Sopenharmony_ci __func__); 126262306a36Sopenharmony_ci return NULL; 126362306a36Sopenharmony_ci } 126462306a36Sopenharmony_ci 126562306a36Sopenharmony_ci if (src_bidx > SZ_64K || dst_bidx > SZ_64K) 126662306a36Sopenharmony_ci return NULL; 126762306a36Sopenharmony_ci 126862306a36Sopenharmony_ci edesc = kzalloc(struct_size(edesc, pset, 1), GFP_ATOMIC); 126962306a36Sopenharmony_ci if (!edesc) 127062306a36Sopenharmony_ci return NULL; 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci edesc->direction = DMA_MEM_TO_MEM; 127362306a36Sopenharmony_ci edesc->echan = echan; 127462306a36Sopenharmony_ci edesc->pset_nr = 1; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci param = &edesc->pset[0].param; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci param->src = xt->src_start; 127962306a36Sopenharmony_ci param->dst = xt->dst_start; 128062306a36Sopenharmony_ci param->a_b_cnt = xt->numf << 16 | xt->sgl[0].size; 128162306a36Sopenharmony_ci param->ccnt = 1; 128262306a36Sopenharmony_ci param->src_dst_bidx = (dst_bidx << 16) | src_bidx; 128362306a36Sopenharmony_ci param->src_dst_cidx = 0; 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_ci param->opt = EDMA_TCC(EDMA_CHAN_SLOT(echan->ch_num)); 128662306a36Sopenharmony_ci param->opt |= ITCCHEN; 128762306a36Sopenharmony_ci /* Enable transfer complete interrupt if requested */ 128862306a36Sopenharmony_ci if (tx_flags & DMA_PREP_INTERRUPT) 128962306a36Sopenharmony_ci param->opt |= TCINTEN; 129062306a36Sopenharmony_ci else 129162306a36Sopenharmony_ci edesc->polled = true; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *edma_prep_dma_cyclic( 129762306a36Sopenharmony_ci struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, 129862306a36Sopenharmony_ci size_t period_len, enum dma_transfer_direction direction, 129962306a36Sopenharmony_ci unsigned long tx_flags) 130062306a36Sopenharmony_ci{ 130162306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 130262306a36Sopenharmony_ci struct device *dev = chan->device->dev; 130362306a36Sopenharmony_ci struct edma_desc *edesc; 130462306a36Sopenharmony_ci dma_addr_t src_addr, dst_addr; 130562306a36Sopenharmony_ci enum dma_slave_buswidth dev_width; 130662306a36Sopenharmony_ci bool use_intermediate = false; 130762306a36Sopenharmony_ci u32 burst; 130862306a36Sopenharmony_ci int i, ret, nslots; 130962306a36Sopenharmony_ci 131062306a36Sopenharmony_ci if (unlikely(!echan || !buf_len || !period_len)) 131162306a36Sopenharmony_ci return NULL; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci if (direction == DMA_DEV_TO_MEM) { 131462306a36Sopenharmony_ci src_addr = echan->cfg.src_addr; 131562306a36Sopenharmony_ci dst_addr = buf_addr; 131662306a36Sopenharmony_ci dev_width = echan->cfg.src_addr_width; 131762306a36Sopenharmony_ci burst = echan->cfg.src_maxburst; 131862306a36Sopenharmony_ci } else if (direction == DMA_MEM_TO_DEV) { 131962306a36Sopenharmony_ci src_addr = buf_addr; 132062306a36Sopenharmony_ci dst_addr = echan->cfg.dst_addr; 132162306a36Sopenharmony_ci dev_width = echan->cfg.dst_addr_width; 132262306a36Sopenharmony_ci burst = echan->cfg.dst_maxburst; 132362306a36Sopenharmony_ci } else { 132462306a36Sopenharmony_ci dev_err(dev, "%s: bad direction: %d\n", __func__, direction); 132562306a36Sopenharmony_ci return NULL; 132662306a36Sopenharmony_ci } 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci if (dev_width == DMA_SLAVE_BUSWIDTH_UNDEFINED) { 132962306a36Sopenharmony_ci dev_err(dev, "%s: Undefined slave buswidth\n", __func__); 133062306a36Sopenharmony_ci return NULL; 133162306a36Sopenharmony_ci } 133262306a36Sopenharmony_ci 133362306a36Sopenharmony_ci if (unlikely(buf_len % period_len)) { 133462306a36Sopenharmony_ci dev_err(dev, "Period should be multiple of Buffer length\n"); 133562306a36Sopenharmony_ci return NULL; 133662306a36Sopenharmony_ci } 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci nslots = (buf_len / period_len) + 1; 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci /* 134162306a36Sopenharmony_ci * Cyclic DMA users such as audio cannot tolerate delays introduced 134262306a36Sopenharmony_ci * by cases where the number of periods is more than the maximum 134362306a36Sopenharmony_ci * number of SGs the EDMA driver can handle at a time. For DMA types 134462306a36Sopenharmony_ci * such as Slave SGs, such delays are tolerable and synchronized, 134562306a36Sopenharmony_ci * but the synchronization is difficult to achieve with Cyclic and 134662306a36Sopenharmony_ci * cannot be guaranteed, so we error out early. 134762306a36Sopenharmony_ci */ 134862306a36Sopenharmony_ci if (nslots > MAX_NR_SG) { 134962306a36Sopenharmony_ci /* 135062306a36Sopenharmony_ci * If the burst and period sizes are the same, we can put 135162306a36Sopenharmony_ci * the full buffer into a single period and activate 135262306a36Sopenharmony_ci * intermediate interrupts. This will produce interrupts 135362306a36Sopenharmony_ci * after each burst, which is also after each desired period. 135462306a36Sopenharmony_ci */ 135562306a36Sopenharmony_ci if (burst == period_len) { 135662306a36Sopenharmony_ci period_len = buf_len; 135762306a36Sopenharmony_ci nslots = 2; 135862306a36Sopenharmony_ci use_intermediate = true; 135962306a36Sopenharmony_ci } else { 136062306a36Sopenharmony_ci return NULL; 136162306a36Sopenharmony_ci } 136262306a36Sopenharmony_ci } 136362306a36Sopenharmony_ci 136462306a36Sopenharmony_ci edesc = kzalloc(struct_size(edesc, pset, nslots), GFP_ATOMIC); 136562306a36Sopenharmony_ci if (!edesc) 136662306a36Sopenharmony_ci return NULL; 136762306a36Sopenharmony_ci 136862306a36Sopenharmony_ci edesc->cyclic = 1; 136962306a36Sopenharmony_ci edesc->pset_nr = nslots; 137062306a36Sopenharmony_ci edesc->residue = edesc->residue_stat = buf_len; 137162306a36Sopenharmony_ci edesc->direction = direction; 137262306a36Sopenharmony_ci edesc->echan = echan; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci dev_dbg(dev, "%s: channel=%d nslots=%d period_len=%zu buf_len=%zu\n", 137562306a36Sopenharmony_ci __func__, echan->ch_num, nslots, period_len, buf_len); 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_ci for (i = 0; i < nslots; i++) { 137862306a36Sopenharmony_ci /* Allocate a PaRAM slot, if needed */ 137962306a36Sopenharmony_ci if (echan->slot[i] < 0) { 138062306a36Sopenharmony_ci echan->slot[i] = 138162306a36Sopenharmony_ci edma_alloc_slot(echan->ecc, EDMA_SLOT_ANY); 138262306a36Sopenharmony_ci if (echan->slot[i] < 0) { 138362306a36Sopenharmony_ci kfree(edesc); 138462306a36Sopenharmony_ci dev_err(dev, "%s: Failed to allocate slot\n", 138562306a36Sopenharmony_ci __func__); 138662306a36Sopenharmony_ci return NULL; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci } 138962306a36Sopenharmony_ci 139062306a36Sopenharmony_ci if (i == nslots - 1) { 139162306a36Sopenharmony_ci memcpy(&edesc->pset[i], &edesc->pset[0], 139262306a36Sopenharmony_ci sizeof(edesc->pset[0])); 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci ret = edma_config_pset(chan, &edesc->pset[i], src_addr, 139762306a36Sopenharmony_ci dst_addr, burst, dev_width, period_len, 139862306a36Sopenharmony_ci direction); 139962306a36Sopenharmony_ci if (ret < 0) { 140062306a36Sopenharmony_ci kfree(edesc); 140162306a36Sopenharmony_ci return NULL; 140262306a36Sopenharmony_ci } 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci if (direction == DMA_DEV_TO_MEM) 140562306a36Sopenharmony_ci dst_addr += period_len; 140662306a36Sopenharmony_ci else 140762306a36Sopenharmony_ci src_addr += period_len; 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci dev_vdbg(dev, "%s: Configure period %d of buf:\n", __func__, i); 141062306a36Sopenharmony_ci dev_vdbg(dev, 141162306a36Sopenharmony_ci "\n pset[%d]:\n" 141262306a36Sopenharmony_ci " chnum\t%d\n" 141362306a36Sopenharmony_ci " slot\t%d\n" 141462306a36Sopenharmony_ci " opt\t%08x\n" 141562306a36Sopenharmony_ci " src\t%08x\n" 141662306a36Sopenharmony_ci " dst\t%08x\n" 141762306a36Sopenharmony_ci " abcnt\t%08x\n" 141862306a36Sopenharmony_ci " ccnt\t%08x\n" 141962306a36Sopenharmony_ci " bidx\t%08x\n" 142062306a36Sopenharmony_ci " cidx\t%08x\n" 142162306a36Sopenharmony_ci " lkrld\t%08x\n", 142262306a36Sopenharmony_ci i, echan->ch_num, echan->slot[i], 142362306a36Sopenharmony_ci edesc->pset[i].param.opt, 142462306a36Sopenharmony_ci edesc->pset[i].param.src, 142562306a36Sopenharmony_ci edesc->pset[i].param.dst, 142662306a36Sopenharmony_ci edesc->pset[i].param.a_b_cnt, 142762306a36Sopenharmony_ci edesc->pset[i].param.ccnt, 142862306a36Sopenharmony_ci edesc->pset[i].param.src_dst_bidx, 142962306a36Sopenharmony_ci edesc->pset[i].param.src_dst_cidx, 143062306a36Sopenharmony_ci edesc->pset[i].param.link_bcntrld); 143162306a36Sopenharmony_ci 143262306a36Sopenharmony_ci edesc->absync = ret; 143362306a36Sopenharmony_ci 143462306a36Sopenharmony_ci /* 143562306a36Sopenharmony_ci * Enable period interrupt only if it is requested 143662306a36Sopenharmony_ci */ 143762306a36Sopenharmony_ci if (tx_flags & DMA_PREP_INTERRUPT) { 143862306a36Sopenharmony_ci edesc->pset[i].param.opt |= TCINTEN; 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci /* Also enable intermediate interrupts if necessary */ 144162306a36Sopenharmony_ci if (use_intermediate) 144262306a36Sopenharmony_ci edesc->pset[i].param.opt |= ITCINTEN; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci /* Place the cyclic channel to highest priority queue */ 144762306a36Sopenharmony_ci if (!echan->tc) 144862306a36Sopenharmony_ci edma_assign_channel_eventq(echan, EVENTQ_0); 144962306a36Sopenharmony_ci 145062306a36Sopenharmony_ci return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags); 145162306a36Sopenharmony_ci} 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_cistatic void edma_completion_handler(struct edma_chan *echan) 145462306a36Sopenharmony_ci{ 145562306a36Sopenharmony_ci struct device *dev = echan->vchan.chan.device->dev; 145662306a36Sopenharmony_ci struct edma_desc *edesc; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci spin_lock(&echan->vchan.lock); 145962306a36Sopenharmony_ci edesc = echan->edesc; 146062306a36Sopenharmony_ci if (edesc) { 146162306a36Sopenharmony_ci if (edesc->cyclic) { 146262306a36Sopenharmony_ci vchan_cyclic_callback(&edesc->vdesc); 146362306a36Sopenharmony_ci spin_unlock(&echan->vchan.lock); 146462306a36Sopenharmony_ci return; 146562306a36Sopenharmony_ci } else if (edesc->processed == edesc->pset_nr) { 146662306a36Sopenharmony_ci edesc->residue = 0; 146762306a36Sopenharmony_ci edma_stop(echan); 146862306a36Sopenharmony_ci vchan_cookie_complete(&edesc->vdesc); 146962306a36Sopenharmony_ci echan->edesc = NULL; 147062306a36Sopenharmony_ci 147162306a36Sopenharmony_ci dev_dbg(dev, "Transfer completed on channel %d\n", 147262306a36Sopenharmony_ci echan->ch_num); 147362306a36Sopenharmony_ci } else { 147462306a36Sopenharmony_ci dev_dbg(dev, "Sub transfer completed on channel %d\n", 147562306a36Sopenharmony_ci echan->ch_num); 147662306a36Sopenharmony_ci 147762306a36Sopenharmony_ci edma_pause(echan); 147862306a36Sopenharmony_ci 147962306a36Sopenharmony_ci /* Update statistics for tx_status */ 148062306a36Sopenharmony_ci edesc->residue -= edesc->sg_len; 148162306a36Sopenharmony_ci edesc->residue_stat = edesc->residue; 148262306a36Sopenharmony_ci edesc->processed_stat = edesc->processed; 148362306a36Sopenharmony_ci } 148462306a36Sopenharmony_ci edma_execute(echan); 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci spin_unlock(&echan->vchan.lock); 148862306a36Sopenharmony_ci} 148962306a36Sopenharmony_ci 149062306a36Sopenharmony_ci/* eDMA interrupt handler */ 149162306a36Sopenharmony_cistatic irqreturn_t dma_irq_handler(int irq, void *data) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci struct edma_cc *ecc = data; 149462306a36Sopenharmony_ci int ctlr; 149562306a36Sopenharmony_ci u32 sh_ier; 149662306a36Sopenharmony_ci u32 sh_ipr; 149762306a36Sopenharmony_ci u32 bank; 149862306a36Sopenharmony_ci 149962306a36Sopenharmony_ci ctlr = ecc->id; 150062306a36Sopenharmony_ci if (ctlr < 0) 150162306a36Sopenharmony_ci return IRQ_NONE; 150262306a36Sopenharmony_ci 150362306a36Sopenharmony_ci dev_vdbg(ecc->dev, "dma_irq_handler\n"); 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_ci sh_ipr = edma_shadow0_read_array(ecc, SH_IPR, 0); 150662306a36Sopenharmony_ci if (!sh_ipr) { 150762306a36Sopenharmony_ci sh_ipr = edma_shadow0_read_array(ecc, SH_IPR, 1); 150862306a36Sopenharmony_ci if (!sh_ipr) 150962306a36Sopenharmony_ci return IRQ_NONE; 151062306a36Sopenharmony_ci sh_ier = edma_shadow0_read_array(ecc, SH_IER, 1); 151162306a36Sopenharmony_ci bank = 1; 151262306a36Sopenharmony_ci } else { 151362306a36Sopenharmony_ci sh_ier = edma_shadow0_read_array(ecc, SH_IER, 0); 151462306a36Sopenharmony_ci bank = 0; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci 151762306a36Sopenharmony_ci do { 151862306a36Sopenharmony_ci u32 slot; 151962306a36Sopenharmony_ci u32 channel; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci slot = __ffs(sh_ipr); 152262306a36Sopenharmony_ci sh_ipr &= ~(BIT(slot)); 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_ci if (sh_ier & BIT(slot)) { 152562306a36Sopenharmony_ci channel = (bank << 5) | slot; 152662306a36Sopenharmony_ci /* Clear the corresponding IPR bits */ 152762306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_ICR, bank, BIT(slot)); 152862306a36Sopenharmony_ci edma_completion_handler(&ecc->slave_chans[channel]); 152962306a36Sopenharmony_ci } 153062306a36Sopenharmony_ci } while (sh_ipr); 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_ci edma_shadow0_write(ecc, SH_IEVAL, 1); 153362306a36Sopenharmony_ci return IRQ_HANDLED; 153462306a36Sopenharmony_ci} 153562306a36Sopenharmony_ci 153662306a36Sopenharmony_cistatic void edma_error_handler(struct edma_chan *echan) 153762306a36Sopenharmony_ci{ 153862306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 153962306a36Sopenharmony_ci struct device *dev = echan->vchan.chan.device->dev; 154062306a36Sopenharmony_ci struct edmacc_param p; 154162306a36Sopenharmony_ci int err; 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (!echan->edesc) 154462306a36Sopenharmony_ci return; 154562306a36Sopenharmony_ci 154662306a36Sopenharmony_ci spin_lock(&echan->vchan.lock); 154762306a36Sopenharmony_ci 154862306a36Sopenharmony_ci err = edma_read_slot(ecc, echan->slot[0], &p); 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_ci /* 155162306a36Sopenharmony_ci * Issue later based on missed flag which will be sure 155262306a36Sopenharmony_ci * to happen as: 155362306a36Sopenharmony_ci * (1) we finished transmitting an intermediate slot and 155462306a36Sopenharmony_ci * edma_execute is coming up. 155562306a36Sopenharmony_ci * (2) or we finished current transfer and issue will 155662306a36Sopenharmony_ci * call edma_execute. 155762306a36Sopenharmony_ci * 155862306a36Sopenharmony_ci * Important note: issuing can be dangerous here and 155962306a36Sopenharmony_ci * lead to some nasty recursion when we are in a NULL 156062306a36Sopenharmony_ci * slot. So we avoid doing so and set the missed flag. 156162306a36Sopenharmony_ci */ 156262306a36Sopenharmony_ci if (err || (p.a_b_cnt == 0 && p.ccnt == 0)) { 156362306a36Sopenharmony_ci dev_dbg(dev, "Error on null slot, setting miss\n"); 156462306a36Sopenharmony_ci echan->missed = 1; 156562306a36Sopenharmony_ci } else { 156662306a36Sopenharmony_ci /* 156762306a36Sopenharmony_ci * The slot is already programmed but the event got 156862306a36Sopenharmony_ci * missed, so its safe to issue it here. 156962306a36Sopenharmony_ci */ 157062306a36Sopenharmony_ci dev_dbg(dev, "Missed event, TRIGGERING\n"); 157162306a36Sopenharmony_ci edma_clean_channel(echan); 157262306a36Sopenharmony_ci edma_stop(echan); 157362306a36Sopenharmony_ci edma_start(echan); 157462306a36Sopenharmony_ci edma_trigger_channel(echan); 157562306a36Sopenharmony_ci } 157662306a36Sopenharmony_ci spin_unlock(&echan->vchan.lock); 157762306a36Sopenharmony_ci} 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_cistatic inline bool edma_error_pending(struct edma_cc *ecc) 158062306a36Sopenharmony_ci{ 158162306a36Sopenharmony_ci if (edma_read_array(ecc, EDMA_EMR, 0) || 158262306a36Sopenharmony_ci edma_read_array(ecc, EDMA_EMR, 1) || 158362306a36Sopenharmony_ci edma_read(ecc, EDMA_QEMR) || edma_read(ecc, EDMA_CCERR)) 158462306a36Sopenharmony_ci return true; 158562306a36Sopenharmony_ci 158662306a36Sopenharmony_ci return false; 158762306a36Sopenharmony_ci} 158862306a36Sopenharmony_ci 158962306a36Sopenharmony_ci/* eDMA error interrupt handler */ 159062306a36Sopenharmony_cistatic irqreturn_t dma_ccerr_handler(int irq, void *data) 159162306a36Sopenharmony_ci{ 159262306a36Sopenharmony_ci struct edma_cc *ecc = data; 159362306a36Sopenharmony_ci int i, j; 159462306a36Sopenharmony_ci int ctlr; 159562306a36Sopenharmony_ci unsigned int cnt = 0; 159662306a36Sopenharmony_ci unsigned int val; 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci ctlr = ecc->id; 159962306a36Sopenharmony_ci if (ctlr < 0) 160062306a36Sopenharmony_ci return IRQ_NONE; 160162306a36Sopenharmony_ci 160262306a36Sopenharmony_ci dev_vdbg(ecc->dev, "dma_ccerr_handler\n"); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci if (!edma_error_pending(ecc)) { 160562306a36Sopenharmony_ci /* 160662306a36Sopenharmony_ci * The registers indicate no pending error event but the irq 160762306a36Sopenharmony_ci * handler has been called. 160862306a36Sopenharmony_ci * Ask eDMA to re-evaluate the error registers. 160962306a36Sopenharmony_ci */ 161062306a36Sopenharmony_ci dev_err(ecc->dev, "%s: Error interrupt without error event!\n", 161162306a36Sopenharmony_ci __func__); 161262306a36Sopenharmony_ci edma_write(ecc, EDMA_EEVAL, 1); 161362306a36Sopenharmony_ci return IRQ_NONE; 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci 161662306a36Sopenharmony_ci while (1) { 161762306a36Sopenharmony_ci /* Event missed register(s) */ 161862306a36Sopenharmony_ci for (j = 0; j < 2; j++) { 161962306a36Sopenharmony_ci unsigned long emr; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci val = edma_read_array(ecc, EDMA_EMR, j); 162262306a36Sopenharmony_ci if (!val) 162362306a36Sopenharmony_ci continue; 162462306a36Sopenharmony_ci 162562306a36Sopenharmony_ci dev_dbg(ecc->dev, "EMR%d 0x%08x\n", j, val); 162662306a36Sopenharmony_ci emr = val; 162762306a36Sopenharmony_ci for_each_set_bit(i, &emr, 32) { 162862306a36Sopenharmony_ci int k = (j << 5) + i; 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci /* Clear the corresponding EMR bits */ 163162306a36Sopenharmony_ci edma_write_array(ecc, EDMA_EMCR, j, BIT(i)); 163262306a36Sopenharmony_ci /* Clear any SER */ 163362306a36Sopenharmony_ci edma_shadow0_write_array(ecc, SH_SECR, j, 163462306a36Sopenharmony_ci BIT(i)); 163562306a36Sopenharmony_ci edma_error_handler(&ecc->slave_chans[k]); 163662306a36Sopenharmony_ci } 163762306a36Sopenharmony_ci } 163862306a36Sopenharmony_ci 163962306a36Sopenharmony_ci val = edma_read(ecc, EDMA_QEMR); 164062306a36Sopenharmony_ci if (val) { 164162306a36Sopenharmony_ci dev_dbg(ecc->dev, "QEMR 0x%02x\n", val); 164262306a36Sopenharmony_ci /* Not reported, just clear the interrupt reason. */ 164362306a36Sopenharmony_ci edma_write(ecc, EDMA_QEMCR, val); 164462306a36Sopenharmony_ci edma_shadow0_write(ecc, SH_QSECR, val); 164562306a36Sopenharmony_ci } 164662306a36Sopenharmony_ci 164762306a36Sopenharmony_ci val = edma_read(ecc, EDMA_CCERR); 164862306a36Sopenharmony_ci if (val) { 164962306a36Sopenharmony_ci dev_warn(ecc->dev, "CCERR 0x%08x\n", val); 165062306a36Sopenharmony_ci /* Not reported, just clear the interrupt reason. */ 165162306a36Sopenharmony_ci edma_write(ecc, EDMA_CCERRCLR, val); 165262306a36Sopenharmony_ci } 165362306a36Sopenharmony_ci 165462306a36Sopenharmony_ci if (!edma_error_pending(ecc)) 165562306a36Sopenharmony_ci break; 165662306a36Sopenharmony_ci cnt++; 165762306a36Sopenharmony_ci if (cnt > 10) 165862306a36Sopenharmony_ci break; 165962306a36Sopenharmony_ci } 166062306a36Sopenharmony_ci edma_write(ecc, EDMA_EEVAL, 1); 166162306a36Sopenharmony_ci return IRQ_HANDLED; 166262306a36Sopenharmony_ci} 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci/* Alloc channel resources */ 166562306a36Sopenharmony_cistatic int edma_alloc_chan_resources(struct dma_chan *chan) 166662306a36Sopenharmony_ci{ 166762306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 166862306a36Sopenharmony_ci struct edma_cc *ecc = echan->ecc; 166962306a36Sopenharmony_ci struct device *dev = ecc->dev; 167062306a36Sopenharmony_ci enum dma_event_q eventq_no = EVENTQ_DEFAULT; 167162306a36Sopenharmony_ci int ret; 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci if (echan->tc) { 167462306a36Sopenharmony_ci eventq_no = echan->tc->id; 167562306a36Sopenharmony_ci } else if (ecc->tc_list) { 167662306a36Sopenharmony_ci /* memcpy channel */ 167762306a36Sopenharmony_ci echan->tc = &ecc->tc_list[ecc->info->default_queue]; 167862306a36Sopenharmony_ci eventq_no = echan->tc->id; 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci 168162306a36Sopenharmony_ci ret = edma_alloc_channel(echan, eventq_no); 168262306a36Sopenharmony_ci if (ret) 168362306a36Sopenharmony_ci return ret; 168462306a36Sopenharmony_ci 168562306a36Sopenharmony_ci echan->slot[0] = edma_alloc_slot(ecc, echan->ch_num); 168662306a36Sopenharmony_ci if (echan->slot[0] < 0) { 168762306a36Sopenharmony_ci dev_err(dev, "Entry slot allocation failed for channel %u\n", 168862306a36Sopenharmony_ci EDMA_CHAN_SLOT(echan->ch_num)); 168962306a36Sopenharmony_ci ret = echan->slot[0]; 169062306a36Sopenharmony_ci goto err_slot; 169162306a36Sopenharmony_ci } 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_ci /* Set up channel -> slot mapping for the entry slot */ 169462306a36Sopenharmony_ci edma_set_chmap(echan, echan->slot[0]); 169562306a36Sopenharmony_ci echan->alloced = true; 169662306a36Sopenharmony_ci 169762306a36Sopenharmony_ci dev_dbg(dev, "Got eDMA channel %d for virt channel %d (%s trigger)\n", 169862306a36Sopenharmony_ci EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id, 169962306a36Sopenharmony_ci echan->hw_triggered ? "HW" : "SW"); 170062306a36Sopenharmony_ci 170162306a36Sopenharmony_ci return 0; 170262306a36Sopenharmony_ci 170362306a36Sopenharmony_cierr_slot: 170462306a36Sopenharmony_ci edma_free_channel(echan); 170562306a36Sopenharmony_ci return ret; 170662306a36Sopenharmony_ci} 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci/* Free channel resources */ 170962306a36Sopenharmony_cistatic void edma_free_chan_resources(struct dma_chan *chan) 171062306a36Sopenharmony_ci{ 171162306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 171262306a36Sopenharmony_ci struct device *dev = echan->ecc->dev; 171362306a36Sopenharmony_ci int i; 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci /* Terminate transfers */ 171662306a36Sopenharmony_ci edma_stop(echan); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci vchan_free_chan_resources(&echan->vchan); 171962306a36Sopenharmony_ci 172062306a36Sopenharmony_ci /* Free EDMA PaRAM slots */ 172162306a36Sopenharmony_ci for (i = 0; i < EDMA_MAX_SLOTS; i++) { 172262306a36Sopenharmony_ci if (echan->slot[i] >= 0) { 172362306a36Sopenharmony_ci edma_free_slot(echan->ecc, echan->slot[i]); 172462306a36Sopenharmony_ci echan->slot[i] = -1; 172562306a36Sopenharmony_ci } 172662306a36Sopenharmony_ci } 172762306a36Sopenharmony_ci 172862306a36Sopenharmony_ci /* Set entry slot to the dummy slot */ 172962306a36Sopenharmony_ci edma_set_chmap(echan, echan->ecc->dummy_slot); 173062306a36Sopenharmony_ci 173162306a36Sopenharmony_ci /* Free EDMA channel */ 173262306a36Sopenharmony_ci if (echan->alloced) { 173362306a36Sopenharmony_ci edma_free_channel(echan); 173462306a36Sopenharmony_ci echan->alloced = false; 173562306a36Sopenharmony_ci } 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci echan->tc = NULL; 173862306a36Sopenharmony_ci echan->hw_triggered = false; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci dev_dbg(dev, "Free eDMA channel %d for virt channel %d\n", 174162306a36Sopenharmony_ci EDMA_CHAN_SLOT(echan->ch_num), chan->chan_id); 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_ci/* Send pending descriptor to hardware */ 174562306a36Sopenharmony_cistatic void edma_issue_pending(struct dma_chan *chan) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 174862306a36Sopenharmony_ci unsigned long flags; 174962306a36Sopenharmony_ci 175062306a36Sopenharmony_ci spin_lock_irqsave(&echan->vchan.lock, flags); 175162306a36Sopenharmony_ci if (vchan_issue_pending(&echan->vchan) && !echan->edesc) 175262306a36Sopenharmony_ci edma_execute(echan); 175362306a36Sopenharmony_ci spin_unlock_irqrestore(&echan->vchan.lock, flags); 175462306a36Sopenharmony_ci} 175562306a36Sopenharmony_ci 175662306a36Sopenharmony_ci/* 175762306a36Sopenharmony_ci * This limit exists to avoid a possible infinite loop when waiting for proof 175862306a36Sopenharmony_ci * that a particular transfer is completed. This limit can be hit if there 175962306a36Sopenharmony_ci * are large bursts to/from slow devices or the CPU is never able to catch 176062306a36Sopenharmony_ci * the DMA hardware idle. On an AM335x transferring 48 bytes from the UART 176162306a36Sopenharmony_ci * RX-FIFO, as many as 55 loops have been seen. 176262306a36Sopenharmony_ci */ 176362306a36Sopenharmony_ci#define EDMA_MAX_TR_WAIT_LOOPS 1000 176462306a36Sopenharmony_ci 176562306a36Sopenharmony_cistatic u32 edma_residue(struct edma_desc *edesc) 176662306a36Sopenharmony_ci{ 176762306a36Sopenharmony_ci bool dst = edesc->direction == DMA_DEV_TO_MEM; 176862306a36Sopenharmony_ci int loop_count = EDMA_MAX_TR_WAIT_LOOPS; 176962306a36Sopenharmony_ci struct edma_chan *echan = edesc->echan; 177062306a36Sopenharmony_ci struct edma_pset *pset = edesc->pset; 177162306a36Sopenharmony_ci dma_addr_t done, pos, pos_old; 177262306a36Sopenharmony_ci int channel = EDMA_CHAN_SLOT(echan->ch_num); 177362306a36Sopenharmony_ci int idx = EDMA_REG_ARRAY_INDEX(channel); 177462306a36Sopenharmony_ci int ch_bit = EDMA_CHANNEL_BIT(channel); 177562306a36Sopenharmony_ci int event_reg; 177662306a36Sopenharmony_ci int i; 177762306a36Sopenharmony_ci 177862306a36Sopenharmony_ci /* 177962306a36Sopenharmony_ci * We always read the dst/src position from the first RamPar 178062306a36Sopenharmony_ci * pset. That's the one which is active now. 178162306a36Sopenharmony_ci */ 178262306a36Sopenharmony_ci pos = edma_get_position(echan->ecc, echan->slot[0], dst); 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci /* 178562306a36Sopenharmony_ci * "pos" may represent a transfer request that is still being 178662306a36Sopenharmony_ci * processed by the EDMACC or EDMATC. We will busy wait until 178762306a36Sopenharmony_ci * any one of the situations occurs: 178862306a36Sopenharmony_ci * 1. while and event is pending for the channel 178962306a36Sopenharmony_ci * 2. a position updated 179062306a36Sopenharmony_ci * 3. we hit the loop limit 179162306a36Sopenharmony_ci */ 179262306a36Sopenharmony_ci if (is_slave_direction(edesc->direction)) 179362306a36Sopenharmony_ci event_reg = SH_ER; 179462306a36Sopenharmony_ci else 179562306a36Sopenharmony_ci event_reg = SH_ESR; 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci pos_old = pos; 179862306a36Sopenharmony_ci while (edma_shadow0_read_array(echan->ecc, event_reg, idx) & ch_bit) { 179962306a36Sopenharmony_ci pos = edma_get_position(echan->ecc, echan->slot[0], dst); 180062306a36Sopenharmony_ci if (pos != pos_old) 180162306a36Sopenharmony_ci break; 180262306a36Sopenharmony_ci 180362306a36Sopenharmony_ci if (!--loop_count) { 180462306a36Sopenharmony_ci dev_dbg_ratelimited(echan->vchan.chan.device->dev, 180562306a36Sopenharmony_ci "%s: timeout waiting for PaRAM update\n", 180662306a36Sopenharmony_ci __func__); 180762306a36Sopenharmony_ci break; 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci cpu_relax(); 181162306a36Sopenharmony_ci } 181262306a36Sopenharmony_ci 181362306a36Sopenharmony_ci /* 181462306a36Sopenharmony_ci * Cyclic is simple. Just subtract pset[0].addr from pos. 181562306a36Sopenharmony_ci * 181662306a36Sopenharmony_ci * We never update edesc->residue in the cyclic case, so we 181762306a36Sopenharmony_ci * can tell the remaining room to the end of the circular 181862306a36Sopenharmony_ci * buffer. 181962306a36Sopenharmony_ci */ 182062306a36Sopenharmony_ci if (edesc->cyclic) { 182162306a36Sopenharmony_ci done = pos - pset->addr; 182262306a36Sopenharmony_ci edesc->residue_stat = edesc->residue - done; 182362306a36Sopenharmony_ci return edesc->residue_stat; 182462306a36Sopenharmony_ci } 182562306a36Sopenharmony_ci 182662306a36Sopenharmony_ci /* 182762306a36Sopenharmony_ci * If the position is 0, then EDMA loaded the closing dummy slot, the 182862306a36Sopenharmony_ci * transfer is completed 182962306a36Sopenharmony_ci */ 183062306a36Sopenharmony_ci if (!pos) 183162306a36Sopenharmony_ci return 0; 183262306a36Sopenharmony_ci /* 183362306a36Sopenharmony_ci * For SG operation we catch up with the last processed 183462306a36Sopenharmony_ci * status. 183562306a36Sopenharmony_ci */ 183662306a36Sopenharmony_ci pset += edesc->processed_stat; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci for (i = edesc->processed_stat; i < edesc->processed; i++, pset++) { 183962306a36Sopenharmony_ci /* 184062306a36Sopenharmony_ci * If we are inside this pset address range, we know 184162306a36Sopenharmony_ci * this is the active one. Get the current delta and 184262306a36Sopenharmony_ci * stop walking the psets. 184362306a36Sopenharmony_ci */ 184462306a36Sopenharmony_ci if (pos >= pset->addr && pos < pset->addr + pset->len) 184562306a36Sopenharmony_ci return edesc->residue_stat - (pos - pset->addr); 184662306a36Sopenharmony_ci 184762306a36Sopenharmony_ci /* Otherwise mark it done and update residue_stat. */ 184862306a36Sopenharmony_ci edesc->processed_stat++; 184962306a36Sopenharmony_ci edesc->residue_stat -= pset->len; 185062306a36Sopenharmony_ci } 185162306a36Sopenharmony_ci return edesc->residue_stat; 185262306a36Sopenharmony_ci} 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci/* Check request completion status */ 185562306a36Sopenharmony_cistatic enum dma_status edma_tx_status(struct dma_chan *chan, 185662306a36Sopenharmony_ci dma_cookie_t cookie, 185762306a36Sopenharmony_ci struct dma_tx_state *txstate) 185862306a36Sopenharmony_ci{ 185962306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 186062306a36Sopenharmony_ci struct dma_tx_state txstate_tmp; 186162306a36Sopenharmony_ci enum dma_status ret; 186262306a36Sopenharmony_ci unsigned long flags; 186362306a36Sopenharmony_ci 186462306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 186562306a36Sopenharmony_ci 186662306a36Sopenharmony_ci if (ret == DMA_COMPLETE) 186762306a36Sopenharmony_ci return ret; 186862306a36Sopenharmony_ci 186962306a36Sopenharmony_ci /* Provide a dummy dma_tx_state for completion checking */ 187062306a36Sopenharmony_ci if (!txstate) 187162306a36Sopenharmony_ci txstate = &txstate_tmp; 187262306a36Sopenharmony_ci 187362306a36Sopenharmony_ci spin_lock_irqsave(&echan->vchan.lock, flags); 187462306a36Sopenharmony_ci if (echan->edesc && echan->edesc->vdesc.tx.cookie == cookie) { 187562306a36Sopenharmony_ci txstate->residue = edma_residue(echan->edesc); 187662306a36Sopenharmony_ci } else { 187762306a36Sopenharmony_ci struct virt_dma_desc *vdesc = vchan_find_desc(&echan->vchan, 187862306a36Sopenharmony_ci cookie); 187962306a36Sopenharmony_ci 188062306a36Sopenharmony_ci if (vdesc) 188162306a36Sopenharmony_ci txstate->residue = to_edma_desc(&vdesc->tx)->residue; 188262306a36Sopenharmony_ci else 188362306a36Sopenharmony_ci txstate->residue = 0; 188462306a36Sopenharmony_ci } 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_ci /* 188762306a36Sopenharmony_ci * Mark the cookie completed if the residue is 0 for non cyclic 188862306a36Sopenharmony_ci * transfers 188962306a36Sopenharmony_ci */ 189062306a36Sopenharmony_ci if (ret != DMA_COMPLETE && !txstate->residue && 189162306a36Sopenharmony_ci echan->edesc && echan->edesc->polled && 189262306a36Sopenharmony_ci echan->edesc->vdesc.tx.cookie == cookie) { 189362306a36Sopenharmony_ci edma_stop(echan); 189462306a36Sopenharmony_ci vchan_cookie_complete(&echan->edesc->vdesc); 189562306a36Sopenharmony_ci echan->edesc = NULL; 189662306a36Sopenharmony_ci edma_execute(echan); 189762306a36Sopenharmony_ci ret = DMA_COMPLETE; 189862306a36Sopenharmony_ci } 189962306a36Sopenharmony_ci 190062306a36Sopenharmony_ci spin_unlock_irqrestore(&echan->vchan.lock, flags); 190162306a36Sopenharmony_ci 190262306a36Sopenharmony_ci return ret; 190362306a36Sopenharmony_ci} 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_cistatic bool edma_is_memcpy_channel(int ch_num, s32 *memcpy_channels) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci if (!memcpy_channels) 190862306a36Sopenharmony_ci return false; 190962306a36Sopenharmony_ci while (*memcpy_channels != -1) { 191062306a36Sopenharmony_ci if (*memcpy_channels == ch_num) 191162306a36Sopenharmony_ci return true; 191262306a36Sopenharmony_ci memcpy_channels++; 191362306a36Sopenharmony_ci } 191462306a36Sopenharmony_ci return false; 191562306a36Sopenharmony_ci} 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci#define EDMA_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ 191862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ 191962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ 192062306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) 192162306a36Sopenharmony_ci 192262306a36Sopenharmony_cistatic void edma_dma_init(struct edma_cc *ecc, bool legacy_mode) 192362306a36Sopenharmony_ci{ 192462306a36Sopenharmony_ci struct dma_device *s_ddev = &ecc->dma_slave; 192562306a36Sopenharmony_ci struct dma_device *m_ddev = NULL; 192662306a36Sopenharmony_ci s32 *memcpy_channels = ecc->info->memcpy_channels; 192762306a36Sopenharmony_ci int i, j; 192862306a36Sopenharmony_ci 192962306a36Sopenharmony_ci dma_cap_zero(s_ddev->cap_mask); 193062306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, s_ddev->cap_mask); 193162306a36Sopenharmony_ci dma_cap_set(DMA_CYCLIC, s_ddev->cap_mask); 193262306a36Sopenharmony_ci if (ecc->legacy_mode && !memcpy_channels) { 193362306a36Sopenharmony_ci dev_warn(ecc->dev, 193462306a36Sopenharmony_ci "Legacy memcpy is enabled, things might not work\n"); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, s_ddev->cap_mask); 193762306a36Sopenharmony_ci dma_cap_set(DMA_INTERLEAVE, s_ddev->cap_mask); 193862306a36Sopenharmony_ci s_ddev->device_prep_dma_memcpy = edma_prep_dma_memcpy; 193962306a36Sopenharmony_ci s_ddev->device_prep_interleaved_dma = edma_prep_dma_interleaved; 194062306a36Sopenharmony_ci s_ddev->directions = BIT(DMA_MEM_TO_MEM); 194162306a36Sopenharmony_ci } 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci s_ddev->device_prep_slave_sg = edma_prep_slave_sg; 194462306a36Sopenharmony_ci s_ddev->device_prep_dma_cyclic = edma_prep_dma_cyclic; 194562306a36Sopenharmony_ci s_ddev->device_alloc_chan_resources = edma_alloc_chan_resources; 194662306a36Sopenharmony_ci s_ddev->device_free_chan_resources = edma_free_chan_resources; 194762306a36Sopenharmony_ci s_ddev->device_issue_pending = edma_issue_pending; 194862306a36Sopenharmony_ci s_ddev->device_tx_status = edma_tx_status; 194962306a36Sopenharmony_ci s_ddev->device_config = edma_slave_config; 195062306a36Sopenharmony_ci s_ddev->device_pause = edma_dma_pause; 195162306a36Sopenharmony_ci s_ddev->device_resume = edma_dma_resume; 195262306a36Sopenharmony_ci s_ddev->device_terminate_all = edma_terminate_all; 195362306a36Sopenharmony_ci s_ddev->device_synchronize = edma_synchronize; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci s_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS; 195662306a36Sopenharmony_ci s_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS; 195762306a36Sopenharmony_ci s_ddev->directions |= (BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV)); 195862306a36Sopenharmony_ci s_ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 195962306a36Sopenharmony_ci s_ddev->max_burst = SZ_32K - 1; /* CIDX: 16bit signed */ 196062306a36Sopenharmony_ci 196162306a36Sopenharmony_ci s_ddev->dev = ecc->dev; 196262306a36Sopenharmony_ci INIT_LIST_HEAD(&s_ddev->channels); 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci if (memcpy_channels) { 196562306a36Sopenharmony_ci m_ddev = devm_kzalloc(ecc->dev, sizeof(*m_ddev), GFP_KERNEL); 196662306a36Sopenharmony_ci if (!m_ddev) { 196762306a36Sopenharmony_ci dev_warn(ecc->dev, "memcpy is disabled due to OoM\n"); 196862306a36Sopenharmony_ci memcpy_channels = NULL; 196962306a36Sopenharmony_ci goto ch_setup; 197062306a36Sopenharmony_ci } 197162306a36Sopenharmony_ci ecc->dma_memcpy = m_ddev; 197262306a36Sopenharmony_ci 197362306a36Sopenharmony_ci dma_cap_zero(m_ddev->cap_mask); 197462306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, m_ddev->cap_mask); 197562306a36Sopenharmony_ci dma_cap_set(DMA_INTERLEAVE, m_ddev->cap_mask); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci m_ddev->device_prep_dma_memcpy = edma_prep_dma_memcpy; 197862306a36Sopenharmony_ci m_ddev->device_prep_interleaved_dma = edma_prep_dma_interleaved; 197962306a36Sopenharmony_ci m_ddev->device_alloc_chan_resources = edma_alloc_chan_resources; 198062306a36Sopenharmony_ci m_ddev->device_free_chan_resources = edma_free_chan_resources; 198162306a36Sopenharmony_ci m_ddev->device_issue_pending = edma_issue_pending; 198262306a36Sopenharmony_ci m_ddev->device_tx_status = edma_tx_status; 198362306a36Sopenharmony_ci m_ddev->device_config = edma_slave_config; 198462306a36Sopenharmony_ci m_ddev->device_pause = edma_dma_pause; 198562306a36Sopenharmony_ci m_ddev->device_resume = edma_dma_resume; 198662306a36Sopenharmony_ci m_ddev->device_terminate_all = edma_terminate_all; 198762306a36Sopenharmony_ci m_ddev->device_synchronize = edma_synchronize; 198862306a36Sopenharmony_ci 198962306a36Sopenharmony_ci m_ddev->src_addr_widths = EDMA_DMA_BUSWIDTHS; 199062306a36Sopenharmony_ci m_ddev->dst_addr_widths = EDMA_DMA_BUSWIDTHS; 199162306a36Sopenharmony_ci m_ddev->directions = BIT(DMA_MEM_TO_MEM); 199262306a36Sopenharmony_ci m_ddev->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 199362306a36Sopenharmony_ci 199462306a36Sopenharmony_ci m_ddev->dev = ecc->dev; 199562306a36Sopenharmony_ci INIT_LIST_HEAD(&m_ddev->channels); 199662306a36Sopenharmony_ci } else if (!ecc->legacy_mode) { 199762306a36Sopenharmony_ci dev_info(ecc->dev, "memcpy is disabled\n"); 199862306a36Sopenharmony_ci } 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cich_setup: 200162306a36Sopenharmony_ci for (i = 0; i < ecc->num_channels; i++) { 200262306a36Sopenharmony_ci struct edma_chan *echan = &ecc->slave_chans[i]; 200362306a36Sopenharmony_ci echan->ch_num = EDMA_CTLR_CHAN(ecc->id, i); 200462306a36Sopenharmony_ci echan->ecc = ecc; 200562306a36Sopenharmony_ci echan->vchan.desc_free = edma_desc_free; 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci if (m_ddev && edma_is_memcpy_channel(i, memcpy_channels)) 200862306a36Sopenharmony_ci vchan_init(&echan->vchan, m_ddev); 200962306a36Sopenharmony_ci else 201062306a36Sopenharmony_ci vchan_init(&echan->vchan, s_ddev); 201162306a36Sopenharmony_ci 201262306a36Sopenharmony_ci INIT_LIST_HEAD(&echan->node); 201362306a36Sopenharmony_ci for (j = 0; j < EDMA_MAX_SLOTS; j++) 201462306a36Sopenharmony_ci echan->slot[j] = -1; 201562306a36Sopenharmony_ci } 201662306a36Sopenharmony_ci} 201762306a36Sopenharmony_ci 201862306a36Sopenharmony_cistatic int edma_setup_from_hw(struct device *dev, struct edma_soc_info *pdata, 201962306a36Sopenharmony_ci struct edma_cc *ecc) 202062306a36Sopenharmony_ci{ 202162306a36Sopenharmony_ci int i; 202262306a36Sopenharmony_ci u32 value, cccfg; 202362306a36Sopenharmony_ci s8 (*queue_priority_map)[2]; 202462306a36Sopenharmony_ci 202562306a36Sopenharmony_ci /* Decode the eDMA3 configuration from CCCFG register */ 202662306a36Sopenharmony_ci cccfg = edma_read(ecc, EDMA_CCCFG); 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci value = GET_NUM_REGN(cccfg); 202962306a36Sopenharmony_ci ecc->num_region = BIT(value); 203062306a36Sopenharmony_ci 203162306a36Sopenharmony_ci value = GET_NUM_DMACH(cccfg); 203262306a36Sopenharmony_ci ecc->num_channels = BIT(value + 1); 203362306a36Sopenharmony_ci 203462306a36Sopenharmony_ci value = GET_NUM_QDMACH(cccfg); 203562306a36Sopenharmony_ci ecc->num_qchannels = value * 2; 203662306a36Sopenharmony_ci 203762306a36Sopenharmony_ci value = GET_NUM_PAENTRY(cccfg); 203862306a36Sopenharmony_ci ecc->num_slots = BIT(value + 4); 203962306a36Sopenharmony_ci 204062306a36Sopenharmony_ci value = GET_NUM_EVQUE(cccfg); 204162306a36Sopenharmony_ci ecc->num_tc = value + 1; 204262306a36Sopenharmony_ci 204362306a36Sopenharmony_ci ecc->chmap_exist = (cccfg & CHMAP_EXIST) ? true : false; 204462306a36Sopenharmony_ci 204562306a36Sopenharmony_ci dev_dbg(dev, "eDMA3 CC HW configuration (cccfg: 0x%08x):\n", cccfg); 204662306a36Sopenharmony_ci dev_dbg(dev, "num_region: %u\n", ecc->num_region); 204762306a36Sopenharmony_ci dev_dbg(dev, "num_channels: %u\n", ecc->num_channels); 204862306a36Sopenharmony_ci dev_dbg(dev, "num_qchannels: %u\n", ecc->num_qchannels); 204962306a36Sopenharmony_ci dev_dbg(dev, "num_slots: %u\n", ecc->num_slots); 205062306a36Sopenharmony_ci dev_dbg(dev, "num_tc: %u\n", ecc->num_tc); 205162306a36Sopenharmony_ci dev_dbg(dev, "chmap_exist: %s\n", ecc->chmap_exist ? "yes" : "no"); 205262306a36Sopenharmony_ci 205362306a36Sopenharmony_ci /* Nothing need to be done if queue priority is provided */ 205462306a36Sopenharmony_ci if (pdata->queue_priority_mapping) 205562306a36Sopenharmony_ci return 0; 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci /* 205862306a36Sopenharmony_ci * Configure TC/queue priority as follows: 205962306a36Sopenharmony_ci * Q0 - priority 0 206062306a36Sopenharmony_ci * Q1 - priority 1 206162306a36Sopenharmony_ci * Q2 - priority 2 206262306a36Sopenharmony_ci * ... 206362306a36Sopenharmony_ci * The meaning of priority numbers: 0 highest priority, 7 lowest 206462306a36Sopenharmony_ci * priority. So Q0 is the highest priority queue and the last queue has 206562306a36Sopenharmony_ci * the lowest priority. 206662306a36Sopenharmony_ci */ 206762306a36Sopenharmony_ci queue_priority_map = devm_kcalloc(dev, ecc->num_tc + 1, sizeof(s8), 206862306a36Sopenharmony_ci GFP_KERNEL); 206962306a36Sopenharmony_ci if (!queue_priority_map) 207062306a36Sopenharmony_ci return -ENOMEM; 207162306a36Sopenharmony_ci 207262306a36Sopenharmony_ci for (i = 0; i < ecc->num_tc; i++) { 207362306a36Sopenharmony_ci queue_priority_map[i][0] = i; 207462306a36Sopenharmony_ci queue_priority_map[i][1] = i; 207562306a36Sopenharmony_ci } 207662306a36Sopenharmony_ci queue_priority_map[i][0] = -1; 207762306a36Sopenharmony_ci queue_priority_map[i][1] = -1; 207862306a36Sopenharmony_ci 207962306a36Sopenharmony_ci pdata->queue_priority_mapping = queue_priority_map; 208062306a36Sopenharmony_ci /* Default queue has the lowest priority */ 208162306a36Sopenharmony_ci pdata->default_queue = i - 1; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci return 0; 208462306a36Sopenharmony_ci} 208562306a36Sopenharmony_ci 208662306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_OF) 208762306a36Sopenharmony_cistatic int edma_xbar_event_map(struct device *dev, struct edma_soc_info *pdata, 208862306a36Sopenharmony_ci size_t sz) 208962306a36Sopenharmony_ci{ 209062306a36Sopenharmony_ci const char pname[] = "ti,edma-xbar-event-map"; 209162306a36Sopenharmony_ci struct resource res; 209262306a36Sopenharmony_ci void __iomem *xbar; 209362306a36Sopenharmony_ci s16 (*xbar_chans)[2]; 209462306a36Sopenharmony_ci size_t nelm = sz / sizeof(s16); 209562306a36Sopenharmony_ci u32 shift, offset, mux; 209662306a36Sopenharmony_ci int ret, i; 209762306a36Sopenharmony_ci 209862306a36Sopenharmony_ci xbar_chans = devm_kcalloc(dev, nelm + 2, sizeof(s16), GFP_KERNEL); 209962306a36Sopenharmony_ci if (!xbar_chans) 210062306a36Sopenharmony_ci return -ENOMEM; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci ret = of_address_to_resource(dev->of_node, 1, &res); 210362306a36Sopenharmony_ci if (ret) 210462306a36Sopenharmony_ci return -ENOMEM; 210562306a36Sopenharmony_ci 210662306a36Sopenharmony_ci xbar = devm_ioremap(dev, res.start, resource_size(&res)); 210762306a36Sopenharmony_ci if (!xbar) 210862306a36Sopenharmony_ci return -ENOMEM; 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_ci ret = of_property_read_u16_array(dev->of_node, pname, (u16 *)xbar_chans, 211162306a36Sopenharmony_ci nelm); 211262306a36Sopenharmony_ci if (ret) 211362306a36Sopenharmony_ci return -EIO; 211462306a36Sopenharmony_ci 211562306a36Sopenharmony_ci /* Invalidate last entry for the other user of this mess */ 211662306a36Sopenharmony_ci nelm >>= 1; 211762306a36Sopenharmony_ci xbar_chans[nelm][0] = -1; 211862306a36Sopenharmony_ci xbar_chans[nelm][1] = -1; 211962306a36Sopenharmony_ci 212062306a36Sopenharmony_ci for (i = 0; i < nelm; i++) { 212162306a36Sopenharmony_ci shift = (xbar_chans[i][1] & 0x03) << 3; 212262306a36Sopenharmony_ci offset = xbar_chans[i][1] & 0xfffffffc; 212362306a36Sopenharmony_ci mux = readl(xbar + offset); 212462306a36Sopenharmony_ci mux &= ~(0xff << shift); 212562306a36Sopenharmony_ci mux |= xbar_chans[i][0] << shift; 212662306a36Sopenharmony_ci writel(mux, (xbar + offset)); 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci pdata->xbar_chans = (const s16 (*)[2]) xbar_chans; 213062306a36Sopenharmony_ci return 0; 213162306a36Sopenharmony_ci} 213262306a36Sopenharmony_ci 213362306a36Sopenharmony_cistatic struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, 213462306a36Sopenharmony_ci bool legacy_mode) 213562306a36Sopenharmony_ci{ 213662306a36Sopenharmony_ci struct edma_soc_info *info; 213762306a36Sopenharmony_ci struct property *prop; 213862306a36Sopenharmony_ci int sz, ret; 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci info = devm_kzalloc(dev, sizeof(struct edma_soc_info), GFP_KERNEL); 214162306a36Sopenharmony_ci if (!info) 214262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci if (legacy_mode) { 214562306a36Sopenharmony_ci prop = of_find_property(dev->of_node, "ti,edma-xbar-event-map", 214662306a36Sopenharmony_ci &sz); 214762306a36Sopenharmony_ci if (prop) { 214862306a36Sopenharmony_ci ret = edma_xbar_event_map(dev, info, sz); 214962306a36Sopenharmony_ci if (ret) 215062306a36Sopenharmony_ci return ERR_PTR(ret); 215162306a36Sopenharmony_ci } 215262306a36Sopenharmony_ci return info; 215362306a36Sopenharmony_ci } 215462306a36Sopenharmony_ci 215562306a36Sopenharmony_ci /* Get the list of channels allocated to be used for memcpy */ 215662306a36Sopenharmony_ci prop = of_find_property(dev->of_node, "ti,edma-memcpy-channels", &sz); 215762306a36Sopenharmony_ci if (prop) { 215862306a36Sopenharmony_ci const char pname[] = "ti,edma-memcpy-channels"; 215962306a36Sopenharmony_ci size_t nelm = sz / sizeof(s32); 216062306a36Sopenharmony_ci s32 *memcpy_ch; 216162306a36Sopenharmony_ci 216262306a36Sopenharmony_ci memcpy_ch = devm_kcalloc(dev, nelm + 1, sizeof(s32), 216362306a36Sopenharmony_ci GFP_KERNEL); 216462306a36Sopenharmony_ci if (!memcpy_ch) 216562306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci ret = of_property_read_u32_array(dev->of_node, pname, 216862306a36Sopenharmony_ci (u32 *)memcpy_ch, nelm); 216962306a36Sopenharmony_ci if (ret) 217062306a36Sopenharmony_ci return ERR_PTR(ret); 217162306a36Sopenharmony_ci 217262306a36Sopenharmony_ci memcpy_ch[nelm] = -1; 217362306a36Sopenharmony_ci info->memcpy_channels = memcpy_ch; 217462306a36Sopenharmony_ci } 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_ci prop = of_find_property(dev->of_node, "ti,edma-reserved-slot-ranges", 217762306a36Sopenharmony_ci &sz); 217862306a36Sopenharmony_ci if (prop) { 217962306a36Sopenharmony_ci const char pname[] = "ti,edma-reserved-slot-ranges"; 218062306a36Sopenharmony_ci u32 (*tmp)[2]; 218162306a36Sopenharmony_ci s16 (*rsv_slots)[2]; 218262306a36Sopenharmony_ci size_t nelm = sz / sizeof(*tmp); 218362306a36Sopenharmony_ci struct edma_rsv_info *rsv_info; 218462306a36Sopenharmony_ci int i; 218562306a36Sopenharmony_ci 218662306a36Sopenharmony_ci if (!nelm) 218762306a36Sopenharmony_ci return info; 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci tmp = kcalloc(nelm, sizeof(*tmp), GFP_KERNEL); 219062306a36Sopenharmony_ci if (!tmp) 219162306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 219262306a36Sopenharmony_ci 219362306a36Sopenharmony_ci rsv_info = devm_kzalloc(dev, sizeof(*rsv_info), GFP_KERNEL); 219462306a36Sopenharmony_ci if (!rsv_info) { 219562306a36Sopenharmony_ci kfree(tmp); 219662306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 219762306a36Sopenharmony_ci } 219862306a36Sopenharmony_ci 219962306a36Sopenharmony_ci rsv_slots = devm_kcalloc(dev, nelm + 1, sizeof(*rsv_slots), 220062306a36Sopenharmony_ci GFP_KERNEL); 220162306a36Sopenharmony_ci if (!rsv_slots) { 220262306a36Sopenharmony_ci kfree(tmp); 220362306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 220462306a36Sopenharmony_ci } 220562306a36Sopenharmony_ci 220662306a36Sopenharmony_ci ret = of_property_read_u32_array(dev->of_node, pname, 220762306a36Sopenharmony_ci (u32 *)tmp, nelm * 2); 220862306a36Sopenharmony_ci if (ret) { 220962306a36Sopenharmony_ci kfree(tmp); 221062306a36Sopenharmony_ci return ERR_PTR(ret); 221162306a36Sopenharmony_ci } 221262306a36Sopenharmony_ci 221362306a36Sopenharmony_ci for (i = 0; i < nelm; i++) { 221462306a36Sopenharmony_ci rsv_slots[i][0] = tmp[i][0]; 221562306a36Sopenharmony_ci rsv_slots[i][1] = tmp[i][1]; 221662306a36Sopenharmony_ci } 221762306a36Sopenharmony_ci rsv_slots[nelm][0] = -1; 221862306a36Sopenharmony_ci rsv_slots[nelm][1] = -1; 221962306a36Sopenharmony_ci 222062306a36Sopenharmony_ci info->rsv = rsv_info; 222162306a36Sopenharmony_ci info->rsv->rsv_slots = (const s16 (*)[2])rsv_slots; 222262306a36Sopenharmony_ci 222362306a36Sopenharmony_ci kfree(tmp); 222462306a36Sopenharmony_ci } 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci return info; 222762306a36Sopenharmony_ci} 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_cistatic struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec, 223062306a36Sopenharmony_ci struct of_dma *ofdma) 223162306a36Sopenharmony_ci{ 223262306a36Sopenharmony_ci struct edma_cc *ecc = ofdma->of_dma_data; 223362306a36Sopenharmony_ci struct dma_chan *chan = NULL; 223462306a36Sopenharmony_ci struct edma_chan *echan; 223562306a36Sopenharmony_ci int i; 223662306a36Sopenharmony_ci 223762306a36Sopenharmony_ci if (!ecc || dma_spec->args_count < 1) 223862306a36Sopenharmony_ci return NULL; 223962306a36Sopenharmony_ci 224062306a36Sopenharmony_ci for (i = 0; i < ecc->num_channels; i++) { 224162306a36Sopenharmony_ci echan = &ecc->slave_chans[i]; 224262306a36Sopenharmony_ci if (echan->ch_num == dma_spec->args[0]) { 224362306a36Sopenharmony_ci chan = &echan->vchan.chan; 224462306a36Sopenharmony_ci break; 224562306a36Sopenharmony_ci } 224662306a36Sopenharmony_ci } 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci if (!chan) 224962306a36Sopenharmony_ci return NULL; 225062306a36Sopenharmony_ci 225162306a36Sopenharmony_ci if (echan->ecc->legacy_mode && dma_spec->args_count == 1) 225262306a36Sopenharmony_ci goto out; 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci if (!echan->ecc->legacy_mode && dma_spec->args_count == 2 && 225562306a36Sopenharmony_ci dma_spec->args[1] < echan->ecc->num_tc) { 225662306a36Sopenharmony_ci echan->tc = &echan->ecc->tc_list[dma_spec->args[1]]; 225762306a36Sopenharmony_ci goto out; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci return NULL; 226162306a36Sopenharmony_ciout: 226262306a36Sopenharmony_ci /* The channel is going to be used as HW synchronized */ 226362306a36Sopenharmony_ci echan->hw_triggered = true; 226462306a36Sopenharmony_ci return dma_get_slave_channel(chan); 226562306a36Sopenharmony_ci} 226662306a36Sopenharmony_ci#else 226762306a36Sopenharmony_cistatic struct edma_soc_info *edma_setup_info_from_dt(struct device *dev, 226862306a36Sopenharmony_ci bool legacy_mode) 226962306a36Sopenharmony_ci{ 227062306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 227162306a36Sopenharmony_ci} 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_cistatic struct dma_chan *of_edma_xlate(struct of_phandle_args *dma_spec, 227462306a36Sopenharmony_ci struct of_dma *ofdma) 227562306a36Sopenharmony_ci{ 227662306a36Sopenharmony_ci return NULL; 227762306a36Sopenharmony_ci} 227862306a36Sopenharmony_ci#endif 227962306a36Sopenharmony_ci 228062306a36Sopenharmony_cistatic bool edma_filter_fn(struct dma_chan *chan, void *param); 228162306a36Sopenharmony_ci 228262306a36Sopenharmony_cistatic int edma_probe(struct platform_device *pdev) 228362306a36Sopenharmony_ci{ 228462306a36Sopenharmony_ci struct edma_soc_info *info = pdev->dev.platform_data; 228562306a36Sopenharmony_ci s8 (*queue_priority_mapping)[2]; 228662306a36Sopenharmony_ci const s16 (*reserved)[2]; 228762306a36Sopenharmony_ci int i, irq; 228862306a36Sopenharmony_ci char *irq_name; 228962306a36Sopenharmony_ci struct resource *mem; 229062306a36Sopenharmony_ci struct device_node *node = pdev->dev.of_node; 229162306a36Sopenharmony_ci struct device *dev = &pdev->dev; 229262306a36Sopenharmony_ci struct edma_cc *ecc; 229362306a36Sopenharmony_ci bool legacy_mode = true; 229462306a36Sopenharmony_ci int ret; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci if (node) { 229762306a36Sopenharmony_ci const struct of_device_id *match; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci match = of_match_node(edma_of_ids, node); 230062306a36Sopenharmony_ci if (match && (*(u32 *)match->data) == EDMA_BINDING_TPCC) 230162306a36Sopenharmony_ci legacy_mode = false; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ci info = edma_setup_info_from_dt(dev, legacy_mode); 230462306a36Sopenharmony_ci if (IS_ERR(info)) { 230562306a36Sopenharmony_ci dev_err(dev, "failed to get DT data\n"); 230662306a36Sopenharmony_ci return PTR_ERR(info); 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci } 230962306a36Sopenharmony_ci 231062306a36Sopenharmony_ci if (!info) 231162306a36Sopenharmony_ci return -ENODEV; 231262306a36Sopenharmony_ci 231362306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32)); 231462306a36Sopenharmony_ci if (ret) 231562306a36Sopenharmony_ci return ret; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci ecc = devm_kzalloc(dev, sizeof(*ecc), GFP_KERNEL); 231862306a36Sopenharmony_ci if (!ecc) 231962306a36Sopenharmony_ci return -ENOMEM; 232062306a36Sopenharmony_ci 232162306a36Sopenharmony_ci ecc->dev = dev; 232262306a36Sopenharmony_ci ecc->id = pdev->id; 232362306a36Sopenharmony_ci ecc->legacy_mode = legacy_mode; 232462306a36Sopenharmony_ci /* When booting with DT the pdev->id is -1 */ 232562306a36Sopenharmony_ci if (ecc->id < 0) 232662306a36Sopenharmony_ci ecc->id = 0; 232762306a36Sopenharmony_ci 232862306a36Sopenharmony_ci mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, "edma3_cc"); 232962306a36Sopenharmony_ci if (!mem) { 233062306a36Sopenharmony_ci dev_dbg(dev, "mem resource not found, using index 0\n"); 233162306a36Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); 233262306a36Sopenharmony_ci if (!mem) { 233362306a36Sopenharmony_ci dev_err(dev, "no mem resource?\n"); 233462306a36Sopenharmony_ci return -ENODEV; 233562306a36Sopenharmony_ci } 233662306a36Sopenharmony_ci } 233762306a36Sopenharmony_ci ecc->base = devm_ioremap_resource(dev, mem); 233862306a36Sopenharmony_ci if (IS_ERR(ecc->base)) 233962306a36Sopenharmony_ci return PTR_ERR(ecc->base); 234062306a36Sopenharmony_ci 234162306a36Sopenharmony_ci platform_set_drvdata(pdev, ecc); 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci pm_runtime_enable(dev); 234462306a36Sopenharmony_ci ret = pm_runtime_get_sync(dev); 234562306a36Sopenharmony_ci if (ret < 0) { 234662306a36Sopenharmony_ci dev_err(dev, "pm_runtime_get_sync() failed\n"); 234762306a36Sopenharmony_ci pm_runtime_disable(dev); 234862306a36Sopenharmony_ci return ret; 234962306a36Sopenharmony_ci } 235062306a36Sopenharmony_ci 235162306a36Sopenharmony_ci /* Get eDMA3 configuration from IP */ 235262306a36Sopenharmony_ci ret = edma_setup_from_hw(dev, info, ecc); 235362306a36Sopenharmony_ci if (ret) 235462306a36Sopenharmony_ci goto err_disable_pm; 235562306a36Sopenharmony_ci 235662306a36Sopenharmony_ci /* Allocate memory based on the information we got from the IP */ 235762306a36Sopenharmony_ci ecc->slave_chans = devm_kcalloc(dev, ecc->num_channels, 235862306a36Sopenharmony_ci sizeof(*ecc->slave_chans), GFP_KERNEL); 235962306a36Sopenharmony_ci 236062306a36Sopenharmony_ci ecc->slot_inuse = devm_kcalloc(dev, BITS_TO_LONGS(ecc->num_slots), 236162306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 236262306a36Sopenharmony_ci 236362306a36Sopenharmony_ci ecc->channels_mask = devm_kcalloc(dev, 236462306a36Sopenharmony_ci BITS_TO_LONGS(ecc->num_channels), 236562306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 236662306a36Sopenharmony_ci if (!ecc->slave_chans || !ecc->slot_inuse || !ecc->channels_mask) { 236762306a36Sopenharmony_ci ret = -ENOMEM; 236862306a36Sopenharmony_ci goto err_disable_pm; 236962306a36Sopenharmony_ci } 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci /* Mark all channels available initially */ 237262306a36Sopenharmony_ci bitmap_fill(ecc->channels_mask, ecc->num_channels); 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_ci ecc->default_queue = info->default_queue; 237562306a36Sopenharmony_ci 237662306a36Sopenharmony_ci if (info->rsv) { 237762306a36Sopenharmony_ci /* Set the reserved slots in inuse list */ 237862306a36Sopenharmony_ci reserved = info->rsv->rsv_slots; 237962306a36Sopenharmony_ci if (reserved) { 238062306a36Sopenharmony_ci for (i = 0; reserved[i][0] != -1; i++) 238162306a36Sopenharmony_ci bitmap_set(ecc->slot_inuse, reserved[i][0], 238262306a36Sopenharmony_ci reserved[i][1]); 238362306a36Sopenharmony_ci } 238462306a36Sopenharmony_ci 238562306a36Sopenharmony_ci /* Clear channels not usable for Linux */ 238662306a36Sopenharmony_ci reserved = info->rsv->rsv_chans; 238762306a36Sopenharmony_ci if (reserved) { 238862306a36Sopenharmony_ci for (i = 0; reserved[i][0] != -1; i++) 238962306a36Sopenharmony_ci bitmap_clear(ecc->channels_mask, reserved[i][0], 239062306a36Sopenharmony_ci reserved[i][1]); 239162306a36Sopenharmony_ci } 239262306a36Sopenharmony_ci } 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ci for (i = 0; i < ecc->num_slots; i++) { 239562306a36Sopenharmony_ci /* Reset only unused - not reserved - paRAM slots */ 239662306a36Sopenharmony_ci if (!test_bit(i, ecc->slot_inuse)) 239762306a36Sopenharmony_ci edma_write_slot(ecc, i, &dummy_paramset); 239862306a36Sopenharmony_ci } 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, "edma3_ccint"); 240162306a36Sopenharmony_ci if (irq < 0 && node) 240262306a36Sopenharmony_ci irq = irq_of_parse_and_map(node, 0); 240362306a36Sopenharmony_ci 240462306a36Sopenharmony_ci if (irq > 0) { 240562306a36Sopenharmony_ci irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccint", 240662306a36Sopenharmony_ci dev_name(dev)); 240762306a36Sopenharmony_ci if (!irq_name) { 240862306a36Sopenharmony_ci ret = -ENOMEM; 240962306a36Sopenharmony_ci goto err_disable_pm; 241062306a36Sopenharmony_ci } 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, dma_irq_handler, 0, irq_name, 241362306a36Sopenharmony_ci ecc); 241462306a36Sopenharmony_ci if (ret) { 241562306a36Sopenharmony_ci dev_err(dev, "CCINT (%d) failed --> %d\n", irq, ret); 241662306a36Sopenharmony_ci goto err_disable_pm; 241762306a36Sopenharmony_ci } 241862306a36Sopenharmony_ci ecc->ccint = irq; 241962306a36Sopenharmony_ci } 242062306a36Sopenharmony_ci 242162306a36Sopenharmony_ci irq = platform_get_irq_byname(pdev, "edma3_ccerrint"); 242262306a36Sopenharmony_ci if (irq < 0 && node) 242362306a36Sopenharmony_ci irq = irq_of_parse_and_map(node, 2); 242462306a36Sopenharmony_ci 242562306a36Sopenharmony_ci if (irq > 0) { 242662306a36Sopenharmony_ci irq_name = devm_kasprintf(dev, GFP_KERNEL, "%s_ccerrint", 242762306a36Sopenharmony_ci dev_name(dev)); 242862306a36Sopenharmony_ci if (!irq_name) { 242962306a36Sopenharmony_ci ret = -ENOMEM; 243062306a36Sopenharmony_ci goto err_disable_pm; 243162306a36Sopenharmony_ci } 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci ret = devm_request_irq(dev, irq, dma_ccerr_handler, 0, irq_name, 243462306a36Sopenharmony_ci ecc); 243562306a36Sopenharmony_ci if (ret) { 243662306a36Sopenharmony_ci dev_err(dev, "CCERRINT (%d) failed --> %d\n", irq, ret); 243762306a36Sopenharmony_ci goto err_disable_pm; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci ecc->ccerrint = irq; 244062306a36Sopenharmony_ci } 244162306a36Sopenharmony_ci 244262306a36Sopenharmony_ci ecc->dummy_slot = edma_alloc_slot(ecc, EDMA_SLOT_ANY); 244362306a36Sopenharmony_ci if (ecc->dummy_slot < 0) { 244462306a36Sopenharmony_ci dev_err(dev, "Can't allocate PaRAM dummy slot\n"); 244562306a36Sopenharmony_ci ret = ecc->dummy_slot; 244662306a36Sopenharmony_ci goto err_disable_pm; 244762306a36Sopenharmony_ci } 244862306a36Sopenharmony_ci 244962306a36Sopenharmony_ci queue_priority_mapping = info->queue_priority_mapping; 245062306a36Sopenharmony_ci 245162306a36Sopenharmony_ci if (!ecc->legacy_mode) { 245262306a36Sopenharmony_ci int lowest_priority = 0; 245362306a36Sopenharmony_ci unsigned int array_max; 245462306a36Sopenharmony_ci struct of_phandle_args tc_args; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci ecc->tc_list = devm_kcalloc(dev, ecc->num_tc, 245762306a36Sopenharmony_ci sizeof(*ecc->tc_list), GFP_KERNEL); 245862306a36Sopenharmony_ci if (!ecc->tc_list) { 245962306a36Sopenharmony_ci ret = -ENOMEM; 246062306a36Sopenharmony_ci goto err_reg1; 246162306a36Sopenharmony_ci } 246262306a36Sopenharmony_ci 246362306a36Sopenharmony_ci for (i = 0;; i++) { 246462306a36Sopenharmony_ci ret = of_parse_phandle_with_fixed_args(node, "ti,tptcs", 246562306a36Sopenharmony_ci 1, i, &tc_args); 246662306a36Sopenharmony_ci if (ret || i == ecc->num_tc) 246762306a36Sopenharmony_ci break; 246862306a36Sopenharmony_ci 246962306a36Sopenharmony_ci ecc->tc_list[i].node = tc_args.np; 247062306a36Sopenharmony_ci ecc->tc_list[i].id = i; 247162306a36Sopenharmony_ci queue_priority_mapping[i][1] = tc_args.args[0]; 247262306a36Sopenharmony_ci if (queue_priority_mapping[i][1] > lowest_priority) { 247362306a36Sopenharmony_ci lowest_priority = queue_priority_mapping[i][1]; 247462306a36Sopenharmony_ci info->default_queue = i; 247562306a36Sopenharmony_ci } 247662306a36Sopenharmony_ci } 247762306a36Sopenharmony_ci 247862306a36Sopenharmony_ci /* See if we have optional dma-channel-mask array */ 247962306a36Sopenharmony_ci array_max = DIV_ROUND_UP(ecc->num_channels, BITS_PER_TYPE(u32)); 248062306a36Sopenharmony_ci ret = of_property_read_variable_u32_array(node, 248162306a36Sopenharmony_ci "dma-channel-mask", 248262306a36Sopenharmony_ci (u32 *)ecc->channels_mask, 248362306a36Sopenharmony_ci 1, array_max); 248462306a36Sopenharmony_ci if (ret > 0 && ret != array_max) 248562306a36Sopenharmony_ci dev_warn(dev, "dma-channel-mask is not complete.\n"); 248662306a36Sopenharmony_ci else if (ret == -EOVERFLOW || ret == -ENODATA) 248762306a36Sopenharmony_ci dev_warn(dev, 248862306a36Sopenharmony_ci "dma-channel-mask is out of range or empty\n"); 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci /* Event queue priority mapping */ 249262306a36Sopenharmony_ci for (i = 0; queue_priority_mapping[i][0] != -1; i++) 249362306a36Sopenharmony_ci edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0], 249462306a36Sopenharmony_ci queue_priority_mapping[i][1]); 249562306a36Sopenharmony_ci 249662306a36Sopenharmony_ci edma_write_array2(ecc, EDMA_DRAE, 0, 0, 0x0); 249762306a36Sopenharmony_ci edma_write_array2(ecc, EDMA_DRAE, 0, 1, 0x0); 249862306a36Sopenharmony_ci edma_write_array(ecc, EDMA_QRAE, 0, 0x0); 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_ci ecc->info = info; 250162306a36Sopenharmony_ci 250262306a36Sopenharmony_ci /* Init the dma device and channels */ 250362306a36Sopenharmony_ci edma_dma_init(ecc, legacy_mode); 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci for (i = 0; i < ecc->num_channels; i++) { 250662306a36Sopenharmony_ci /* Do not touch reserved channels */ 250762306a36Sopenharmony_ci if (!test_bit(i, ecc->channels_mask)) 250862306a36Sopenharmony_ci continue; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci /* Assign all channels to the default queue */ 251162306a36Sopenharmony_ci edma_assign_channel_eventq(&ecc->slave_chans[i], 251262306a36Sopenharmony_ci info->default_queue); 251362306a36Sopenharmony_ci /* Set entry slot to the dummy slot */ 251462306a36Sopenharmony_ci edma_set_chmap(&ecc->slave_chans[i], ecc->dummy_slot); 251562306a36Sopenharmony_ci } 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci ecc->dma_slave.filter.map = info->slave_map; 251862306a36Sopenharmony_ci ecc->dma_slave.filter.mapcnt = info->slavecnt; 251962306a36Sopenharmony_ci ecc->dma_slave.filter.fn = edma_filter_fn; 252062306a36Sopenharmony_ci 252162306a36Sopenharmony_ci ret = dma_async_device_register(&ecc->dma_slave); 252262306a36Sopenharmony_ci if (ret) { 252362306a36Sopenharmony_ci dev_err(dev, "slave ddev registration failed (%d)\n", ret); 252462306a36Sopenharmony_ci goto err_reg1; 252562306a36Sopenharmony_ci } 252662306a36Sopenharmony_ci 252762306a36Sopenharmony_ci if (ecc->dma_memcpy) { 252862306a36Sopenharmony_ci ret = dma_async_device_register(ecc->dma_memcpy); 252962306a36Sopenharmony_ci if (ret) { 253062306a36Sopenharmony_ci dev_err(dev, "memcpy ddev registration failed (%d)\n", 253162306a36Sopenharmony_ci ret); 253262306a36Sopenharmony_ci dma_async_device_unregister(&ecc->dma_slave); 253362306a36Sopenharmony_ci goto err_reg1; 253462306a36Sopenharmony_ci } 253562306a36Sopenharmony_ci } 253662306a36Sopenharmony_ci 253762306a36Sopenharmony_ci if (node) 253862306a36Sopenharmony_ci of_dma_controller_register(node, of_edma_xlate, ecc); 253962306a36Sopenharmony_ci 254062306a36Sopenharmony_ci dev_info(dev, "TI EDMA DMA engine driver\n"); 254162306a36Sopenharmony_ci 254262306a36Sopenharmony_ci return 0; 254362306a36Sopenharmony_ci 254462306a36Sopenharmony_cierr_reg1: 254562306a36Sopenharmony_ci edma_free_slot(ecc, ecc->dummy_slot); 254662306a36Sopenharmony_cierr_disable_pm: 254762306a36Sopenharmony_ci pm_runtime_put_sync(dev); 254862306a36Sopenharmony_ci pm_runtime_disable(dev); 254962306a36Sopenharmony_ci return ret; 255062306a36Sopenharmony_ci} 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cistatic void edma_cleanupp_vchan(struct dma_device *dmadev) 255362306a36Sopenharmony_ci{ 255462306a36Sopenharmony_ci struct edma_chan *echan, *_echan; 255562306a36Sopenharmony_ci 255662306a36Sopenharmony_ci list_for_each_entry_safe(echan, _echan, 255762306a36Sopenharmony_ci &dmadev->channels, vchan.chan.device_node) { 255862306a36Sopenharmony_ci list_del(&echan->vchan.chan.device_node); 255962306a36Sopenharmony_ci tasklet_kill(&echan->vchan.task); 256062306a36Sopenharmony_ci } 256162306a36Sopenharmony_ci} 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_cistatic int edma_remove(struct platform_device *pdev) 256462306a36Sopenharmony_ci{ 256562306a36Sopenharmony_ci struct device *dev = &pdev->dev; 256662306a36Sopenharmony_ci struct edma_cc *ecc = dev_get_drvdata(dev); 256762306a36Sopenharmony_ci 256862306a36Sopenharmony_ci devm_free_irq(dev, ecc->ccint, ecc); 256962306a36Sopenharmony_ci devm_free_irq(dev, ecc->ccerrint, ecc); 257062306a36Sopenharmony_ci 257162306a36Sopenharmony_ci edma_cleanupp_vchan(&ecc->dma_slave); 257262306a36Sopenharmony_ci 257362306a36Sopenharmony_ci if (dev->of_node) 257462306a36Sopenharmony_ci of_dma_controller_free(dev->of_node); 257562306a36Sopenharmony_ci dma_async_device_unregister(&ecc->dma_slave); 257662306a36Sopenharmony_ci if (ecc->dma_memcpy) 257762306a36Sopenharmony_ci dma_async_device_unregister(ecc->dma_memcpy); 257862306a36Sopenharmony_ci edma_free_slot(ecc, ecc->dummy_slot); 257962306a36Sopenharmony_ci pm_runtime_put_sync(dev); 258062306a36Sopenharmony_ci pm_runtime_disable(dev); 258162306a36Sopenharmony_ci 258262306a36Sopenharmony_ci return 0; 258362306a36Sopenharmony_ci} 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 258662306a36Sopenharmony_cistatic int edma_pm_suspend(struct device *dev) 258762306a36Sopenharmony_ci{ 258862306a36Sopenharmony_ci struct edma_cc *ecc = dev_get_drvdata(dev); 258962306a36Sopenharmony_ci struct edma_chan *echan = ecc->slave_chans; 259062306a36Sopenharmony_ci int i; 259162306a36Sopenharmony_ci 259262306a36Sopenharmony_ci for (i = 0; i < ecc->num_channels; i++) { 259362306a36Sopenharmony_ci if (echan[i].alloced) 259462306a36Sopenharmony_ci edma_setup_interrupt(&echan[i], false); 259562306a36Sopenharmony_ci } 259662306a36Sopenharmony_ci 259762306a36Sopenharmony_ci return 0; 259862306a36Sopenharmony_ci} 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_cistatic int edma_pm_resume(struct device *dev) 260162306a36Sopenharmony_ci{ 260262306a36Sopenharmony_ci struct edma_cc *ecc = dev_get_drvdata(dev); 260362306a36Sopenharmony_ci struct edma_chan *echan = ecc->slave_chans; 260462306a36Sopenharmony_ci int i; 260562306a36Sopenharmony_ci s8 (*queue_priority_mapping)[2]; 260662306a36Sopenharmony_ci 260762306a36Sopenharmony_ci /* re initialize dummy slot to dummy param set */ 260862306a36Sopenharmony_ci edma_write_slot(ecc, ecc->dummy_slot, &dummy_paramset); 260962306a36Sopenharmony_ci 261062306a36Sopenharmony_ci queue_priority_mapping = ecc->info->queue_priority_mapping; 261162306a36Sopenharmony_ci 261262306a36Sopenharmony_ci /* Event queue priority mapping */ 261362306a36Sopenharmony_ci for (i = 0; queue_priority_mapping[i][0] != -1; i++) 261462306a36Sopenharmony_ci edma_assign_priority_to_queue(ecc, queue_priority_mapping[i][0], 261562306a36Sopenharmony_ci queue_priority_mapping[i][1]); 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_ci for (i = 0; i < ecc->num_channels; i++) { 261862306a36Sopenharmony_ci if (echan[i].alloced) { 261962306a36Sopenharmony_ci /* ensure access through shadow region 0 */ 262062306a36Sopenharmony_ci edma_or_array2(ecc, EDMA_DRAE, 0, 262162306a36Sopenharmony_ci EDMA_REG_ARRAY_INDEX(i), 262262306a36Sopenharmony_ci EDMA_CHANNEL_BIT(i)); 262362306a36Sopenharmony_ci 262462306a36Sopenharmony_ci edma_setup_interrupt(&echan[i], true); 262562306a36Sopenharmony_ci 262662306a36Sopenharmony_ci /* Set up channel -> slot mapping for the entry slot */ 262762306a36Sopenharmony_ci edma_set_chmap(&echan[i], echan[i].slot[0]); 262862306a36Sopenharmony_ci } 262962306a36Sopenharmony_ci } 263062306a36Sopenharmony_ci 263162306a36Sopenharmony_ci return 0; 263262306a36Sopenharmony_ci} 263362306a36Sopenharmony_ci#endif 263462306a36Sopenharmony_ci 263562306a36Sopenharmony_cistatic const struct dev_pm_ops edma_pm_ops = { 263662306a36Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(edma_pm_suspend, edma_pm_resume) 263762306a36Sopenharmony_ci}; 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_cistatic struct platform_driver edma_driver = { 264062306a36Sopenharmony_ci .probe = edma_probe, 264162306a36Sopenharmony_ci .remove = edma_remove, 264262306a36Sopenharmony_ci .driver = { 264362306a36Sopenharmony_ci .name = "edma", 264462306a36Sopenharmony_ci .pm = &edma_pm_ops, 264562306a36Sopenharmony_ci .of_match_table = edma_of_ids, 264662306a36Sopenharmony_ci }, 264762306a36Sopenharmony_ci}; 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_cistatic int edma_tptc_probe(struct platform_device *pdev) 265062306a36Sopenharmony_ci{ 265162306a36Sopenharmony_ci pm_runtime_enable(&pdev->dev); 265262306a36Sopenharmony_ci return pm_runtime_get_sync(&pdev->dev); 265362306a36Sopenharmony_ci} 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_cistatic struct platform_driver edma_tptc_driver = { 265662306a36Sopenharmony_ci .probe = edma_tptc_probe, 265762306a36Sopenharmony_ci .driver = { 265862306a36Sopenharmony_ci .name = "edma3-tptc", 265962306a36Sopenharmony_ci .of_match_table = edma_tptc_of_ids, 266062306a36Sopenharmony_ci }, 266162306a36Sopenharmony_ci}; 266262306a36Sopenharmony_ci 266362306a36Sopenharmony_cistatic bool edma_filter_fn(struct dma_chan *chan, void *param) 266462306a36Sopenharmony_ci{ 266562306a36Sopenharmony_ci bool match = false; 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci if (chan->device->dev->driver == &edma_driver.driver) { 266862306a36Sopenharmony_ci struct edma_chan *echan = to_edma_chan(chan); 266962306a36Sopenharmony_ci unsigned ch_req = *(unsigned *)param; 267062306a36Sopenharmony_ci if (ch_req == echan->ch_num) { 267162306a36Sopenharmony_ci /* The channel is going to be used as HW synchronized */ 267262306a36Sopenharmony_ci echan->hw_triggered = true; 267362306a36Sopenharmony_ci match = true; 267462306a36Sopenharmony_ci } 267562306a36Sopenharmony_ci } 267662306a36Sopenharmony_ci return match; 267762306a36Sopenharmony_ci} 267862306a36Sopenharmony_ci 267962306a36Sopenharmony_cistatic int edma_init(void) 268062306a36Sopenharmony_ci{ 268162306a36Sopenharmony_ci int ret; 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci ret = platform_driver_register(&edma_tptc_driver); 268462306a36Sopenharmony_ci if (ret) 268562306a36Sopenharmony_ci return ret; 268662306a36Sopenharmony_ci 268762306a36Sopenharmony_ci return platform_driver_register(&edma_driver); 268862306a36Sopenharmony_ci} 268962306a36Sopenharmony_cisubsys_initcall(edma_init); 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_cistatic void __exit edma_exit(void) 269262306a36Sopenharmony_ci{ 269362306a36Sopenharmony_ci platform_driver_unregister(&edma_driver); 269462306a36Sopenharmony_ci platform_driver_unregister(&edma_tptc_driver); 269562306a36Sopenharmony_ci} 269662306a36Sopenharmony_cimodule_exit(edma_exit); 269762306a36Sopenharmony_ci 269862306a36Sopenharmony_ciMODULE_AUTHOR("Matt Porter <matt.porter@linaro.org>"); 269962306a36Sopenharmony_ciMODULE_DESCRIPTION("TI EDMA DMA engine driver"); 270062306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 2701