162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com 462306a36Sopenharmony_ci * Author: Peter Ujfalusi <peter.ujfalusi@ti.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/module.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/dmaengine.h> 1162306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1262306a36Sopenharmony_ci#include <linux/dmapool.h> 1362306a36Sopenharmony_ci#include <linux/err.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/list.h> 1762306a36Sopenharmony_ci#include <linux/platform_device.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/spinlock.h> 2062306a36Sopenharmony_ci#include <linux/sys_soc.h> 2162306a36Sopenharmony_ci#include <linux/of.h> 2262306a36Sopenharmony_ci#include <linux/of_dma.h> 2362306a36Sopenharmony_ci#include <linux/of_irq.h> 2462306a36Sopenharmony_ci#include <linux/workqueue.h> 2562306a36Sopenharmony_ci#include <linux/completion.h> 2662306a36Sopenharmony_ci#include <linux/soc/ti/k3-ringacc.h> 2762306a36Sopenharmony_ci#include <linux/soc/ti/ti_sci_protocol.h> 2862306a36Sopenharmony_ci#include <linux/soc/ti/ti_sci_inta_msi.h> 2962306a36Sopenharmony_ci#include <linux/dma/k3-event-router.h> 3062306a36Sopenharmony_ci#include <linux/dma/ti-cppi5.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "../virt-dma.h" 3362306a36Sopenharmony_ci#include "k3-udma.h" 3462306a36Sopenharmony_ci#include "k3-psil-priv.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct udma_static_tr { 3762306a36Sopenharmony_ci u8 elsize; /* RPSTR0 */ 3862306a36Sopenharmony_ci u16 elcnt; /* RPSTR0 */ 3962306a36Sopenharmony_ci u16 bstcnt; /* RPSTR1 */ 4062306a36Sopenharmony_ci}; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci#define K3_UDMA_MAX_RFLOWS 1024 4362306a36Sopenharmony_ci#define K3_UDMA_DEFAULT_RING_SIZE 16 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci/* How SRC/DST tag should be updated by UDMA in the descriptor's Word 3 */ 4662306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_NONE 0 4762306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_CFG_TAG 1 4862306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_FLOW_ID 2 4962306a36Sopenharmony_ci#define UDMA_RFLOW_SRCTAG_SRC_TAG 4 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_NONE 0 5262306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_CFG_TAG 1 5362306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_FLOW_ID 2 5462306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_DST_TAG_LO 4 5562306a36Sopenharmony_ci#define UDMA_RFLOW_DSTTAG_DST_TAG_HI 5 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistruct udma_chan; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cienum k3_dma_type { 6062306a36Sopenharmony_ci DMA_TYPE_UDMA = 0, 6162306a36Sopenharmony_ci DMA_TYPE_BCDMA, 6262306a36Sopenharmony_ci DMA_TYPE_PKTDMA, 6362306a36Sopenharmony_ci}; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_cienum udma_mmr { 6662306a36Sopenharmony_ci MMR_GCFG = 0, 6762306a36Sopenharmony_ci MMR_BCHANRT, 6862306a36Sopenharmony_ci MMR_RCHANRT, 6962306a36Sopenharmony_ci MMR_TCHANRT, 7062306a36Sopenharmony_ci MMR_LAST, 7162306a36Sopenharmony_ci}; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const char * const mmr_names[] = { 7462306a36Sopenharmony_ci [MMR_GCFG] = "gcfg", 7562306a36Sopenharmony_ci [MMR_BCHANRT] = "bchanrt", 7662306a36Sopenharmony_ci [MMR_RCHANRT] = "rchanrt", 7762306a36Sopenharmony_ci [MMR_TCHANRT] = "tchanrt", 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistruct udma_tchan { 8162306a36Sopenharmony_ci void __iomem *reg_rt; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci int id; 8462306a36Sopenharmony_ci struct k3_ring *t_ring; /* Transmit ring */ 8562306a36Sopenharmony_ci struct k3_ring *tc_ring; /* Transmit Completion ring */ 8662306a36Sopenharmony_ci int tflow_id; /* applicable only for PKTDMA */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci}; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci#define udma_bchan udma_tchan 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_cistruct udma_rflow { 9362306a36Sopenharmony_ci int id; 9462306a36Sopenharmony_ci struct k3_ring *fd_ring; /* Free Descriptor ring */ 9562306a36Sopenharmony_ci struct k3_ring *r_ring; /* Receive ring */ 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistruct udma_rchan { 9962306a36Sopenharmony_ci void __iomem *reg_rt; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci int id; 10262306a36Sopenharmony_ci}; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_cistruct udma_oes_offsets { 10562306a36Sopenharmony_ci /* K3 UDMA Output Event Offset */ 10662306a36Sopenharmony_ci u32 udma_rchan; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci /* BCDMA Output Event Offsets */ 10962306a36Sopenharmony_ci u32 bcdma_bchan_data; 11062306a36Sopenharmony_ci u32 bcdma_bchan_ring; 11162306a36Sopenharmony_ci u32 bcdma_tchan_data; 11262306a36Sopenharmony_ci u32 bcdma_tchan_ring; 11362306a36Sopenharmony_ci u32 bcdma_rchan_data; 11462306a36Sopenharmony_ci u32 bcdma_rchan_ring; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* PKTDMA Output Event Offsets */ 11762306a36Sopenharmony_ci u32 pktdma_tchan_flow; 11862306a36Sopenharmony_ci u32 pktdma_rchan_flow; 11962306a36Sopenharmony_ci}; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define UDMA_FLAG_PDMA_ACC32 BIT(0) 12262306a36Sopenharmony_ci#define UDMA_FLAG_PDMA_BURST BIT(1) 12362306a36Sopenharmony_ci#define UDMA_FLAG_TDTYPE BIT(2) 12462306a36Sopenharmony_ci#define UDMA_FLAG_BURST_SIZE BIT(3) 12562306a36Sopenharmony_ci#define UDMA_FLAGS_J7_CLASS (UDMA_FLAG_PDMA_ACC32 | \ 12662306a36Sopenharmony_ci UDMA_FLAG_PDMA_BURST | \ 12762306a36Sopenharmony_ci UDMA_FLAG_TDTYPE | \ 12862306a36Sopenharmony_ci UDMA_FLAG_BURST_SIZE) 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_cistruct udma_match_data { 13162306a36Sopenharmony_ci enum k3_dma_type type; 13262306a36Sopenharmony_ci u32 psil_base; 13362306a36Sopenharmony_ci bool enable_memcpy_support; 13462306a36Sopenharmony_ci u32 flags; 13562306a36Sopenharmony_ci u32 statictr_z_mask; 13662306a36Sopenharmony_ci u8 burst_size[3]; 13762306a36Sopenharmony_ci struct udma_soc_data *soc_data; 13862306a36Sopenharmony_ci}; 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistruct udma_soc_data { 14162306a36Sopenharmony_ci struct udma_oes_offsets oes; 14262306a36Sopenharmony_ci u32 bcdma_trigger_event_offset; 14362306a36Sopenharmony_ci}; 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_cistruct udma_hwdesc { 14662306a36Sopenharmony_ci size_t cppi5_desc_size; 14762306a36Sopenharmony_ci void *cppi5_desc_vaddr; 14862306a36Sopenharmony_ci dma_addr_t cppi5_desc_paddr; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* TR descriptor internal pointers */ 15162306a36Sopenharmony_ci void *tr_req_base; 15262306a36Sopenharmony_ci struct cppi5_tr_resp_t *tr_resp_base; 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistruct udma_rx_flush { 15662306a36Sopenharmony_ci struct udma_hwdesc hwdescs[2]; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci size_t buffer_size; 15962306a36Sopenharmony_ci void *buffer_vaddr; 16062306a36Sopenharmony_ci dma_addr_t buffer_paddr; 16162306a36Sopenharmony_ci}; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_cistruct udma_tpl { 16462306a36Sopenharmony_ci u8 levels; 16562306a36Sopenharmony_ci u32 start_idx[3]; 16662306a36Sopenharmony_ci}; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistruct udma_dev { 16962306a36Sopenharmony_ci struct dma_device ddev; 17062306a36Sopenharmony_ci struct device *dev; 17162306a36Sopenharmony_ci void __iomem *mmrs[MMR_LAST]; 17262306a36Sopenharmony_ci const struct udma_match_data *match_data; 17362306a36Sopenharmony_ci const struct udma_soc_data *soc_data; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci struct udma_tpl bchan_tpl; 17662306a36Sopenharmony_ci struct udma_tpl tchan_tpl; 17762306a36Sopenharmony_ci struct udma_tpl rchan_tpl; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci size_t desc_align; /* alignment to use for descriptors */ 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci struct udma_tisci_rm tisci_rm; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci struct k3_ringacc *ringacc; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci struct work_struct purge_work; 18662306a36Sopenharmony_ci struct list_head desc_to_purge; 18762306a36Sopenharmony_ci spinlock_t lock; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci struct udma_rx_flush rx_flush; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci int bchan_cnt; 19262306a36Sopenharmony_ci int tchan_cnt; 19362306a36Sopenharmony_ci int echan_cnt; 19462306a36Sopenharmony_ci int rchan_cnt; 19562306a36Sopenharmony_ci int rflow_cnt; 19662306a36Sopenharmony_ci int tflow_cnt; 19762306a36Sopenharmony_ci unsigned long *bchan_map; 19862306a36Sopenharmony_ci unsigned long *tchan_map; 19962306a36Sopenharmony_ci unsigned long *rchan_map; 20062306a36Sopenharmony_ci unsigned long *rflow_gp_map; 20162306a36Sopenharmony_ci unsigned long *rflow_gp_map_allocated; 20262306a36Sopenharmony_ci unsigned long *rflow_in_use; 20362306a36Sopenharmony_ci unsigned long *tflow_map; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci struct udma_bchan *bchans; 20662306a36Sopenharmony_ci struct udma_tchan *tchans; 20762306a36Sopenharmony_ci struct udma_rchan *rchans; 20862306a36Sopenharmony_ci struct udma_rflow *rflows; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci struct udma_chan *channels; 21162306a36Sopenharmony_ci u32 psil_base; 21262306a36Sopenharmony_ci u32 atype; 21362306a36Sopenharmony_ci u32 asel; 21462306a36Sopenharmony_ci}; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_cistruct udma_desc { 21762306a36Sopenharmony_ci struct virt_dma_desc vd; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci bool terminated; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci enum dma_transfer_direction dir; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci struct udma_static_tr static_tr; 22462306a36Sopenharmony_ci u32 residue; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci unsigned int sglen; 22762306a36Sopenharmony_ci unsigned int desc_idx; /* Only used for cyclic in packet mode */ 22862306a36Sopenharmony_ci unsigned int tr_idx; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci u32 metadata_size; 23162306a36Sopenharmony_ci void *metadata; /* pointer to provided metadata buffer (EPIP, PSdata) */ 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci unsigned int hwdesc_count; 23462306a36Sopenharmony_ci struct udma_hwdesc hwdesc[]; 23562306a36Sopenharmony_ci}; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_cienum udma_chan_state { 23862306a36Sopenharmony_ci UDMA_CHAN_IS_IDLE = 0, /* not active, no teardown is in progress */ 23962306a36Sopenharmony_ci UDMA_CHAN_IS_ACTIVE, /* Normal operation */ 24062306a36Sopenharmony_ci UDMA_CHAN_IS_TERMINATING, /* channel is being terminated */ 24162306a36Sopenharmony_ci}; 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_cistruct udma_tx_drain { 24462306a36Sopenharmony_ci struct delayed_work work; 24562306a36Sopenharmony_ci ktime_t tstamp; 24662306a36Sopenharmony_ci u32 residue; 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistruct udma_chan_config { 25062306a36Sopenharmony_ci bool pkt_mode; /* TR or packet */ 25162306a36Sopenharmony_ci bool needs_epib; /* EPIB is needed for the communication or not */ 25262306a36Sopenharmony_ci u32 psd_size; /* size of Protocol Specific Data */ 25362306a36Sopenharmony_ci u32 metadata_size; /* (needs_epib ? 16:0) + psd_size */ 25462306a36Sopenharmony_ci u32 hdesc_size; /* Size of a packet descriptor in packet mode */ 25562306a36Sopenharmony_ci bool notdpkt; /* Suppress sending TDC packet */ 25662306a36Sopenharmony_ci int remote_thread_id; 25762306a36Sopenharmony_ci u32 atype; 25862306a36Sopenharmony_ci u32 asel; 25962306a36Sopenharmony_ci u32 src_thread; 26062306a36Sopenharmony_ci u32 dst_thread; 26162306a36Sopenharmony_ci enum psil_endpoint_type ep_type; 26262306a36Sopenharmony_ci bool enable_acc32; 26362306a36Sopenharmony_ci bool enable_burst; 26462306a36Sopenharmony_ci enum udma_tp_level channel_tpl; /* Channel Throughput Level */ 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci u32 tr_trigger_type; 26762306a36Sopenharmony_ci unsigned long tx_flags; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci /* PKDMA mapped channel */ 27062306a36Sopenharmony_ci int mapped_channel_id; 27162306a36Sopenharmony_ci /* PKTDMA default tflow or rflow for mapped channel */ 27262306a36Sopenharmony_ci int default_flow_id; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci enum dma_transfer_direction dir; 27562306a36Sopenharmony_ci}; 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_cistruct udma_chan { 27862306a36Sopenharmony_ci struct virt_dma_chan vc; 27962306a36Sopenharmony_ci struct dma_slave_config cfg; 28062306a36Sopenharmony_ci struct udma_dev *ud; 28162306a36Sopenharmony_ci struct device *dma_dev; 28262306a36Sopenharmony_ci struct udma_desc *desc; 28362306a36Sopenharmony_ci struct udma_desc *terminated_desc; 28462306a36Sopenharmony_ci struct udma_static_tr static_tr; 28562306a36Sopenharmony_ci char *name; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci struct udma_bchan *bchan; 28862306a36Sopenharmony_ci struct udma_tchan *tchan; 28962306a36Sopenharmony_ci struct udma_rchan *rchan; 29062306a36Sopenharmony_ci struct udma_rflow *rflow; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci bool psil_paired; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci int irq_num_ring; 29562306a36Sopenharmony_ci int irq_num_udma; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci bool cyclic; 29862306a36Sopenharmony_ci bool paused; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci enum udma_chan_state state; 30162306a36Sopenharmony_ci struct completion teardown_completed; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci struct udma_tx_drain tx_drain; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci /* Channel configuration parameters */ 30662306a36Sopenharmony_ci struct udma_chan_config config; 30762306a36Sopenharmony_ci /* Channel configuration parameters (backup) */ 30862306a36Sopenharmony_ci struct udma_chan_config backup_config; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci /* dmapool for packet mode descriptors */ 31162306a36Sopenharmony_ci bool use_dma_pool; 31262306a36Sopenharmony_ci struct dma_pool *hdesc_pool; 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci u32 id; 31562306a36Sopenharmony_ci}; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_cistatic inline struct udma_dev *to_udma_dev(struct dma_device *d) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci return container_of(d, struct udma_dev, ddev); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic inline struct udma_chan *to_udma_chan(struct dma_chan *c) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci return container_of(c, struct udma_chan, vc.chan); 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic inline struct udma_desc *to_udma_desc(struct dma_async_tx_descriptor *t) 32862306a36Sopenharmony_ci{ 32962306a36Sopenharmony_ci return container_of(t, struct udma_desc, vd.tx); 33062306a36Sopenharmony_ci} 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci/* Generic register access functions */ 33362306a36Sopenharmony_cistatic inline u32 udma_read(void __iomem *base, int reg) 33462306a36Sopenharmony_ci{ 33562306a36Sopenharmony_ci return readl(base + reg); 33662306a36Sopenharmony_ci} 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_cistatic inline void udma_write(void __iomem *base, int reg, u32 val) 33962306a36Sopenharmony_ci{ 34062306a36Sopenharmony_ci writel(val, base + reg); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_cistatic inline void udma_update_bits(void __iomem *base, int reg, 34462306a36Sopenharmony_ci u32 mask, u32 val) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci u32 tmp, orig; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci orig = readl(base + reg); 34962306a36Sopenharmony_ci tmp = orig & ~mask; 35062306a36Sopenharmony_ci tmp |= (val & mask); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (tmp != orig) 35362306a36Sopenharmony_ci writel(tmp, base + reg); 35462306a36Sopenharmony_ci} 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* TCHANRT */ 35762306a36Sopenharmony_cistatic inline u32 udma_tchanrt_read(struct udma_chan *uc, int reg) 35862306a36Sopenharmony_ci{ 35962306a36Sopenharmony_ci if (!uc->tchan) 36062306a36Sopenharmony_ci return 0; 36162306a36Sopenharmony_ci return udma_read(uc->tchan->reg_rt, reg); 36262306a36Sopenharmony_ci} 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_cistatic inline void udma_tchanrt_write(struct udma_chan *uc, int reg, u32 val) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci if (!uc->tchan) 36762306a36Sopenharmony_ci return; 36862306a36Sopenharmony_ci udma_write(uc->tchan->reg_rt, reg, val); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic inline void udma_tchanrt_update_bits(struct udma_chan *uc, int reg, 37262306a36Sopenharmony_ci u32 mask, u32 val) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci if (!uc->tchan) 37562306a36Sopenharmony_ci return; 37662306a36Sopenharmony_ci udma_update_bits(uc->tchan->reg_rt, reg, mask, val); 37762306a36Sopenharmony_ci} 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci/* RCHANRT */ 38062306a36Sopenharmony_cistatic inline u32 udma_rchanrt_read(struct udma_chan *uc, int reg) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci if (!uc->rchan) 38362306a36Sopenharmony_ci return 0; 38462306a36Sopenharmony_ci return udma_read(uc->rchan->reg_rt, reg); 38562306a36Sopenharmony_ci} 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_cistatic inline void udma_rchanrt_write(struct udma_chan *uc, int reg, u32 val) 38862306a36Sopenharmony_ci{ 38962306a36Sopenharmony_ci if (!uc->rchan) 39062306a36Sopenharmony_ci return; 39162306a36Sopenharmony_ci udma_write(uc->rchan->reg_rt, reg, val); 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic inline void udma_rchanrt_update_bits(struct udma_chan *uc, int reg, 39562306a36Sopenharmony_ci u32 mask, u32 val) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci if (!uc->rchan) 39862306a36Sopenharmony_ci return; 39962306a36Sopenharmony_ci udma_update_bits(uc->rchan->reg_rt, reg, mask, val); 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic int navss_psil_pair(struct udma_dev *ud, u32 src_thread, u32 dst_thread) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET; 40762306a36Sopenharmony_ci return tisci_rm->tisci_psil_ops->pair(tisci_rm->tisci, 40862306a36Sopenharmony_ci tisci_rm->tisci_navss_dev_id, 40962306a36Sopenharmony_ci src_thread, dst_thread); 41062306a36Sopenharmony_ci} 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_cistatic int navss_psil_unpair(struct udma_dev *ud, u32 src_thread, 41362306a36Sopenharmony_ci u32 dst_thread) 41462306a36Sopenharmony_ci{ 41562306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET; 41862306a36Sopenharmony_ci return tisci_rm->tisci_psil_ops->unpair(tisci_rm->tisci, 41962306a36Sopenharmony_ci tisci_rm->tisci_navss_dev_id, 42062306a36Sopenharmony_ci src_thread, dst_thread); 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_cistatic void k3_configure_chan_coherency(struct dma_chan *chan, u32 asel) 42462306a36Sopenharmony_ci{ 42562306a36Sopenharmony_ci struct device *chan_dev = &chan->dev->device; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (asel == 0) { 42862306a36Sopenharmony_ci /* No special handling for the channel */ 42962306a36Sopenharmony_ci chan->dev->chan_dma_dev = false; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci chan_dev->dma_coherent = false; 43262306a36Sopenharmony_ci chan_dev->dma_parms = NULL; 43362306a36Sopenharmony_ci } else if (asel == 14 || asel == 15) { 43462306a36Sopenharmony_ci chan->dev->chan_dma_dev = true; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci chan_dev->dma_coherent = true; 43762306a36Sopenharmony_ci dma_coerce_mask_and_coherent(chan_dev, DMA_BIT_MASK(48)); 43862306a36Sopenharmony_ci chan_dev->dma_parms = chan_dev->parent->dma_parms; 43962306a36Sopenharmony_ci } else { 44062306a36Sopenharmony_ci dev_warn(chan->device->dev, "Invalid ASEL value: %u\n", asel); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci chan_dev->dma_coherent = false; 44362306a36Sopenharmony_ci chan_dev->dma_parms = NULL; 44462306a36Sopenharmony_ci } 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic u8 udma_get_chan_tpl_index(struct udma_tpl *tpl_map, int chan_id) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci int i; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci for (i = 0; i < tpl_map->levels; i++) { 45262306a36Sopenharmony_ci if (chan_id >= tpl_map->start_idx[i]) 45362306a36Sopenharmony_ci return i; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci return 0; 45762306a36Sopenharmony_ci} 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_cistatic void udma_reset_uchan(struct udma_chan *uc) 46062306a36Sopenharmony_ci{ 46162306a36Sopenharmony_ci memset(&uc->config, 0, sizeof(uc->config)); 46262306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 46362306a36Sopenharmony_ci uc->config.mapped_channel_id = -1; 46462306a36Sopenharmony_ci uc->config.default_flow_id = -1; 46562306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_IDLE; 46662306a36Sopenharmony_ci} 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_cistatic void udma_dump_chan_stdata(struct udma_chan *uc) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct device *dev = uc->ud->dev; 47162306a36Sopenharmony_ci u32 offset; 47262306a36Sopenharmony_ci int i; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci if (uc->config.dir == DMA_MEM_TO_DEV || uc->config.dir == DMA_MEM_TO_MEM) { 47562306a36Sopenharmony_ci dev_dbg(dev, "TCHAN State data:\n"); 47662306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 47762306a36Sopenharmony_ci offset = UDMA_CHAN_RT_STDATA_REG + i * 4; 47862306a36Sopenharmony_ci dev_dbg(dev, "TRT_STDATA[%02d]: 0x%08x\n", i, 47962306a36Sopenharmony_ci udma_tchanrt_read(uc, offset)); 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci } 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (uc->config.dir == DMA_DEV_TO_MEM || uc->config.dir == DMA_MEM_TO_MEM) { 48462306a36Sopenharmony_ci dev_dbg(dev, "RCHAN State data:\n"); 48562306a36Sopenharmony_ci for (i = 0; i < 32; i++) { 48662306a36Sopenharmony_ci offset = UDMA_CHAN_RT_STDATA_REG + i * 4; 48762306a36Sopenharmony_ci dev_dbg(dev, "RRT_STDATA[%02d]: 0x%08x\n", i, 48862306a36Sopenharmony_ci udma_rchanrt_read(uc, offset)); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci} 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_cistatic inline dma_addr_t udma_curr_cppi5_desc_paddr(struct udma_desc *d, 49462306a36Sopenharmony_ci int idx) 49562306a36Sopenharmony_ci{ 49662306a36Sopenharmony_ci return d->hwdesc[idx].cppi5_desc_paddr; 49762306a36Sopenharmony_ci} 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_cistatic inline void *udma_curr_cppi5_desc_vaddr(struct udma_desc *d, int idx) 50062306a36Sopenharmony_ci{ 50162306a36Sopenharmony_ci return d->hwdesc[idx].cppi5_desc_vaddr; 50262306a36Sopenharmony_ci} 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_cistatic struct udma_desc *udma_udma_desc_from_paddr(struct udma_chan *uc, 50562306a36Sopenharmony_ci dma_addr_t paddr) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci struct udma_desc *d = uc->terminated_desc; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (d) { 51062306a36Sopenharmony_ci dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d, 51162306a36Sopenharmony_ci d->desc_idx); 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci if (desc_paddr != paddr) 51462306a36Sopenharmony_ci d = NULL; 51562306a36Sopenharmony_ci } 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (!d) { 51862306a36Sopenharmony_ci d = uc->desc; 51962306a36Sopenharmony_ci if (d) { 52062306a36Sopenharmony_ci dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d, 52162306a36Sopenharmony_ci d->desc_idx); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci if (desc_paddr != paddr) 52462306a36Sopenharmony_ci d = NULL; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci } 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return d; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_cistatic void udma_free_hwdesc(struct udma_chan *uc, struct udma_desc *d) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci if (uc->use_dma_pool) { 53462306a36Sopenharmony_ci int i; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci for (i = 0; i < d->hwdesc_count; i++) { 53762306a36Sopenharmony_ci if (!d->hwdesc[i].cppi5_desc_vaddr) 53862306a36Sopenharmony_ci continue; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci dma_pool_free(uc->hdesc_pool, 54162306a36Sopenharmony_ci d->hwdesc[i].cppi5_desc_vaddr, 54262306a36Sopenharmony_ci d->hwdesc[i].cppi5_desc_paddr); 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci d->hwdesc[i].cppi5_desc_vaddr = NULL; 54562306a36Sopenharmony_ci } 54662306a36Sopenharmony_ci } else if (d->hwdesc[0].cppi5_desc_vaddr) { 54762306a36Sopenharmony_ci dma_free_coherent(uc->dma_dev, d->hwdesc[0].cppi5_desc_size, 54862306a36Sopenharmony_ci d->hwdesc[0].cppi5_desc_vaddr, 54962306a36Sopenharmony_ci d->hwdesc[0].cppi5_desc_paddr); 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci d->hwdesc[0].cppi5_desc_vaddr = NULL; 55262306a36Sopenharmony_ci } 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic void udma_purge_desc_work(struct work_struct *work) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct udma_dev *ud = container_of(work, typeof(*ud), purge_work); 55862306a36Sopenharmony_ci struct virt_dma_desc *vd, *_vd; 55962306a36Sopenharmony_ci unsigned long flags; 56062306a36Sopenharmony_ci LIST_HEAD(head); 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci spin_lock_irqsave(&ud->lock, flags); 56362306a36Sopenharmony_ci list_splice_tail_init(&ud->desc_to_purge, &head); 56462306a36Sopenharmony_ci spin_unlock_irqrestore(&ud->lock, flags); 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci list_for_each_entry_safe(vd, _vd, &head, node) { 56762306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(vd->tx.chan); 56862306a36Sopenharmony_ci struct udma_desc *d = to_udma_desc(&vd->tx); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 57162306a36Sopenharmony_ci list_del(&vd->node); 57262306a36Sopenharmony_ci kfree(d); 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* If more to purge, schedule the work again */ 57662306a36Sopenharmony_ci if (!list_empty(&ud->desc_to_purge)) 57762306a36Sopenharmony_ci schedule_work(&ud->purge_work); 57862306a36Sopenharmony_ci} 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_cistatic void udma_desc_free(struct virt_dma_desc *vd) 58162306a36Sopenharmony_ci{ 58262306a36Sopenharmony_ci struct udma_dev *ud = to_udma_dev(vd->tx.chan->device); 58362306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(vd->tx.chan); 58462306a36Sopenharmony_ci struct udma_desc *d = to_udma_desc(&vd->tx); 58562306a36Sopenharmony_ci unsigned long flags; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci if (uc->terminated_desc == d) 58862306a36Sopenharmony_ci uc->terminated_desc = NULL; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci if (uc->use_dma_pool) { 59162306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 59262306a36Sopenharmony_ci kfree(d); 59362306a36Sopenharmony_ci return; 59462306a36Sopenharmony_ci } 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci spin_lock_irqsave(&ud->lock, flags); 59762306a36Sopenharmony_ci list_add_tail(&vd->node, &ud->desc_to_purge); 59862306a36Sopenharmony_ci spin_unlock_irqrestore(&ud->lock, flags); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci schedule_work(&ud->purge_work); 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_cistatic bool udma_is_chan_running(struct udma_chan *uc) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci u32 trt_ctl = 0; 60662306a36Sopenharmony_ci u32 rrt_ctl = 0; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci if (uc->tchan) 60962306a36Sopenharmony_ci trt_ctl = udma_tchanrt_read(uc, UDMA_CHAN_RT_CTL_REG); 61062306a36Sopenharmony_ci if (uc->rchan) 61162306a36Sopenharmony_ci rrt_ctl = udma_rchanrt_read(uc, UDMA_CHAN_RT_CTL_REG); 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci if (trt_ctl & UDMA_CHAN_RT_CTL_EN || rrt_ctl & UDMA_CHAN_RT_CTL_EN) 61462306a36Sopenharmony_ci return true; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci return false; 61762306a36Sopenharmony_ci} 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_cistatic bool udma_is_chan_paused(struct udma_chan *uc) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci u32 val, pause_mask; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci switch (uc->config.dir) { 62462306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 62562306a36Sopenharmony_ci val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PEER_RT_EN_REG); 62662306a36Sopenharmony_ci pause_mask = UDMA_PEER_RT_EN_PAUSE; 62762306a36Sopenharmony_ci break; 62862306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 62962306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_RT_EN_REG); 63062306a36Sopenharmony_ci pause_mask = UDMA_PEER_RT_EN_PAUSE; 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 63362306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_CTL_REG); 63462306a36Sopenharmony_ci pause_mask = UDMA_CHAN_RT_CTL_PAUSE; 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci default: 63762306a36Sopenharmony_ci return false; 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci if (val & pause_mask) 64162306a36Sopenharmony_ci return true; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci return false; 64462306a36Sopenharmony_ci} 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_cistatic inline dma_addr_t udma_get_rx_flush_hwdesc_paddr(struct udma_chan *uc) 64762306a36Sopenharmony_ci{ 64862306a36Sopenharmony_ci return uc->ud->rx_flush.hwdescs[uc->config.pkt_mode].cppi5_desc_paddr; 64962306a36Sopenharmony_ci} 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_cistatic int udma_push_to_ring(struct udma_chan *uc, int idx) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct udma_desc *d = uc->desc; 65462306a36Sopenharmony_ci struct k3_ring *ring = NULL; 65562306a36Sopenharmony_ci dma_addr_t paddr; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci switch (uc->config.dir) { 65862306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 65962306a36Sopenharmony_ci ring = uc->rflow->fd_ring; 66062306a36Sopenharmony_ci break; 66162306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 66262306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 66362306a36Sopenharmony_ci ring = uc->tchan->t_ring; 66462306a36Sopenharmony_ci break; 66562306a36Sopenharmony_ci default: 66662306a36Sopenharmony_ci return -EINVAL; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci /* RX flush packet: idx == -1 is only passed in case of DEV_TO_MEM */ 67062306a36Sopenharmony_ci if (idx == -1) { 67162306a36Sopenharmony_ci paddr = udma_get_rx_flush_hwdesc_paddr(uc); 67262306a36Sopenharmony_ci } else { 67362306a36Sopenharmony_ci paddr = udma_curr_cppi5_desc_paddr(d, idx); 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci wmb(); /* Ensure that writes are not moved over this point */ 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci return k3_ringacc_ring_push(ring, &paddr); 67962306a36Sopenharmony_ci} 68062306a36Sopenharmony_ci 68162306a36Sopenharmony_cistatic bool udma_desc_is_rx_flush(struct udma_chan *uc, dma_addr_t addr) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci if (uc->config.dir != DMA_DEV_TO_MEM) 68462306a36Sopenharmony_ci return false; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci if (addr == udma_get_rx_flush_hwdesc_paddr(uc)) 68762306a36Sopenharmony_ci return true; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci return false; 69062306a36Sopenharmony_ci} 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_cistatic int udma_pop_from_ring(struct udma_chan *uc, dma_addr_t *addr) 69362306a36Sopenharmony_ci{ 69462306a36Sopenharmony_ci struct k3_ring *ring = NULL; 69562306a36Sopenharmony_ci int ret; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci switch (uc->config.dir) { 69862306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 69962306a36Sopenharmony_ci ring = uc->rflow->r_ring; 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 70262306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 70362306a36Sopenharmony_ci ring = uc->tchan->tc_ring; 70462306a36Sopenharmony_ci break; 70562306a36Sopenharmony_ci default: 70662306a36Sopenharmony_ci return -ENOENT; 70762306a36Sopenharmony_ci } 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_ci ret = k3_ringacc_ring_pop(ring, addr); 71062306a36Sopenharmony_ci if (ret) 71162306a36Sopenharmony_ci return ret; 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci rmb(); /* Ensure that reads are not moved before this point */ 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Teardown completion */ 71662306a36Sopenharmony_ci if (cppi5_desc_is_tdcm(*addr)) 71762306a36Sopenharmony_ci return 0; 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* Check for flush descriptor */ 72062306a36Sopenharmony_ci if (udma_desc_is_rx_flush(uc, *addr)) 72162306a36Sopenharmony_ci return -ENOENT; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_cistatic void udma_reset_rings(struct udma_chan *uc) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct k3_ring *ring1 = NULL; 72962306a36Sopenharmony_ci struct k3_ring *ring2 = NULL; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci switch (uc->config.dir) { 73262306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 73362306a36Sopenharmony_ci if (uc->rchan) { 73462306a36Sopenharmony_ci ring1 = uc->rflow->fd_ring; 73562306a36Sopenharmony_ci ring2 = uc->rflow->r_ring; 73662306a36Sopenharmony_ci } 73762306a36Sopenharmony_ci break; 73862306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 73962306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 74062306a36Sopenharmony_ci if (uc->tchan) { 74162306a36Sopenharmony_ci ring1 = uc->tchan->t_ring; 74262306a36Sopenharmony_ci ring2 = uc->tchan->tc_ring; 74362306a36Sopenharmony_ci } 74462306a36Sopenharmony_ci break; 74562306a36Sopenharmony_ci default: 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci } 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (ring1) 75062306a36Sopenharmony_ci k3_ringacc_ring_reset_dma(ring1, 75162306a36Sopenharmony_ci k3_ringacc_ring_get_occ(ring1)); 75262306a36Sopenharmony_ci if (ring2) 75362306a36Sopenharmony_ci k3_ringacc_ring_reset(ring2); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci /* make sure we are not leaking memory by stalled descriptor */ 75662306a36Sopenharmony_ci if (uc->terminated_desc) { 75762306a36Sopenharmony_ci udma_desc_free(&uc->terminated_desc->vd); 75862306a36Sopenharmony_ci uc->terminated_desc = NULL; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cistatic void udma_decrement_byte_counters(struct udma_chan *uc, u32 val) 76362306a36Sopenharmony_ci{ 76462306a36Sopenharmony_ci if (uc->desc->dir == DMA_DEV_TO_MEM) { 76562306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); 76662306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); 76762306a36Sopenharmony_ci if (uc->config.ep_type != PSIL_EP_NATIVE) 76862306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); 76962306a36Sopenharmony_ci } else { 77062306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); 77162306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); 77262306a36Sopenharmony_ci if (!uc->bchan && uc->config.ep_type != PSIL_EP_NATIVE) 77362306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci} 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_cistatic void udma_reset_counters(struct udma_chan *uc) 77862306a36Sopenharmony_ci{ 77962306a36Sopenharmony_ci u32 val; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (uc->tchan) { 78262306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); 78362306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG); 78662306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PCNT_REG); 78962306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PCNT_REG, val); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (!uc->bchan) { 79262306a36Sopenharmony_ci val = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG); 79362306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci } 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci if (uc->rchan) { 79862306a36Sopenharmony_ci val = udma_rchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); 79962306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_BCNT_REG, val); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci val = udma_rchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG); 80262306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_SBCNT_REG, val); 80362306a36Sopenharmony_ci 80462306a36Sopenharmony_ci val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PCNT_REG); 80562306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PCNT_REG, val); 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci val = udma_rchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG); 80862306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_BCNT_REG, val); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic int udma_reset_chan(struct udma_chan *uc, bool hard) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci switch (uc->config.dir) { 81562306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 81662306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 0); 81762306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0); 81862306a36Sopenharmony_ci break; 81962306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 82062306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0); 82162306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 0); 82262306a36Sopenharmony_ci break; 82362306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 82462306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0); 82562306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 0); 82662306a36Sopenharmony_ci break; 82762306a36Sopenharmony_ci default: 82862306a36Sopenharmony_ci return -EINVAL; 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci /* Reset all counters */ 83262306a36Sopenharmony_ci udma_reset_counters(uc); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci /* Hard reset: re-initialize the channel to reset */ 83562306a36Sopenharmony_ci if (hard) { 83662306a36Sopenharmony_ci struct udma_chan_config ucc_backup; 83762306a36Sopenharmony_ci int ret; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci memcpy(&ucc_backup, &uc->config, sizeof(uc->config)); 84062306a36Sopenharmony_ci uc->ud->ddev.device_free_chan_resources(&uc->vc.chan); 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci /* restore the channel configuration */ 84362306a36Sopenharmony_ci memcpy(&uc->config, &ucc_backup, sizeof(uc->config)); 84462306a36Sopenharmony_ci ret = uc->ud->ddev.device_alloc_chan_resources(&uc->vc.chan); 84562306a36Sopenharmony_ci if (ret) 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci /* 84962306a36Sopenharmony_ci * Setting forced teardown after forced reset helps recovering 85062306a36Sopenharmony_ci * the rchan. 85162306a36Sopenharmony_ci */ 85262306a36Sopenharmony_ci if (uc->config.dir == DMA_DEV_TO_MEM) 85362306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 85462306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN | 85562306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_TDOWN | 85662306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_FTDOWN); 85762306a36Sopenharmony_ci } 85862306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_IDLE; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci return 0; 86162306a36Sopenharmony_ci} 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cistatic void udma_start_desc(struct udma_chan *uc) 86462306a36Sopenharmony_ci{ 86562306a36Sopenharmony_ci struct udma_chan_config *ucc = &uc->config; 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_UDMA && ucc->pkt_mode && 86862306a36Sopenharmony_ci (uc->cyclic || ucc->dir == DMA_DEV_TO_MEM)) { 86962306a36Sopenharmony_ci int i; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci /* 87262306a36Sopenharmony_ci * UDMA only: Push all descriptors to ring for packet mode 87362306a36Sopenharmony_ci * cyclic or RX 87462306a36Sopenharmony_ci * PKTDMA supports pre-linked descriptor and cyclic is not 87562306a36Sopenharmony_ci * supported 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_ci for (i = 0; i < uc->desc->sglen; i++) 87862306a36Sopenharmony_ci udma_push_to_ring(uc, i); 87962306a36Sopenharmony_ci } else { 88062306a36Sopenharmony_ci udma_push_to_ring(uc, 0); 88162306a36Sopenharmony_ci } 88262306a36Sopenharmony_ci} 88362306a36Sopenharmony_ci 88462306a36Sopenharmony_cistatic bool udma_chan_needs_reconfiguration(struct udma_chan *uc) 88562306a36Sopenharmony_ci{ 88662306a36Sopenharmony_ci /* Only PDMAs have staticTR */ 88762306a36Sopenharmony_ci if (uc->config.ep_type == PSIL_EP_NATIVE) 88862306a36Sopenharmony_ci return false; 88962306a36Sopenharmony_ci 89062306a36Sopenharmony_ci /* Check if the staticTR configuration has changed for TX */ 89162306a36Sopenharmony_ci if (memcmp(&uc->static_tr, &uc->desc->static_tr, sizeof(uc->static_tr))) 89262306a36Sopenharmony_ci return true; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci return false; 89562306a36Sopenharmony_ci} 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_cistatic int udma_start(struct udma_chan *uc) 89862306a36Sopenharmony_ci{ 89962306a36Sopenharmony_ci struct virt_dma_desc *vd = vchan_next_desc(&uc->vc); 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci if (!vd) { 90262306a36Sopenharmony_ci uc->desc = NULL; 90362306a36Sopenharmony_ci return -ENOENT; 90462306a36Sopenharmony_ci } 90562306a36Sopenharmony_ci 90662306a36Sopenharmony_ci list_del(&vd->node); 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci uc->desc = to_udma_desc(&vd->tx); 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* Channel is already running and does not need reconfiguration */ 91162306a36Sopenharmony_ci if (udma_is_chan_running(uc) && !udma_chan_needs_reconfiguration(uc)) { 91262306a36Sopenharmony_ci udma_start_desc(uc); 91362306a36Sopenharmony_ci goto out; 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci /* Make sure that we clear the teardown bit, if it is set */ 91762306a36Sopenharmony_ci udma_reset_chan(uc, false); 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci /* Push descriptors before we start the channel */ 92062306a36Sopenharmony_ci udma_start_desc(uc); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci switch (uc->desc->dir) { 92362306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 92462306a36Sopenharmony_ci /* Config remote TR */ 92562306a36Sopenharmony_ci if (uc->config.ep_type == PSIL_EP_PDMA_XY) { 92662306a36Sopenharmony_ci u32 val = PDMA_STATIC_TR_Y(uc->desc->static_tr.elcnt) | 92762306a36Sopenharmony_ci PDMA_STATIC_TR_X(uc->desc->static_tr.elsize); 92862306a36Sopenharmony_ci const struct udma_match_data *match_data = 92962306a36Sopenharmony_ci uc->ud->match_data; 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci if (uc->config.enable_acc32) 93262306a36Sopenharmony_ci val |= PDMA_STATIC_TR_XY_ACC32; 93362306a36Sopenharmony_ci if (uc->config.enable_burst) 93462306a36Sopenharmony_ci val |= PDMA_STATIC_TR_XY_BURST; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci udma_rchanrt_write(uc, 93762306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_STATIC_TR_XY_REG, 93862306a36Sopenharmony_ci val); 93962306a36Sopenharmony_ci 94062306a36Sopenharmony_ci udma_rchanrt_write(uc, 94162306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_STATIC_TR_Z_REG, 94262306a36Sopenharmony_ci PDMA_STATIC_TR_Z(uc->desc->static_tr.bstcnt, 94362306a36Sopenharmony_ci match_data->statictr_z_mask)); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci /* save the current staticTR configuration */ 94662306a36Sopenharmony_ci memcpy(&uc->static_tr, &uc->desc->static_tr, 94762306a36Sopenharmony_ci sizeof(uc->static_tr)); 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 95162306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci /* Enable remote */ 95462306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 95562306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE); 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci break; 95862306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 95962306a36Sopenharmony_ci /* Config remote TR */ 96062306a36Sopenharmony_ci if (uc->config.ep_type == PSIL_EP_PDMA_XY) { 96162306a36Sopenharmony_ci u32 val = PDMA_STATIC_TR_Y(uc->desc->static_tr.elcnt) | 96262306a36Sopenharmony_ci PDMA_STATIC_TR_X(uc->desc->static_tr.elsize); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci if (uc->config.enable_acc32) 96562306a36Sopenharmony_ci val |= PDMA_STATIC_TR_XY_ACC32; 96662306a36Sopenharmony_ci if (uc->config.enable_burst) 96762306a36Sopenharmony_ci val |= PDMA_STATIC_TR_XY_BURST; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci udma_tchanrt_write(uc, 97062306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_STATIC_TR_XY_REG, 97162306a36Sopenharmony_ci val); 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci /* save the current staticTR configuration */ 97462306a36Sopenharmony_ci memcpy(&uc->static_tr, &uc->desc->static_tr, 97562306a36Sopenharmony_ci sizeof(uc->static_tr)); 97662306a36Sopenharmony_ci } 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci /* Enable remote */ 97962306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 98062306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 98362306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci break; 98662306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 98762306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 98862306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 98962306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 99062306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci break; 99362306a36Sopenharmony_ci default: 99462306a36Sopenharmony_ci return -EINVAL; 99562306a36Sopenharmony_ci } 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_ACTIVE; 99862306a36Sopenharmony_ciout: 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci return 0; 100162306a36Sopenharmony_ci} 100262306a36Sopenharmony_ci 100362306a36Sopenharmony_cistatic int udma_stop(struct udma_chan *uc) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci enum udma_chan_state old_state = uc->state; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_TERMINATING; 100862306a36Sopenharmony_ci reinit_completion(&uc->teardown_completed); 100962306a36Sopenharmony_ci 101062306a36Sopenharmony_ci switch (uc->config.dir) { 101162306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 101262306a36Sopenharmony_ci if (!uc->cyclic && !uc->desc) 101362306a36Sopenharmony_ci udma_push_to_ring(uc, -1); 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_ci udma_rchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 101662306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE | 101762306a36Sopenharmony_ci UDMA_PEER_RT_EN_TEARDOWN); 101862306a36Sopenharmony_ci break; 101962306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 102062306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 102162306a36Sopenharmony_ci UDMA_PEER_RT_EN_ENABLE | 102262306a36Sopenharmony_ci UDMA_PEER_RT_EN_FLUSH); 102362306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 102462306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN | 102562306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_TDOWN); 102662306a36Sopenharmony_ci break; 102762306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 102862306a36Sopenharmony_ci udma_tchanrt_write(uc, UDMA_CHAN_RT_CTL_REG, 102962306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_EN | 103062306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_TDOWN); 103162306a36Sopenharmony_ci break; 103262306a36Sopenharmony_ci default: 103362306a36Sopenharmony_ci uc->state = old_state; 103462306a36Sopenharmony_ci complete_all(&uc->teardown_completed); 103562306a36Sopenharmony_ci return -EINVAL; 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci 103862306a36Sopenharmony_ci return 0; 103962306a36Sopenharmony_ci} 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_cistatic void udma_cyclic_packet_elapsed(struct udma_chan *uc) 104262306a36Sopenharmony_ci{ 104362306a36Sopenharmony_ci struct udma_desc *d = uc->desc; 104462306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci h_desc = d->hwdesc[d->desc_idx].cppi5_desc_vaddr; 104762306a36Sopenharmony_ci cppi5_hdesc_reset_to_original(h_desc); 104862306a36Sopenharmony_ci udma_push_to_ring(uc, d->desc_idx); 104962306a36Sopenharmony_ci d->desc_idx = (d->desc_idx + 1) % d->sglen; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_cistatic inline void udma_fetch_epib(struct udma_chan *uc, struct udma_desc *d) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc = d->hwdesc[0].cppi5_desc_vaddr; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci memcpy(d->metadata, h_desc->epib, d->metadata_size); 105762306a36Sopenharmony_ci} 105862306a36Sopenharmony_ci 105962306a36Sopenharmony_cistatic bool udma_is_desc_really_done(struct udma_chan *uc, struct udma_desc *d) 106062306a36Sopenharmony_ci{ 106162306a36Sopenharmony_ci u32 peer_bcnt, bcnt; 106262306a36Sopenharmony_ci 106362306a36Sopenharmony_ci /* 106462306a36Sopenharmony_ci * Only TX towards PDMA is affected. 106562306a36Sopenharmony_ci * If DMA_PREP_INTERRUPT is not set by consumer then skip the transfer 106662306a36Sopenharmony_ci * completion calculation, consumer must ensure that there is no stale 106762306a36Sopenharmony_ci * data in DMA fabric in this case. 106862306a36Sopenharmony_ci */ 106962306a36Sopenharmony_ci if (uc->config.ep_type == PSIL_EP_NATIVE || 107062306a36Sopenharmony_ci uc->config.dir != DMA_MEM_TO_DEV || !(uc->config.tx_flags & DMA_PREP_INTERRUPT)) 107162306a36Sopenharmony_ci return true; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci peer_bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_PEER_BCNT_REG); 107462306a36Sopenharmony_ci bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci /* Transfer is incomplete, store current residue and time stamp */ 107762306a36Sopenharmony_ci if (peer_bcnt < bcnt) { 107862306a36Sopenharmony_ci uc->tx_drain.residue = bcnt - peer_bcnt; 107962306a36Sopenharmony_ci uc->tx_drain.tstamp = ktime_get(); 108062306a36Sopenharmony_ci return false; 108162306a36Sopenharmony_ci } 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return true; 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic void udma_check_tx_completion(struct work_struct *work) 108762306a36Sopenharmony_ci{ 108862306a36Sopenharmony_ci struct udma_chan *uc = container_of(work, typeof(*uc), 108962306a36Sopenharmony_ci tx_drain.work.work); 109062306a36Sopenharmony_ci bool desc_done = true; 109162306a36Sopenharmony_ci u32 residue_diff; 109262306a36Sopenharmony_ci ktime_t time_diff; 109362306a36Sopenharmony_ci unsigned long delay; 109462306a36Sopenharmony_ci 109562306a36Sopenharmony_ci while (1) { 109662306a36Sopenharmony_ci if (uc->desc) { 109762306a36Sopenharmony_ci /* Get previous residue and time stamp */ 109862306a36Sopenharmony_ci residue_diff = uc->tx_drain.residue; 109962306a36Sopenharmony_ci time_diff = uc->tx_drain.tstamp; 110062306a36Sopenharmony_ci /* 110162306a36Sopenharmony_ci * Get current residue and time stamp or see if 110262306a36Sopenharmony_ci * transfer is complete 110362306a36Sopenharmony_ci */ 110462306a36Sopenharmony_ci desc_done = udma_is_desc_really_done(uc, uc->desc); 110562306a36Sopenharmony_ci } 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci if (!desc_done) { 110862306a36Sopenharmony_ci /* 110962306a36Sopenharmony_ci * Find the time delta and residue delta w.r.t 111062306a36Sopenharmony_ci * previous poll 111162306a36Sopenharmony_ci */ 111262306a36Sopenharmony_ci time_diff = ktime_sub(uc->tx_drain.tstamp, 111362306a36Sopenharmony_ci time_diff) + 1; 111462306a36Sopenharmony_ci residue_diff -= uc->tx_drain.residue; 111562306a36Sopenharmony_ci if (residue_diff) { 111662306a36Sopenharmony_ci /* 111762306a36Sopenharmony_ci * Try to guess when we should check 111862306a36Sopenharmony_ci * next time by calculating rate at 111962306a36Sopenharmony_ci * which data is being drained at the 112062306a36Sopenharmony_ci * peer device 112162306a36Sopenharmony_ci */ 112262306a36Sopenharmony_ci delay = (time_diff / residue_diff) * 112362306a36Sopenharmony_ci uc->tx_drain.residue; 112462306a36Sopenharmony_ci } else { 112562306a36Sopenharmony_ci /* No progress, check again in 1 second */ 112662306a36Sopenharmony_ci schedule_delayed_work(&uc->tx_drain.work, HZ); 112762306a36Sopenharmony_ci break; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci usleep_range(ktime_to_us(delay), 113162306a36Sopenharmony_ci ktime_to_us(delay) + 10); 113262306a36Sopenharmony_ci continue; 113362306a36Sopenharmony_ci } 113462306a36Sopenharmony_ci 113562306a36Sopenharmony_ci if (uc->desc) { 113662306a36Sopenharmony_ci struct udma_desc *d = uc->desc; 113762306a36Sopenharmony_ci 113862306a36Sopenharmony_ci udma_decrement_byte_counters(uc, d->residue); 113962306a36Sopenharmony_ci udma_start(uc); 114062306a36Sopenharmony_ci vchan_cookie_complete(&d->vd); 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci } 114362306a36Sopenharmony_ci 114462306a36Sopenharmony_ci break; 114562306a36Sopenharmony_ci } 114662306a36Sopenharmony_ci} 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_cistatic irqreturn_t udma_ring_irq_handler(int irq, void *data) 114962306a36Sopenharmony_ci{ 115062306a36Sopenharmony_ci struct udma_chan *uc = data; 115162306a36Sopenharmony_ci struct udma_desc *d; 115262306a36Sopenharmony_ci dma_addr_t paddr = 0; 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci if (udma_pop_from_ring(uc, &paddr) || !paddr) 115562306a36Sopenharmony_ci return IRQ_HANDLED; 115662306a36Sopenharmony_ci 115762306a36Sopenharmony_ci spin_lock(&uc->vc.lock); 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_ci /* Teardown completion message */ 116062306a36Sopenharmony_ci if (cppi5_desc_is_tdcm(paddr)) { 116162306a36Sopenharmony_ci complete_all(&uc->teardown_completed); 116262306a36Sopenharmony_ci 116362306a36Sopenharmony_ci if (uc->terminated_desc) { 116462306a36Sopenharmony_ci udma_desc_free(&uc->terminated_desc->vd); 116562306a36Sopenharmony_ci uc->terminated_desc = NULL; 116662306a36Sopenharmony_ci } 116762306a36Sopenharmony_ci 116862306a36Sopenharmony_ci if (!uc->desc) 116962306a36Sopenharmony_ci udma_start(uc); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci goto out; 117262306a36Sopenharmony_ci } 117362306a36Sopenharmony_ci 117462306a36Sopenharmony_ci d = udma_udma_desc_from_paddr(uc, paddr); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci if (d) { 117762306a36Sopenharmony_ci dma_addr_t desc_paddr = udma_curr_cppi5_desc_paddr(d, 117862306a36Sopenharmony_ci d->desc_idx); 117962306a36Sopenharmony_ci if (desc_paddr != paddr) { 118062306a36Sopenharmony_ci dev_err(uc->ud->dev, "not matching descriptors!\n"); 118162306a36Sopenharmony_ci goto out; 118262306a36Sopenharmony_ci } 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (d == uc->desc) { 118562306a36Sopenharmony_ci /* active descriptor */ 118662306a36Sopenharmony_ci if (uc->cyclic) { 118762306a36Sopenharmony_ci udma_cyclic_packet_elapsed(uc); 118862306a36Sopenharmony_ci vchan_cyclic_callback(&d->vd); 118962306a36Sopenharmony_ci } else { 119062306a36Sopenharmony_ci if (udma_is_desc_really_done(uc, d)) { 119162306a36Sopenharmony_ci udma_decrement_byte_counters(uc, d->residue); 119262306a36Sopenharmony_ci udma_start(uc); 119362306a36Sopenharmony_ci vchan_cookie_complete(&d->vd); 119462306a36Sopenharmony_ci } else { 119562306a36Sopenharmony_ci schedule_delayed_work(&uc->tx_drain.work, 119662306a36Sopenharmony_ci 0); 119762306a36Sopenharmony_ci } 119862306a36Sopenharmony_ci } 119962306a36Sopenharmony_ci } else { 120062306a36Sopenharmony_ci /* 120162306a36Sopenharmony_ci * terminated descriptor, mark the descriptor as 120262306a36Sopenharmony_ci * completed to update the channel's cookie marker 120362306a36Sopenharmony_ci */ 120462306a36Sopenharmony_ci dma_cookie_complete(&d->vd.tx); 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci } 120762306a36Sopenharmony_ciout: 120862306a36Sopenharmony_ci spin_unlock(&uc->vc.lock); 120962306a36Sopenharmony_ci 121062306a36Sopenharmony_ci return IRQ_HANDLED; 121162306a36Sopenharmony_ci} 121262306a36Sopenharmony_ci 121362306a36Sopenharmony_cistatic irqreturn_t udma_udma_irq_handler(int irq, void *data) 121462306a36Sopenharmony_ci{ 121562306a36Sopenharmony_ci struct udma_chan *uc = data; 121662306a36Sopenharmony_ci struct udma_desc *d; 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci spin_lock(&uc->vc.lock); 121962306a36Sopenharmony_ci d = uc->desc; 122062306a36Sopenharmony_ci if (d) { 122162306a36Sopenharmony_ci d->tr_idx = (d->tr_idx + 1) % d->sglen; 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (uc->cyclic) { 122462306a36Sopenharmony_ci vchan_cyclic_callback(&d->vd); 122562306a36Sopenharmony_ci } else { 122662306a36Sopenharmony_ci /* TODO: figure out the real amount of data */ 122762306a36Sopenharmony_ci udma_decrement_byte_counters(uc, d->residue); 122862306a36Sopenharmony_ci udma_start(uc); 122962306a36Sopenharmony_ci vchan_cookie_complete(&d->vd); 123062306a36Sopenharmony_ci } 123162306a36Sopenharmony_ci } 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci spin_unlock(&uc->vc.lock); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return IRQ_HANDLED; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci/** 123962306a36Sopenharmony_ci * __udma_alloc_gp_rflow_range - alloc range of GP RX flows 124062306a36Sopenharmony_ci * @ud: UDMA device 124162306a36Sopenharmony_ci * @from: Start the search from this flow id number 124262306a36Sopenharmony_ci * @cnt: Number of consecutive flow ids to allocate 124362306a36Sopenharmony_ci * 124462306a36Sopenharmony_ci * Allocate range of RX flow ids for future use, those flows can be requested 124562306a36Sopenharmony_ci * only using explicit flow id number. if @from is set to -1 it will try to find 124662306a36Sopenharmony_ci * first free range. if @from is positive value it will force allocation only 124762306a36Sopenharmony_ci * of the specified range of flows. 124862306a36Sopenharmony_ci * 124962306a36Sopenharmony_ci * Returns -ENOMEM if can't find free range. 125062306a36Sopenharmony_ci * -EEXIST if requested range is busy. 125162306a36Sopenharmony_ci * -EINVAL if wrong input values passed. 125262306a36Sopenharmony_ci * Returns flow id on success. 125362306a36Sopenharmony_ci */ 125462306a36Sopenharmony_cistatic int __udma_alloc_gp_rflow_range(struct udma_dev *ud, int from, int cnt) 125562306a36Sopenharmony_ci{ 125662306a36Sopenharmony_ci int start, tmp_from; 125762306a36Sopenharmony_ci DECLARE_BITMAP(tmp, K3_UDMA_MAX_RFLOWS); 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_ci tmp_from = from; 126062306a36Sopenharmony_ci if (tmp_from < 0) 126162306a36Sopenharmony_ci tmp_from = ud->rchan_cnt; 126262306a36Sopenharmony_ci /* default flows can't be allocated and accessible only by id */ 126362306a36Sopenharmony_ci if (tmp_from < ud->rchan_cnt) 126462306a36Sopenharmony_ci return -EINVAL; 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci if (tmp_from + cnt > ud->rflow_cnt) 126762306a36Sopenharmony_ci return -EINVAL; 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci bitmap_or(tmp, ud->rflow_gp_map, ud->rflow_gp_map_allocated, 127062306a36Sopenharmony_ci ud->rflow_cnt); 127162306a36Sopenharmony_ci 127262306a36Sopenharmony_ci start = bitmap_find_next_zero_area(tmp, 127362306a36Sopenharmony_ci ud->rflow_cnt, 127462306a36Sopenharmony_ci tmp_from, cnt, 0); 127562306a36Sopenharmony_ci if (start >= ud->rflow_cnt) 127662306a36Sopenharmony_ci return -ENOMEM; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci if (from >= 0 && start != from) 127962306a36Sopenharmony_ci return -EEXIST; 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci bitmap_set(ud->rflow_gp_map_allocated, start, cnt); 128262306a36Sopenharmony_ci return start; 128362306a36Sopenharmony_ci} 128462306a36Sopenharmony_ci 128562306a36Sopenharmony_cistatic int __udma_free_gp_rflow_range(struct udma_dev *ud, int from, int cnt) 128662306a36Sopenharmony_ci{ 128762306a36Sopenharmony_ci if (from < ud->rchan_cnt) 128862306a36Sopenharmony_ci return -EINVAL; 128962306a36Sopenharmony_ci if (from + cnt > ud->rflow_cnt) 129062306a36Sopenharmony_ci return -EINVAL; 129162306a36Sopenharmony_ci 129262306a36Sopenharmony_ci bitmap_clear(ud->rflow_gp_map_allocated, from, cnt); 129362306a36Sopenharmony_ci return 0; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic struct udma_rflow *__udma_get_rflow(struct udma_dev *ud, int id) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci /* 129962306a36Sopenharmony_ci * Attempt to request rflow by ID can be made for any rflow 130062306a36Sopenharmony_ci * if not in use with assumption that caller knows what's doing. 130162306a36Sopenharmony_ci * TI-SCI FW will perform additional permission check ant way, it's 130262306a36Sopenharmony_ci * safe 130362306a36Sopenharmony_ci */ 130462306a36Sopenharmony_ci 130562306a36Sopenharmony_ci if (id < 0 || id >= ud->rflow_cnt) 130662306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci if (test_bit(id, ud->rflow_in_use)) 130962306a36Sopenharmony_ci return ERR_PTR(-ENOENT); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci if (ud->rflow_gp_map) { 131262306a36Sopenharmony_ci /* GP rflow has to be allocated first */ 131362306a36Sopenharmony_ci if (!test_bit(id, ud->rflow_gp_map) && 131462306a36Sopenharmony_ci !test_bit(id, ud->rflow_gp_map_allocated)) 131562306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 131662306a36Sopenharmony_ci } 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci dev_dbg(ud->dev, "get rflow%d\n", id); 131962306a36Sopenharmony_ci set_bit(id, ud->rflow_in_use); 132062306a36Sopenharmony_ci return &ud->rflows[id]; 132162306a36Sopenharmony_ci} 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_cistatic void __udma_put_rflow(struct udma_dev *ud, struct udma_rflow *rflow) 132462306a36Sopenharmony_ci{ 132562306a36Sopenharmony_ci if (!test_bit(rflow->id, ud->rflow_in_use)) { 132662306a36Sopenharmony_ci dev_err(ud->dev, "attempt to put unused rflow%d\n", rflow->id); 132762306a36Sopenharmony_ci return; 132862306a36Sopenharmony_ci } 132962306a36Sopenharmony_ci 133062306a36Sopenharmony_ci dev_dbg(ud->dev, "put rflow%d\n", rflow->id); 133162306a36Sopenharmony_ci clear_bit(rflow->id, ud->rflow_in_use); 133262306a36Sopenharmony_ci} 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci#define UDMA_RESERVE_RESOURCE(res) \ 133562306a36Sopenharmony_cistatic struct udma_##res *__udma_reserve_##res(struct udma_dev *ud, \ 133662306a36Sopenharmony_ci enum udma_tp_level tpl, \ 133762306a36Sopenharmony_ci int id) \ 133862306a36Sopenharmony_ci{ \ 133962306a36Sopenharmony_ci if (id >= 0) { \ 134062306a36Sopenharmony_ci if (test_bit(id, ud->res##_map)) { \ 134162306a36Sopenharmony_ci dev_err(ud->dev, "res##%d is in use\n", id); \ 134262306a36Sopenharmony_ci return ERR_PTR(-ENOENT); \ 134362306a36Sopenharmony_ci } \ 134462306a36Sopenharmony_ci } else { \ 134562306a36Sopenharmony_ci int start; \ 134662306a36Sopenharmony_ci \ 134762306a36Sopenharmony_ci if (tpl >= ud->res##_tpl.levels) \ 134862306a36Sopenharmony_ci tpl = ud->res##_tpl.levels - 1; \ 134962306a36Sopenharmony_ci \ 135062306a36Sopenharmony_ci start = ud->res##_tpl.start_idx[tpl]; \ 135162306a36Sopenharmony_ci \ 135262306a36Sopenharmony_ci id = find_next_zero_bit(ud->res##_map, ud->res##_cnt, \ 135362306a36Sopenharmony_ci start); \ 135462306a36Sopenharmony_ci if (id == ud->res##_cnt) { \ 135562306a36Sopenharmony_ci return ERR_PTR(-ENOENT); \ 135662306a36Sopenharmony_ci } \ 135762306a36Sopenharmony_ci } \ 135862306a36Sopenharmony_ci \ 135962306a36Sopenharmony_ci set_bit(id, ud->res##_map); \ 136062306a36Sopenharmony_ci return &ud->res##s[id]; \ 136162306a36Sopenharmony_ci} 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(bchan); 136462306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(tchan); 136562306a36Sopenharmony_ciUDMA_RESERVE_RESOURCE(rchan); 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_cistatic int bcdma_get_bchan(struct udma_chan *uc) 136862306a36Sopenharmony_ci{ 136962306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 137062306a36Sopenharmony_ci enum udma_tp_level tpl; 137162306a36Sopenharmony_ci int ret; 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci if (uc->bchan) { 137462306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: already have bchan%d allocated\n", 137562306a36Sopenharmony_ci uc->id, uc->bchan->id); 137662306a36Sopenharmony_ci return 0; 137762306a36Sopenharmony_ci } 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci /* 138062306a36Sopenharmony_ci * Use normal channels for peripherals, and highest TPL channel for 138162306a36Sopenharmony_ci * mem2mem 138262306a36Sopenharmony_ci */ 138362306a36Sopenharmony_ci if (uc->config.tr_trigger_type) 138462306a36Sopenharmony_ci tpl = 0; 138562306a36Sopenharmony_ci else 138662306a36Sopenharmony_ci tpl = ud->bchan_tpl.levels - 1; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci uc->bchan = __udma_reserve_bchan(ud, tpl, -1); 138962306a36Sopenharmony_ci if (IS_ERR(uc->bchan)) { 139062306a36Sopenharmony_ci ret = PTR_ERR(uc->bchan); 139162306a36Sopenharmony_ci uc->bchan = NULL; 139262306a36Sopenharmony_ci return ret; 139362306a36Sopenharmony_ci } 139462306a36Sopenharmony_ci 139562306a36Sopenharmony_ci uc->tchan = uc->bchan; 139662306a36Sopenharmony_ci 139762306a36Sopenharmony_ci return 0; 139862306a36Sopenharmony_ci} 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_cistatic int udma_get_tchan(struct udma_chan *uc) 140162306a36Sopenharmony_ci{ 140262306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 140362306a36Sopenharmony_ci int ret; 140462306a36Sopenharmony_ci 140562306a36Sopenharmony_ci if (uc->tchan) { 140662306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: already have tchan%d allocated\n", 140762306a36Sopenharmony_ci uc->id, uc->tchan->id); 140862306a36Sopenharmony_ci return 0; 140962306a36Sopenharmony_ci } 141062306a36Sopenharmony_ci 141162306a36Sopenharmony_ci /* 141262306a36Sopenharmony_ci * mapped_channel_id is -1 for UDMA, BCDMA and PKTDMA unmapped channels. 141362306a36Sopenharmony_ci * For PKTDMA mapped channels it is configured to a channel which must 141462306a36Sopenharmony_ci * be used to service the peripheral. 141562306a36Sopenharmony_ci */ 141662306a36Sopenharmony_ci uc->tchan = __udma_reserve_tchan(ud, uc->config.channel_tpl, 141762306a36Sopenharmony_ci uc->config.mapped_channel_id); 141862306a36Sopenharmony_ci if (IS_ERR(uc->tchan)) { 141962306a36Sopenharmony_ci ret = PTR_ERR(uc->tchan); 142062306a36Sopenharmony_ci uc->tchan = NULL; 142162306a36Sopenharmony_ci return ret; 142262306a36Sopenharmony_ci } 142362306a36Sopenharmony_ci 142462306a36Sopenharmony_ci if (ud->tflow_cnt) { 142562306a36Sopenharmony_ci int tflow_id; 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci /* Only PKTDMA have support for tx flows */ 142862306a36Sopenharmony_ci if (uc->config.default_flow_id >= 0) 142962306a36Sopenharmony_ci tflow_id = uc->config.default_flow_id; 143062306a36Sopenharmony_ci else 143162306a36Sopenharmony_ci tflow_id = uc->tchan->id; 143262306a36Sopenharmony_ci 143362306a36Sopenharmony_ci if (test_bit(tflow_id, ud->tflow_map)) { 143462306a36Sopenharmony_ci dev_err(ud->dev, "tflow%d is in use\n", tflow_id); 143562306a36Sopenharmony_ci clear_bit(uc->tchan->id, ud->tchan_map); 143662306a36Sopenharmony_ci uc->tchan = NULL; 143762306a36Sopenharmony_ci return -ENOENT; 143862306a36Sopenharmony_ci } 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci uc->tchan->tflow_id = tflow_id; 144162306a36Sopenharmony_ci set_bit(tflow_id, ud->tflow_map); 144262306a36Sopenharmony_ci } else { 144362306a36Sopenharmony_ci uc->tchan->tflow_id = -1; 144462306a36Sopenharmony_ci } 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci return 0; 144762306a36Sopenharmony_ci} 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_cistatic int udma_get_rchan(struct udma_chan *uc) 145062306a36Sopenharmony_ci{ 145162306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 145262306a36Sopenharmony_ci int ret; 145362306a36Sopenharmony_ci 145462306a36Sopenharmony_ci if (uc->rchan) { 145562306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: already have rchan%d allocated\n", 145662306a36Sopenharmony_ci uc->id, uc->rchan->id); 145762306a36Sopenharmony_ci return 0; 145862306a36Sopenharmony_ci } 145962306a36Sopenharmony_ci 146062306a36Sopenharmony_ci /* 146162306a36Sopenharmony_ci * mapped_channel_id is -1 for UDMA, BCDMA and PKTDMA unmapped channels. 146262306a36Sopenharmony_ci * For PKTDMA mapped channels it is configured to a channel which must 146362306a36Sopenharmony_ci * be used to service the peripheral. 146462306a36Sopenharmony_ci */ 146562306a36Sopenharmony_ci uc->rchan = __udma_reserve_rchan(ud, uc->config.channel_tpl, 146662306a36Sopenharmony_ci uc->config.mapped_channel_id); 146762306a36Sopenharmony_ci if (IS_ERR(uc->rchan)) { 146862306a36Sopenharmony_ci ret = PTR_ERR(uc->rchan); 146962306a36Sopenharmony_ci uc->rchan = NULL; 147062306a36Sopenharmony_ci return ret; 147162306a36Sopenharmony_ci } 147262306a36Sopenharmony_ci 147362306a36Sopenharmony_ci return 0; 147462306a36Sopenharmony_ci} 147562306a36Sopenharmony_ci 147662306a36Sopenharmony_cistatic int udma_get_chan_pair(struct udma_chan *uc) 147762306a36Sopenharmony_ci{ 147862306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 147962306a36Sopenharmony_ci int chan_id, end; 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci if ((uc->tchan && uc->rchan) && uc->tchan->id == uc->rchan->id) { 148262306a36Sopenharmony_ci dev_info(ud->dev, "chan%d: already have %d pair allocated\n", 148362306a36Sopenharmony_ci uc->id, uc->tchan->id); 148462306a36Sopenharmony_ci return 0; 148562306a36Sopenharmony_ci } 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci if (uc->tchan) { 148862306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: already have tchan%d allocated\n", 148962306a36Sopenharmony_ci uc->id, uc->tchan->id); 149062306a36Sopenharmony_ci return -EBUSY; 149162306a36Sopenharmony_ci } else if (uc->rchan) { 149262306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: already have rchan%d allocated\n", 149362306a36Sopenharmony_ci uc->id, uc->rchan->id); 149462306a36Sopenharmony_ci return -EBUSY; 149562306a36Sopenharmony_ci } 149662306a36Sopenharmony_ci 149762306a36Sopenharmony_ci /* Can be optimized, but let's have it like this for now */ 149862306a36Sopenharmony_ci end = min(ud->tchan_cnt, ud->rchan_cnt); 149962306a36Sopenharmony_ci /* 150062306a36Sopenharmony_ci * Try to use the highest TPL channel pair for MEM_TO_MEM channels 150162306a36Sopenharmony_ci * Note: in UDMAP the channel TPL is symmetric between tchan and rchan 150262306a36Sopenharmony_ci */ 150362306a36Sopenharmony_ci chan_id = ud->tchan_tpl.start_idx[ud->tchan_tpl.levels - 1]; 150462306a36Sopenharmony_ci for (; chan_id < end; chan_id++) { 150562306a36Sopenharmony_ci if (!test_bit(chan_id, ud->tchan_map) && 150662306a36Sopenharmony_ci !test_bit(chan_id, ud->rchan_map)) 150762306a36Sopenharmony_ci break; 150862306a36Sopenharmony_ci } 150962306a36Sopenharmony_ci 151062306a36Sopenharmony_ci if (chan_id == end) 151162306a36Sopenharmony_ci return -ENOENT; 151262306a36Sopenharmony_ci 151362306a36Sopenharmony_ci set_bit(chan_id, ud->tchan_map); 151462306a36Sopenharmony_ci set_bit(chan_id, ud->rchan_map); 151562306a36Sopenharmony_ci uc->tchan = &ud->tchans[chan_id]; 151662306a36Sopenharmony_ci uc->rchan = &ud->rchans[chan_id]; 151762306a36Sopenharmony_ci 151862306a36Sopenharmony_ci /* UDMA does not use tx flows */ 151962306a36Sopenharmony_ci uc->tchan->tflow_id = -1; 152062306a36Sopenharmony_ci 152162306a36Sopenharmony_ci return 0; 152262306a36Sopenharmony_ci} 152362306a36Sopenharmony_ci 152462306a36Sopenharmony_cistatic int udma_get_rflow(struct udma_chan *uc, int flow_id) 152562306a36Sopenharmony_ci{ 152662306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 152762306a36Sopenharmony_ci int ret; 152862306a36Sopenharmony_ci 152962306a36Sopenharmony_ci if (!uc->rchan) { 153062306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: does not have rchan??\n", uc->id); 153162306a36Sopenharmony_ci return -EINVAL; 153262306a36Sopenharmony_ci } 153362306a36Sopenharmony_ci 153462306a36Sopenharmony_ci if (uc->rflow) { 153562306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: already have rflow%d allocated\n", 153662306a36Sopenharmony_ci uc->id, uc->rflow->id); 153762306a36Sopenharmony_ci return 0; 153862306a36Sopenharmony_ci } 153962306a36Sopenharmony_ci 154062306a36Sopenharmony_ci uc->rflow = __udma_get_rflow(ud, flow_id); 154162306a36Sopenharmony_ci if (IS_ERR(uc->rflow)) { 154262306a36Sopenharmony_ci ret = PTR_ERR(uc->rflow); 154362306a36Sopenharmony_ci uc->rflow = NULL; 154462306a36Sopenharmony_ci return ret; 154562306a36Sopenharmony_ci } 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci return 0; 154862306a36Sopenharmony_ci} 154962306a36Sopenharmony_ci 155062306a36Sopenharmony_cistatic void bcdma_put_bchan(struct udma_chan *uc) 155162306a36Sopenharmony_ci{ 155262306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 155362306a36Sopenharmony_ci 155462306a36Sopenharmony_ci if (uc->bchan) { 155562306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: put bchan%d\n", uc->id, 155662306a36Sopenharmony_ci uc->bchan->id); 155762306a36Sopenharmony_ci clear_bit(uc->bchan->id, ud->bchan_map); 155862306a36Sopenharmony_ci uc->bchan = NULL; 155962306a36Sopenharmony_ci uc->tchan = NULL; 156062306a36Sopenharmony_ci } 156162306a36Sopenharmony_ci} 156262306a36Sopenharmony_ci 156362306a36Sopenharmony_cistatic void udma_put_rchan(struct udma_chan *uc) 156462306a36Sopenharmony_ci{ 156562306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 156662306a36Sopenharmony_ci 156762306a36Sopenharmony_ci if (uc->rchan) { 156862306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: put rchan%d\n", uc->id, 156962306a36Sopenharmony_ci uc->rchan->id); 157062306a36Sopenharmony_ci clear_bit(uc->rchan->id, ud->rchan_map); 157162306a36Sopenharmony_ci uc->rchan = NULL; 157262306a36Sopenharmony_ci } 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cistatic void udma_put_tchan(struct udma_chan *uc) 157662306a36Sopenharmony_ci{ 157762306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci if (uc->tchan) { 158062306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: put tchan%d\n", uc->id, 158162306a36Sopenharmony_ci uc->tchan->id); 158262306a36Sopenharmony_ci clear_bit(uc->tchan->id, ud->tchan_map); 158362306a36Sopenharmony_ci 158462306a36Sopenharmony_ci if (uc->tchan->tflow_id >= 0) 158562306a36Sopenharmony_ci clear_bit(uc->tchan->tflow_id, ud->tflow_map); 158662306a36Sopenharmony_ci 158762306a36Sopenharmony_ci uc->tchan = NULL; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ci} 159062306a36Sopenharmony_ci 159162306a36Sopenharmony_cistatic void udma_put_rflow(struct udma_chan *uc) 159262306a36Sopenharmony_ci{ 159362306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci if (uc->rflow) { 159662306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: put rflow%d\n", uc->id, 159762306a36Sopenharmony_ci uc->rflow->id); 159862306a36Sopenharmony_ci __udma_put_rflow(ud, uc->rflow); 159962306a36Sopenharmony_ci uc->rflow = NULL; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci} 160262306a36Sopenharmony_ci 160362306a36Sopenharmony_cistatic void bcdma_free_bchan_resources(struct udma_chan *uc) 160462306a36Sopenharmony_ci{ 160562306a36Sopenharmony_ci if (!uc->bchan) 160662306a36Sopenharmony_ci return; 160762306a36Sopenharmony_ci 160862306a36Sopenharmony_ci k3_ringacc_ring_free(uc->bchan->tc_ring); 160962306a36Sopenharmony_ci k3_ringacc_ring_free(uc->bchan->t_ring); 161062306a36Sopenharmony_ci uc->bchan->tc_ring = NULL; 161162306a36Sopenharmony_ci uc->bchan->t_ring = NULL; 161262306a36Sopenharmony_ci k3_configure_chan_coherency(&uc->vc.chan, 0); 161362306a36Sopenharmony_ci 161462306a36Sopenharmony_ci bcdma_put_bchan(uc); 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic int bcdma_alloc_bchan_resources(struct udma_chan *uc) 161862306a36Sopenharmony_ci{ 161962306a36Sopenharmony_ci struct k3_ring_cfg ring_cfg; 162062306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 162162306a36Sopenharmony_ci int ret; 162262306a36Sopenharmony_ci 162362306a36Sopenharmony_ci ret = bcdma_get_bchan(uc); 162462306a36Sopenharmony_ci if (ret) 162562306a36Sopenharmony_ci return ret; 162662306a36Sopenharmony_ci 162762306a36Sopenharmony_ci ret = k3_ringacc_request_rings_pair(ud->ringacc, uc->bchan->id, -1, 162862306a36Sopenharmony_ci &uc->bchan->t_ring, 162962306a36Sopenharmony_ci &uc->bchan->tc_ring); 163062306a36Sopenharmony_ci if (ret) { 163162306a36Sopenharmony_ci ret = -EBUSY; 163262306a36Sopenharmony_ci goto err_ring; 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci 163562306a36Sopenharmony_ci memset(&ring_cfg, 0, sizeof(ring_cfg)); 163662306a36Sopenharmony_ci ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE; 163762306a36Sopenharmony_ci ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8; 163862306a36Sopenharmony_ci ring_cfg.mode = K3_RINGACC_RING_MODE_RING; 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci k3_configure_chan_coherency(&uc->vc.chan, ud->asel); 164162306a36Sopenharmony_ci ring_cfg.asel = ud->asel; 164262306a36Sopenharmony_ci ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan); 164362306a36Sopenharmony_ci 164462306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(uc->bchan->t_ring, &ring_cfg); 164562306a36Sopenharmony_ci if (ret) 164662306a36Sopenharmony_ci goto err_ringcfg; 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci return 0; 164962306a36Sopenharmony_ci 165062306a36Sopenharmony_cierr_ringcfg: 165162306a36Sopenharmony_ci k3_ringacc_ring_free(uc->bchan->tc_ring); 165262306a36Sopenharmony_ci uc->bchan->tc_ring = NULL; 165362306a36Sopenharmony_ci k3_ringacc_ring_free(uc->bchan->t_ring); 165462306a36Sopenharmony_ci uc->bchan->t_ring = NULL; 165562306a36Sopenharmony_ci k3_configure_chan_coherency(&uc->vc.chan, 0); 165662306a36Sopenharmony_cierr_ring: 165762306a36Sopenharmony_ci bcdma_put_bchan(uc); 165862306a36Sopenharmony_ci 165962306a36Sopenharmony_ci return ret; 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic void udma_free_tx_resources(struct udma_chan *uc) 166362306a36Sopenharmony_ci{ 166462306a36Sopenharmony_ci if (!uc->tchan) 166562306a36Sopenharmony_ci return; 166662306a36Sopenharmony_ci 166762306a36Sopenharmony_ci k3_ringacc_ring_free(uc->tchan->t_ring); 166862306a36Sopenharmony_ci k3_ringacc_ring_free(uc->tchan->tc_ring); 166962306a36Sopenharmony_ci uc->tchan->t_ring = NULL; 167062306a36Sopenharmony_ci uc->tchan->tc_ring = NULL; 167162306a36Sopenharmony_ci 167262306a36Sopenharmony_ci udma_put_tchan(uc); 167362306a36Sopenharmony_ci} 167462306a36Sopenharmony_ci 167562306a36Sopenharmony_cistatic int udma_alloc_tx_resources(struct udma_chan *uc) 167662306a36Sopenharmony_ci{ 167762306a36Sopenharmony_ci struct k3_ring_cfg ring_cfg; 167862306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 167962306a36Sopenharmony_ci struct udma_tchan *tchan; 168062306a36Sopenharmony_ci int ring_idx, ret; 168162306a36Sopenharmony_ci 168262306a36Sopenharmony_ci ret = udma_get_tchan(uc); 168362306a36Sopenharmony_ci if (ret) 168462306a36Sopenharmony_ci return ret; 168562306a36Sopenharmony_ci 168662306a36Sopenharmony_ci tchan = uc->tchan; 168762306a36Sopenharmony_ci if (tchan->tflow_id >= 0) 168862306a36Sopenharmony_ci ring_idx = tchan->tflow_id; 168962306a36Sopenharmony_ci else 169062306a36Sopenharmony_ci ring_idx = ud->bchan_cnt + tchan->id; 169162306a36Sopenharmony_ci 169262306a36Sopenharmony_ci ret = k3_ringacc_request_rings_pair(ud->ringacc, ring_idx, -1, 169362306a36Sopenharmony_ci &tchan->t_ring, 169462306a36Sopenharmony_ci &tchan->tc_ring); 169562306a36Sopenharmony_ci if (ret) { 169662306a36Sopenharmony_ci ret = -EBUSY; 169762306a36Sopenharmony_ci goto err_ring; 169862306a36Sopenharmony_ci } 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci memset(&ring_cfg, 0, sizeof(ring_cfg)); 170162306a36Sopenharmony_ci ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE; 170262306a36Sopenharmony_ci ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8; 170362306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_UDMA) { 170462306a36Sopenharmony_ci ring_cfg.mode = K3_RINGACC_RING_MODE_MESSAGE; 170562306a36Sopenharmony_ci } else { 170662306a36Sopenharmony_ci ring_cfg.mode = K3_RINGACC_RING_MODE_RING; 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci k3_configure_chan_coherency(&uc->vc.chan, uc->config.asel); 170962306a36Sopenharmony_ci ring_cfg.asel = uc->config.asel; 171062306a36Sopenharmony_ci ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan); 171162306a36Sopenharmony_ci } 171262306a36Sopenharmony_ci 171362306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(tchan->t_ring, &ring_cfg); 171462306a36Sopenharmony_ci ret |= k3_ringacc_ring_cfg(tchan->tc_ring, &ring_cfg); 171562306a36Sopenharmony_ci 171662306a36Sopenharmony_ci if (ret) 171762306a36Sopenharmony_ci goto err_ringcfg; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci return 0; 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cierr_ringcfg: 172262306a36Sopenharmony_ci k3_ringacc_ring_free(uc->tchan->tc_ring); 172362306a36Sopenharmony_ci uc->tchan->tc_ring = NULL; 172462306a36Sopenharmony_ci k3_ringacc_ring_free(uc->tchan->t_ring); 172562306a36Sopenharmony_ci uc->tchan->t_ring = NULL; 172662306a36Sopenharmony_cierr_ring: 172762306a36Sopenharmony_ci udma_put_tchan(uc); 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci return ret; 173062306a36Sopenharmony_ci} 173162306a36Sopenharmony_ci 173262306a36Sopenharmony_cistatic void udma_free_rx_resources(struct udma_chan *uc) 173362306a36Sopenharmony_ci{ 173462306a36Sopenharmony_ci if (!uc->rchan) 173562306a36Sopenharmony_ci return; 173662306a36Sopenharmony_ci 173762306a36Sopenharmony_ci if (uc->rflow) { 173862306a36Sopenharmony_ci struct udma_rflow *rflow = uc->rflow; 173962306a36Sopenharmony_ci 174062306a36Sopenharmony_ci k3_ringacc_ring_free(rflow->fd_ring); 174162306a36Sopenharmony_ci k3_ringacc_ring_free(rflow->r_ring); 174262306a36Sopenharmony_ci rflow->fd_ring = NULL; 174362306a36Sopenharmony_ci rflow->r_ring = NULL; 174462306a36Sopenharmony_ci 174562306a36Sopenharmony_ci udma_put_rflow(uc); 174662306a36Sopenharmony_ci } 174762306a36Sopenharmony_ci 174862306a36Sopenharmony_ci udma_put_rchan(uc); 174962306a36Sopenharmony_ci} 175062306a36Sopenharmony_ci 175162306a36Sopenharmony_cistatic int udma_alloc_rx_resources(struct udma_chan *uc) 175262306a36Sopenharmony_ci{ 175362306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 175462306a36Sopenharmony_ci struct k3_ring_cfg ring_cfg; 175562306a36Sopenharmony_ci struct udma_rflow *rflow; 175662306a36Sopenharmony_ci int fd_ring_id; 175762306a36Sopenharmony_ci int ret; 175862306a36Sopenharmony_ci 175962306a36Sopenharmony_ci ret = udma_get_rchan(uc); 176062306a36Sopenharmony_ci if (ret) 176162306a36Sopenharmony_ci return ret; 176262306a36Sopenharmony_ci 176362306a36Sopenharmony_ci /* For MEM_TO_MEM we don't need rflow or rings */ 176462306a36Sopenharmony_ci if (uc->config.dir == DMA_MEM_TO_MEM) 176562306a36Sopenharmony_ci return 0; 176662306a36Sopenharmony_ci 176762306a36Sopenharmony_ci if (uc->config.default_flow_id >= 0) 176862306a36Sopenharmony_ci ret = udma_get_rflow(uc, uc->config.default_flow_id); 176962306a36Sopenharmony_ci else 177062306a36Sopenharmony_ci ret = udma_get_rflow(uc, uc->rchan->id); 177162306a36Sopenharmony_ci 177262306a36Sopenharmony_ci if (ret) { 177362306a36Sopenharmony_ci ret = -EBUSY; 177462306a36Sopenharmony_ci goto err_rflow; 177562306a36Sopenharmony_ci } 177662306a36Sopenharmony_ci 177762306a36Sopenharmony_ci rflow = uc->rflow; 177862306a36Sopenharmony_ci if (ud->tflow_cnt) 177962306a36Sopenharmony_ci fd_ring_id = ud->tflow_cnt + rflow->id; 178062306a36Sopenharmony_ci else 178162306a36Sopenharmony_ci fd_ring_id = ud->bchan_cnt + ud->tchan_cnt + ud->echan_cnt + 178262306a36Sopenharmony_ci uc->rchan->id; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci ret = k3_ringacc_request_rings_pair(ud->ringacc, fd_ring_id, -1, 178562306a36Sopenharmony_ci &rflow->fd_ring, &rflow->r_ring); 178662306a36Sopenharmony_ci if (ret) { 178762306a36Sopenharmony_ci ret = -EBUSY; 178862306a36Sopenharmony_ci goto err_ring; 178962306a36Sopenharmony_ci } 179062306a36Sopenharmony_ci 179162306a36Sopenharmony_ci memset(&ring_cfg, 0, sizeof(ring_cfg)); 179262306a36Sopenharmony_ci 179362306a36Sopenharmony_ci ring_cfg.elm_size = K3_RINGACC_RING_ELSIZE_8; 179462306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_UDMA) { 179562306a36Sopenharmony_ci if (uc->config.pkt_mode) 179662306a36Sopenharmony_ci ring_cfg.size = SG_MAX_SEGMENTS; 179762306a36Sopenharmony_ci else 179862306a36Sopenharmony_ci ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE; 179962306a36Sopenharmony_ci 180062306a36Sopenharmony_ci ring_cfg.mode = K3_RINGACC_RING_MODE_MESSAGE; 180162306a36Sopenharmony_ci } else { 180262306a36Sopenharmony_ci ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE; 180362306a36Sopenharmony_ci ring_cfg.mode = K3_RINGACC_RING_MODE_RING; 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci k3_configure_chan_coherency(&uc->vc.chan, uc->config.asel); 180662306a36Sopenharmony_ci ring_cfg.asel = uc->config.asel; 180762306a36Sopenharmony_ci ring_cfg.dma_dev = dmaengine_get_dma_device(&uc->vc.chan); 180862306a36Sopenharmony_ci } 180962306a36Sopenharmony_ci 181062306a36Sopenharmony_ci ret = k3_ringacc_ring_cfg(rflow->fd_ring, &ring_cfg); 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_ci ring_cfg.size = K3_UDMA_DEFAULT_RING_SIZE; 181362306a36Sopenharmony_ci ret |= k3_ringacc_ring_cfg(rflow->r_ring, &ring_cfg); 181462306a36Sopenharmony_ci 181562306a36Sopenharmony_ci if (ret) 181662306a36Sopenharmony_ci goto err_ringcfg; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci return 0; 181962306a36Sopenharmony_ci 182062306a36Sopenharmony_cierr_ringcfg: 182162306a36Sopenharmony_ci k3_ringacc_ring_free(rflow->r_ring); 182262306a36Sopenharmony_ci rflow->r_ring = NULL; 182362306a36Sopenharmony_ci k3_ringacc_ring_free(rflow->fd_ring); 182462306a36Sopenharmony_ci rflow->fd_ring = NULL; 182562306a36Sopenharmony_cierr_ring: 182662306a36Sopenharmony_ci udma_put_rflow(uc); 182762306a36Sopenharmony_cierr_rflow: 182862306a36Sopenharmony_ci udma_put_rchan(uc); 182962306a36Sopenharmony_ci 183062306a36Sopenharmony_ci return ret; 183162306a36Sopenharmony_ci} 183262306a36Sopenharmony_ci 183362306a36Sopenharmony_ci#define TISCI_BCDMA_BCHAN_VALID_PARAMS ( \ 183462306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID | \ 183562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_EXTENDED_CH_TYPE_VALID) 183662306a36Sopenharmony_ci 183762306a36Sopenharmony_ci#define TISCI_BCDMA_TCHAN_VALID_PARAMS ( \ 183862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID | \ 183962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID) 184062306a36Sopenharmony_ci 184162306a36Sopenharmony_ci#define TISCI_BCDMA_RCHAN_VALID_PARAMS ( \ 184262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID) 184362306a36Sopenharmony_ci 184462306a36Sopenharmony_ci#define TISCI_UDMA_TCHAN_VALID_PARAMS ( \ 184562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID | \ 184662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_EINFO_VALID | \ 184762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_FILT_PSWORDS_VALID | \ 184862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID | \ 184962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_SUPR_TDPKT_VALID | \ 185062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID | \ 185162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID | \ 185262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID) 185362306a36Sopenharmony_ci 185462306a36Sopenharmony_ci#define TISCI_UDMA_RCHAN_VALID_PARAMS ( \ 185562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_PAUSE_ON_ERR_VALID | \ 185662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_FETCH_SIZE_VALID | \ 185762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CQ_QNUM_VALID | \ 185862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_CHAN_TYPE_VALID | \ 185962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_SHORT_VALID | \ 186062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_IGNORE_LONG_VALID | \ 186162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_START_VALID | \ 186262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_RX_FLOWID_CNT_VALID | \ 186362306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_ATYPE_VALID) 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_cistatic int udma_tisci_m2m_channel_config(struct udma_chan *uc) 186662306a36Sopenharmony_ci{ 186762306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 186862306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 186962306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 187062306a36Sopenharmony_ci struct udma_tchan *tchan = uc->tchan; 187162306a36Sopenharmony_ci struct udma_rchan *rchan = uc->rchan; 187262306a36Sopenharmony_ci u8 burst_size = 0; 187362306a36Sopenharmony_ci int ret; 187462306a36Sopenharmony_ci u8 tpl; 187562306a36Sopenharmony_ci 187662306a36Sopenharmony_ci /* Non synchronized - mem to mem type of transfer */ 187762306a36Sopenharmony_ci int tc_ring = k3_ringacc_get_ring_id(tchan->tc_ring); 187862306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 }; 187962306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 }; 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci if (ud->match_data->flags & UDMA_FLAG_BURST_SIZE) { 188262306a36Sopenharmony_ci tpl = udma_get_chan_tpl_index(&ud->tchan_tpl, tchan->id); 188362306a36Sopenharmony_ci 188462306a36Sopenharmony_ci burst_size = ud->match_data->burst_size[tpl]; 188562306a36Sopenharmony_ci } 188662306a36Sopenharmony_ci 188762306a36Sopenharmony_ci req_tx.valid_params = TISCI_UDMA_TCHAN_VALID_PARAMS; 188862306a36Sopenharmony_ci req_tx.nav_id = tisci_rm->tisci_dev_id; 188962306a36Sopenharmony_ci req_tx.index = tchan->id; 189062306a36Sopenharmony_ci req_tx.tx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR; 189162306a36Sopenharmony_ci req_tx.tx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2; 189262306a36Sopenharmony_ci req_tx.txcq_qnum = tc_ring; 189362306a36Sopenharmony_ci req_tx.tx_atype = ud->atype; 189462306a36Sopenharmony_ci if (burst_size) { 189562306a36Sopenharmony_ci req_tx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID; 189662306a36Sopenharmony_ci req_tx.tx_burst_size = burst_size; 189762306a36Sopenharmony_ci } 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx); 190062306a36Sopenharmony_ci if (ret) { 190162306a36Sopenharmony_ci dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret); 190262306a36Sopenharmony_ci return ret; 190362306a36Sopenharmony_ci } 190462306a36Sopenharmony_ci 190562306a36Sopenharmony_ci req_rx.valid_params = TISCI_UDMA_RCHAN_VALID_PARAMS; 190662306a36Sopenharmony_ci req_rx.nav_id = tisci_rm->tisci_dev_id; 190762306a36Sopenharmony_ci req_rx.index = rchan->id; 190862306a36Sopenharmony_ci req_rx.rx_fetch_size = sizeof(struct cppi5_desc_hdr_t) >> 2; 190962306a36Sopenharmony_ci req_rx.rxcq_qnum = tc_ring; 191062306a36Sopenharmony_ci req_rx.rx_chan_type = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_BCOPY_PBRR; 191162306a36Sopenharmony_ci req_rx.rx_atype = ud->atype; 191262306a36Sopenharmony_ci if (burst_size) { 191362306a36Sopenharmony_ci req_rx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID; 191462306a36Sopenharmony_ci req_rx.rx_burst_size = burst_size; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx); 191862306a36Sopenharmony_ci if (ret) 191962306a36Sopenharmony_ci dev_err(ud->dev, "rchan%d alloc failed %d\n", rchan->id, ret); 192062306a36Sopenharmony_ci 192162306a36Sopenharmony_ci return ret; 192262306a36Sopenharmony_ci} 192362306a36Sopenharmony_ci 192462306a36Sopenharmony_cistatic int bcdma_tisci_m2m_channel_config(struct udma_chan *uc) 192562306a36Sopenharmony_ci{ 192662306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 192762306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 192862306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 192962306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 }; 193062306a36Sopenharmony_ci struct udma_bchan *bchan = uc->bchan; 193162306a36Sopenharmony_ci u8 burst_size = 0; 193262306a36Sopenharmony_ci int ret; 193362306a36Sopenharmony_ci u8 tpl; 193462306a36Sopenharmony_ci 193562306a36Sopenharmony_ci if (ud->match_data->flags & UDMA_FLAG_BURST_SIZE) { 193662306a36Sopenharmony_ci tpl = udma_get_chan_tpl_index(&ud->bchan_tpl, bchan->id); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci burst_size = ud->match_data->burst_size[tpl]; 193962306a36Sopenharmony_ci } 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci req_tx.valid_params = TISCI_BCDMA_BCHAN_VALID_PARAMS; 194262306a36Sopenharmony_ci req_tx.nav_id = tisci_rm->tisci_dev_id; 194362306a36Sopenharmony_ci req_tx.extended_ch_type = TI_SCI_RM_BCDMA_EXTENDED_CH_TYPE_BCHAN; 194462306a36Sopenharmony_ci req_tx.index = bchan->id; 194562306a36Sopenharmony_ci if (burst_size) { 194662306a36Sopenharmony_ci req_tx.valid_params |= TI_SCI_MSG_VALUE_RM_UDMAP_CH_BURST_SIZE_VALID; 194762306a36Sopenharmony_ci req_tx.tx_burst_size = burst_size; 194862306a36Sopenharmony_ci } 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx); 195162306a36Sopenharmony_ci if (ret) 195262306a36Sopenharmony_ci dev_err(ud->dev, "bchan%d cfg failed %d\n", bchan->id, ret); 195362306a36Sopenharmony_ci 195462306a36Sopenharmony_ci return ret; 195562306a36Sopenharmony_ci} 195662306a36Sopenharmony_ci 195762306a36Sopenharmony_cistatic int udma_tisci_tx_channel_config(struct udma_chan *uc) 195862306a36Sopenharmony_ci{ 195962306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 196062306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 196162306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 196262306a36Sopenharmony_ci struct udma_tchan *tchan = uc->tchan; 196362306a36Sopenharmony_ci int tc_ring = k3_ringacc_get_ring_id(tchan->tc_ring); 196462306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 }; 196562306a36Sopenharmony_ci u32 mode, fetch_size; 196662306a36Sopenharmony_ci int ret; 196762306a36Sopenharmony_ci 196862306a36Sopenharmony_ci if (uc->config.pkt_mode) { 196962306a36Sopenharmony_ci mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; 197062306a36Sopenharmony_ci fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib, 197162306a36Sopenharmony_ci uc->config.psd_size, 0); 197262306a36Sopenharmony_ci } else { 197362306a36Sopenharmony_ci mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR; 197462306a36Sopenharmony_ci fetch_size = sizeof(struct cppi5_desc_hdr_t); 197562306a36Sopenharmony_ci } 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci req_tx.valid_params = TISCI_UDMA_TCHAN_VALID_PARAMS; 197862306a36Sopenharmony_ci req_tx.nav_id = tisci_rm->tisci_dev_id; 197962306a36Sopenharmony_ci req_tx.index = tchan->id; 198062306a36Sopenharmony_ci req_tx.tx_chan_type = mode; 198162306a36Sopenharmony_ci req_tx.tx_supr_tdpkt = uc->config.notdpkt; 198262306a36Sopenharmony_ci req_tx.tx_fetch_size = fetch_size >> 2; 198362306a36Sopenharmony_ci req_tx.txcq_qnum = tc_ring; 198462306a36Sopenharmony_ci req_tx.tx_atype = uc->config.atype; 198562306a36Sopenharmony_ci if (uc->config.ep_type == PSIL_EP_PDMA_XY && 198662306a36Sopenharmony_ci ud->match_data->flags & UDMA_FLAG_TDTYPE) { 198762306a36Sopenharmony_ci /* wait for peer to complete the teardown for PDMAs */ 198862306a36Sopenharmony_ci req_tx.valid_params |= 198962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_TDTYPE_VALID; 199062306a36Sopenharmony_ci req_tx.tx_tdtype = 1; 199162306a36Sopenharmony_ci } 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx); 199462306a36Sopenharmony_ci if (ret) 199562306a36Sopenharmony_ci dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci return ret; 199862306a36Sopenharmony_ci} 199962306a36Sopenharmony_ci 200062306a36Sopenharmony_cistatic int bcdma_tisci_tx_channel_config(struct udma_chan *uc) 200162306a36Sopenharmony_ci{ 200262306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 200362306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 200462306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 200562306a36Sopenharmony_ci struct udma_tchan *tchan = uc->tchan; 200662306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_tx_ch_cfg req_tx = { 0 }; 200762306a36Sopenharmony_ci int ret; 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci req_tx.valid_params = TISCI_BCDMA_TCHAN_VALID_PARAMS; 201062306a36Sopenharmony_ci req_tx.nav_id = tisci_rm->tisci_dev_id; 201162306a36Sopenharmony_ci req_tx.index = tchan->id; 201262306a36Sopenharmony_ci req_tx.tx_supr_tdpkt = uc->config.notdpkt; 201362306a36Sopenharmony_ci if (ud->match_data->flags & UDMA_FLAG_TDTYPE) { 201462306a36Sopenharmony_ci /* wait for peer to complete the teardown for PDMAs */ 201562306a36Sopenharmony_ci req_tx.valid_params |= 201662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_CH_TX_TDTYPE_VALID; 201762306a36Sopenharmony_ci req_tx.tx_tdtype = 1; 201862306a36Sopenharmony_ci } 201962306a36Sopenharmony_ci 202062306a36Sopenharmony_ci ret = tisci_ops->tx_ch_cfg(tisci_rm->tisci, &req_tx); 202162306a36Sopenharmony_ci if (ret) 202262306a36Sopenharmony_ci dev_err(ud->dev, "tchan%d cfg failed %d\n", tchan->id, ret); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci return ret; 202562306a36Sopenharmony_ci} 202662306a36Sopenharmony_ci 202762306a36Sopenharmony_ci#define pktdma_tisci_tx_channel_config bcdma_tisci_tx_channel_config 202862306a36Sopenharmony_ci 202962306a36Sopenharmony_cistatic int udma_tisci_rx_channel_config(struct udma_chan *uc) 203062306a36Sopenharmony_ci{ 203162306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 203262306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 203362306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 203462306a36Sopenharmony_ci struct udma_rchan *rchan = uc->rchan; 203562306a36Sopenharmony_ci int fd_ring = k3_ringacc_get_ring_id(uc->rflow->fd_ring); 203662306a36Sopenharmony_ci int rx_ring = k3_ringacc_get_ring_id(uc->rflow->r_ring); 203762306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 }; 203862306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 }; 203962306a36Sopenharmony_ci u32 mode, fetch_size; 204062306a36Sopenharmony_ci int ret; 204162306a36Sopenharmony_ci 204262306a36Sopenharmony_ci if (uc->config.pkt_mode) { 204362306a36Sopenharmony_ci mode = TI_SCI_RM_UDMAP_CHAN_TYPE_PKT_PBRR; 204462306a36Sopenharmony_ci fetch_size = cppi5_hdesc_calc_size(uc->config.needs_epib, 204562306a36Sopenharmony_ci uc->config.psd_size, 0); 204662306a36Sopenharmony_ci } else { 204762306a36Sopenharmony_ci mode = TI_SCI_RM_UDMAP_CHAN_TYPE_3RDP_PBRR; 204862306a36Sopenharmony_ci fetch_size = sizeof(struct cppi5_desc_hdr_t); 204962306a36Sopenharmony_ci } 205062306a36Sopenharmony_ci 205162306a36Sopenharmony_ci req_rx.valid_params = TISCI_UDMA_RCHAN_VALID_PARAMS; 205262306a36Sopenharmony_ci req_rx.nav_id = tisci_rm->tisci_dev_id; 205362306a36Sopenharmony_ci req_rx.index = rchan->id; 205462306a36Sopenharmony_ci req_rx.rx_fetch_size = fetch_size >> 2; 205562306a36Sopenharmony_ci req_rx.rxcq_qnum = rx_ring; 205662306a36Sopenharmony_ci req_rx.rx_chan_type = mode; 205762306a36Sopenharmony_ci req_rx.rx_atype = uc->config.atype; 205862306a36Sopenharmony_ci 205962306a36Sopenharmony_ci ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx); 206062306a36Sopenharmony_ci if (ret) { 206162306a36Sopenharmony_ci dev_err(ud->dev, "rchan%d cfg failed %d\n", rchan->id, ret); 206262306a36Sopenharmony_ci return ret; 206362306a36Sopenharmony_ci } 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci flow_req.valid_params = 206662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID | 206762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID | 206862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID | 206962306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DESC_TYPE_VALID | 207062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_QNUM_VALID | 207162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_HI_SEL_VALID | 207262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_SRC_TAG_LO_SEL_VALID | 207362306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_HI_SEL_VALID | 207462306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_DEST_TAG_LO_SEL_VALID | 207562306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ0_SZ0_QNUM_VALID | 207662306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ1_QNUM_VALID | 207762306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ2_QNUM_VALID | 207862306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_FDQ3_QNUM_VALID; 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci flow_req.nav_id = tisci_rm->tisci_dev_id; 208162306a36Sopenharmony_ci flow_req.flow_index = rchan->id; 208262306a36Sopenharmony_ci 208362306a36Sopenharmony_ci if (uc->config.needs_epib) 208462306a36Sopenharmony_ci flow_req.rx_einfo_present = 1; 208562306a36Sopenharmony_ci else 208662306a36Sopenharmony_ci flow_req.rx_einfo_present = 0; 208762306a36Sopenharmony_ci if (uc->config.psd_size) 208862306a36Sopenharmony_ci flow_req.rx_psinfo_present = 1; 208962306a36Sopenharmony_ci else 209062306a36Sopenharmony_ci flow_req.rx_psinfo_present = 0; 209162306a36Sopenharmony_ci flow_req.rx_error_handling = 1; 209262306a36Sopenharmony_ci flow_req.rx_dest_qnum = rx_ring; 209362306a36Sopenharmony_ci flow_req.rx_src_tag_hi_sel = UDMA_RFLOW_SRCTAG_NONE; 209462306a36Sopenharmony_ci flow_req.rx_src_tag_lo_sel = UDMA_RFLOW_SRCTAG_SRC_TAG; 209562306a36Sopenharmony_ci flow_req.rx_dest_tag_hi_sel = UDMA_RFLOW_DSTTAG_DST_TAG_HI; 209662306a36Sopenharmony_ci flow_req.rx_dest_tag_lo_sel = UDMA_RFLOW_DSTTAG_DST_TAG_LO; 209762306a36Sopenharmony_ci flow_req.rx_fdq0_sz0_qnum = fd_ring; 209862306a36Sopenharmony_ci flow_req.rx_fdq1_qnum = fd_ring; 209962306a36Sopenharmony_ci flow_req.rx_fdq2_qnum = fd_ring; 210062306a36Sopenharmony_ci flow_req.rx_fdq3_qnum = fd_ring; 210162306a36Sopenharmony_ci 210262306a36Sopenharmony_ci ret = tisci_ops->rx_flow_cfg(tisci_rm->tisci, &flow_req); 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci if (ret) 210562306a36Sopenharmony_ci dev_err(ud->dev, "flow%d config failed: %d\n", rchan->id, ret); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci return 0; 210862306a36Sopenharmony_ci} 210962306a36Sopenharmony_ci 211062306a36Sopenharmony_cistatic int bcdma_tisci_rx_channel_config(struct udma_chan *uc) 211162306a36Sopenharmony_ci{ 211262306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 211362306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 211462306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 211562306a36Sopenharmony_ci struct udma_rchan *rchan = uc->rchan; 211662306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 }; 211762306a36Sopenharmony_ci int ret; 211862306a36Sopenharmony_ci 211962306a36Sopenharmony_ci req_rx.valid_params = TISCI_BCDMA_RCHAN_VALID_PARAMS; 212062306a36Sopenharmony_ci req_rx.nav_id = tisci_rm->tisci_dev_id; 212162306a36Sopenharmony_ci req_rx.index = rchan->id; 212262306a36Sopenharmony_ci 212362306a36Sopenharmony_ci ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx); 212462306a36Sopenharmony_ci if (ret) 212562306a36Sopenharmony_ci dev_err(ud->dev, "rchan%d cfg failed %d\n", rchan->id, ret); 212662306a36Sopenharmony_ci 212762306a36Sopenharmony_ci return ret; 212862306a36Sopenharmony_ci} 212962306a36Sopenharmony_ci 213062306a36Sopenharmony_cistatic int pktdma_tisci_rx_channel_config(struct udma_chan *uc) 213162306a36Sopenharmony_ci{ 213262306a36Sopenharmony_ci struct udma_dev *ud = uc->ud; 213362306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 213462306a36Sopenharmony_ci const struct ti_sci_rm_udmap_ops *tisci_ops = tisci_rm->tisci_udmap_ops; 213562306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_rx_ch_cfg req_rx = { 0 }; 213662306a36Sopenharmony_ci struct ti_sci_msg_rm_udmap_flow_cfg flow_req = { 0 }; 213762306a36Sopenharmony_ci int ret; 213862306a36Sopenharmony_ci 213962306a36Sopenharmony_ci req_rx.valid_params = TISCI_BCDMA_RCHAN_VALID_PARAMS; 214062306a36Sopenharmony_ci req_rx.nav_id = tisci_rm->tisci_dev_id; 214162306a36Sopenharmony_ci req_rx.index = uc->rchan->id; 214262306a36Sopenharmony_ci 214362306a36Sopenharmony_ci ret = tisci_ops->rx_ch_cfg(tisci_rm->tisci, &req_rx); 214462306a36Sopenharmony_ci if (ret) { 214562306a36Sopenharmony_ci dev_err(ud->dev, "rchan%d cfg failed %d\n", uc->rchan->id, ret); 214662306a36Sopenharmony_ci return ret; 214762306a36Sopenharmony_ci } 214862306a36Sopenharmony_ci 214962306a36Sopenharmony_ci flow_req.valid_params = 215062306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_EINFO_PRESENT_VALID | 215162306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_PSINFO_PRESENT_VALID | 215262306a36Sopenharmony_ci TI_SCI_MSG_VALUE_RM_UDMAP_FLOW_ERROR_HANDLING_VALID; 215362306a36Sopenharmony_ci 215462306a36Sopenharmony_ci flow_req.nav_id = tisci_rm->tisci_dev_id; 215562306a36Sopenharmony_ci flow_req.flow_index = uc->rflow->id; 215662306a36Sopenharmony_ci 215762306a36Sopenharmony_ci if (uc->config.needs_epib) 215862306a36Sopenharmony_ci flow_req.rx_einfo_present = 1; 215962306a36Sopenharmony_ci else 216062306a36Sopenharmony_ci flow_req.rx_einfo_present = 0; 216162306a36Sopenharmony_ci if (uc->config.psd_size) 216262306a36Sopenharmony_ci flow_req.rx_psinfo_present = 1; 216362306a36Sopenharmony_ci else 216462306a36Sopenharmony_ci flow_req.rx_psinfo_present = 0; 216562306a36Sopenharmony_ci flow_req.rx_error_handling = 1; 216662306a36Sopenharmony_ci 216762306a36Sopenharmony_ci ret = tisci_ops->rx_flow_cfg(tisci_rm->tisci, &flow_req); 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci if (ret) 217062306a36Sopenharmony_ci dev_err(ud->dev, "flow%d config failed: %d\n", uc->rflow->id, 217162306a36Sopenharmony_ci ret); 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci return ret; 217462306a36Sopenharmony_ci} 217562306a36Sopenharmony_ci 217662306a36Sopenharmony_cistatic int udma_alloc_chan_resources(struct dma_chan *chan) 217762306a36Sopenharmony_ci{ 217862306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 217962306a36Sopenharmony_ci struct udma_dev *ud = to_udma_dev(chan->device); 218062306a36Sopenharmony_ci const struct udma_soc_data *soc_data = ud->soc_data; 218162306a36Sopenharmony_ci struct k3_ring *irq_ring; 218262306a36Sopenharmony_ci u32 irq_udma_idx; 218362306a36Sopenharmony_ci int ret; 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci uc->dma_dev = ud->dev; 218662306a36Sopenharmony_ci 218762306a36Sopenharmony_ci if (uc->config.pkt_mode || uc->config.dir == DMA_MEM_TO_MEM) { 218862306a36Sopenharmony_ci uc->use_dma_pool = true; 218962306a36Sopenharmony_ci /* in case of MEM_TO_MEM we have maximum of two TRs */ 219062306a36Sopenharmony_ci if (uc->config.dir == DMA_MEM_TO_MEM) { 219162306a36Sopenharmony_ci uc->config.hdesc_size = cppi5_trdesc_calc_size( 219262306a36Sopenharmony_ci sizeof(struct cppi5_tr_type15_t), 2); 219362306a36Sopenharmony_ci uc->config.pkt_mode = false; 219462306a36Sopenharmony_ci } 219562306a36Sopenharmony_ci } 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci if (uc->use_dma_pool) { 219862306a36Sopenharmony_ci uc->hdesc_pool = dma_pool_create(uc->name, ud->ddev.dev, 219962306a36Sopenharmony_ci uc->config.hdesc_size, 220062306a36Sopenharmony_ci ud->desc_align, 220162306a36Sopenharmony_ci 0); 220262306a36Sopenharmony_ci if (!uc->hdesc_pool) { 220362306a36Sopenharmony_ci dev_err(ud->ddev.dev, 220462306a36Sopenharmony_ci "Descriptor pool allocation failed\n"); 220562306a36Sopenharmony_ci uc->use_dma_pool = false; 220662306a36Sopenharmony_ci ret = -ENOMEM; 220762306a36Sopenharmony_ci goto err_cleanup; 220862306a36Sopenharmony_ci } 220962306a36Sopenharmony_ci } 221062306a36Sopenharmony_ci 221162306a36Sopenharmony_ci /* 221262306a36Sopenharmony_ci * Make sure that the completion is in a known state: 221362306a36Sopenharmony_ci * No teardown, the channel is idle 221462306a36Sopenharmony_ci */ 221562306a36Sopenharmony_ci reinit_completion(&uc->teardown_completed); 221662306a36Sopenharmony_ci complete_all(&uc->teardown_completed); 221762306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_IDLE; 221862306a36Sopenharmony_ci 221962306a36Sopenharmony_ci switch (uc->config.dir) { 222062306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 222162306a36Sopenharmony_ci /* Non synchronized - mem to mem type of transfer */ 222262306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-MEM\n", __func__, 222362306a36Sopenharmony_ci uc->id); 222462306a36Sopenharmony_ci 222562306a36Sopenharmony_ci ret = udma_get_chan_pair(uc); 222662306a36Sopenharmony_ci if (ret) 222762306a36Sopenharmony_ci goto err_cleanup; 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci ret = udma_alloc_tx_resources(uc); 223062306a36Sopenharmony_ci if (ret) { 223162306a36Sopenharmony_ci udma_put_rchan(uc); 223262306a36Sopenharmony_ci goto err_cleanup; 223362306a36Sopenharmony_ci } 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci ret = udma_alloc_rx_resources(uc); 223662306a36Sopenharmony_ci if (ret) { 223762306a36Sopenharmony_ci udma_free_tx_resources(uc); 223862306a36Sopenharmony_ci goto err_cleanup; 223962306a36Sopenharmony_ci } 224062306a36Sopenharmony_ci 224162306a36Sopenharmony_ci uc->config.src_thread = ud->psil_base + uc->tchan->id; 224262306a36Sopenharmony_ci uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 224362306a36Sopenharmony_ci K3_PSIL_DST_THREAD_ID_OFFSET; 224462306a36Sopenharmony_ci 224562306a36Sopenharmony_ci irq_ring = uc->tchan->tc_ring; 224662306a36Sopenharmony_ci irq_udma_idx = uc->tchan->id; 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci ret = udma_tisci_m2m_channel_config(uc); 224962306a36Sopenharmony_ci break; 225062306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 225162306a36Sopenharmony_ci /* Slave transfer synchronized - mem to dev (TX) trasnfer */ 225262306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__, 225362306a36Sopenharmony_ci uc->id); 225462306a36Sopenharmony_ci 225562306a36Sopenharmony_ci ret = udma_alloc_tx_resources(uc); 225662306a36Sopenharmony_ci if (ret) 225762306a36Sopenharmony_ci goto err_cleanup; 225862306a36Sopenharmony_ci 225962306a36Sopenharmony_ci uc->config.src_thread = ud->psil_base + uc->tchan->id; 226062306a36Sopenharmony_ci uc->config.dst_thread = uc->config.remote_thread_id; 226162306a36Sopenharmony_ci uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET; 226262306a36Sopenharmony_ci 226362306a36Sopenharmony_ci irq_ring = uc->tchan->tc_ring; 226462306a36Sopenharmony_ci irq_udma_idx = uc->tchan->id; 226562306a36Sopenharmony_ci 226662306a36Sopenharmony_ci ret = udma_tisci_tx_channel_config(uc); 226762306a36Sopenharmony_ci break; 226862306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 226962306a36Sopenharmony_ci /* Slave transfer synchronized - dev to mem (RX) trasnfer */ 227062306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__, 227162306a36Sopenharmony_ci uc->id); 227262306a36Sopenharmony_ci 227362306a36Sopenharmony_ci ret = udma_alloc_rx_resources(uc); 227462306a36Sopenharmony_ci if (ret) 227562306a36Sopenharmony_ci goto err_cleanup; 227662306a36Sopenharmony_ci 227762306a36Sopenharmony_ci uc->config.src_thread = uc->config.remote_thread_id; 227862306a36Sopenharmony_ci uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 227962306a36Sopenharmony_ci K3_PSIL_DST_THREAD_ID_OFFSET; 228062306a36Sopenharmony_ci 228162306a36Sopenharmony_ci irq_ring = uc->rflow->r_ring; 228262306a36Sopenharmony_ci irq_udma_idx = soc_data->oes.udma_rchan + uc->rchan->id; 228362306a36Sopenharmony_ci 228462306a36Sopenharmony_ci ret = udma_tisci_rx_channel_config(uc); 228562306a36Sopenharmony_ci break; 228662306a36Sopenharmony_ci default: 228762306a36Sopenharmony_ci /* Can not happen */ 228862306a36Sopenharmony_ci dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n", 228962306a36Sopenharmony_ci __func__, uc->id, uc->config.dir); 229062306a36Sopenharmony_ci ret = -EINVAL; 229162306a36Sopenharmony_ci goto err_cleanup; 229262306a36Sopenharmony_ci 229362306a36Sopenharmony_ci } 229462306a36Sopenharmony_ci 229562306a36Sopenharmony_ci /* check if the channel configuration was successful */ 229662306a36Sopenharmony_ci if (ret) 229762306a36Sopenharmony_ci goto err_res_free; 229862306a36Sopenharmony_ci 229962306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 230062306a36Sopenharmony_ci dev_warn(ud->dev, "chan%d: is running!\n", uc->id); 230162306a36Sopenharmony_ci udma_reset_chan(uc, false); 230262306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 230362306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); 230462306a36Sopenharmony_ci ret = -EBUSY; 230562306a36Sopenharmony_ci goto err_res_free; 230662306a36Sopenharmony_ci } 230762306a36Sopenharmony_ci } 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_ci /* PSI-L pairing */ 231062306a36Sopenharmony_ci ret = navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread); 231162306a36Sopenharmony_ci if (ret) { 231262306a36Sopenharmony_ci dev_err(ud->dev, "PSI-L pairing failed: 0x%04x -> 0x%04x\n", 231362306a36Sopenharmony_ci uc->config.src_thread, uc->config.dst_thread); 231462306a36Sopenharmony_ci goto err_res_free; 231562306a36Sopenharmony_ci } 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci uc->psil_paired = true; 231862306a36Sopenharmony_ci 231962306a36Sopenharmony_ci uc->irq_num_ring = k3_ringacc_get_ring_irq_num(irq_ring); 232062306a36Sopenharmony_ci if (uc->irq_num_ring <= 0) { 232162306a36Sopenharmony_ci dev_err(ud->dev, "Failed to get ring irq (index: %u)\n", 232262306a36Sopenharmony_ci k3_ringacc_get_ring_id(irq_ring)); 232362306a36Sopenharmony_ci ret = -EINVAL; 232462306a36Sopenharmony_ci goto err_psi_free; 232562306a36Sopenharmony_ci } 232662306a36Sopenharmony_ci 232762306a36Sopenharmony_ci ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler, 232862306a36Sopenharmony_ci IRQF_TRIGGER_HIGH, uc->name, uc); 232962306a36Sopenharmony_ci if (ret) { 233062306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id); 233162306a36Sopenharmony_ci goto err_irq_free; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci 233462306a36Sopenharmony_ci /* Event from UDMA (TR events) only needed for slave TR mode channels */ 233562306a36Sopenharmony_ci if (is_slave_direction(uc->config.dir) && !uc->config.pkt_mode) { 233662306a36Sopenharmony_ci uc->irq_num_udma = msi_get_virq(ud->dev, irq_udma_idx); 233762306a36Sopenharmony_ci if (uc->irq_num_udma <= 0) { 233862306a36Sopenharmony_ci dev_err(ud->dev, "Failed to get udma irq (index: %u)\n", 233962306a36Sopenharmony_ci irq_udma_idx); 234062306a36Sopenharmony_ci free_irq(uc->irq_num_ring, uc); 234162306a36Sopenharmony_ci ret = -EINVAL; 234262306a36Sopenharmony_ci goto err_irq_free; 234362306a36Sopenharmony_ci } 234462306a36Sopenharmony_ci 234562306a36Sopenharmony_ci ret = request_irq(uc->irq_num_udma, udma_udma_irq_handler, 0, 234662306a36Sopenharmony_ci uc->name, uc); 234762306a36Sopenharmony_ci if (ret) { 234862306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: UDMA irq request failed\n", 234962306a36Sopenharmony_ci uc->id); 235062306a36Sopenharmony_ci free_irq(uc->irq_num_ring, uc); 235162306a36Sopenharmony_ci goto err_irq_free; 235262306a36Sopenharmony_ci } 235362306a36Sopenharmony_ci } else { 235462306a36Sopenharmony_ci uc->irq_num_udma = 0; 235562306a36Sopenharmony_ci } 235662306a36Sopenharmony_ci 235762306a36Sopenharmony_ci udma_reset_rings(uc); 235862306a36Sopenharmony_ci 235962306a36Sopenharmony_ci return 0; 236062306a36Sopenharmony_ci 236162306a36Sopenharmony_cierr_irq_free: 236262306a36Sopenharmony_ci uc->irq_num_ring = 0; 236362306a36Sopenharmony_ci uc->irq_num_udma = 0; 236462306a36Sopenharmony_cierr_psi_free: 236562306a36Sopenharmony_ci navss_psil_unpair(ud, uc->config.src_thread, uc->config.dst_thread); 236662306a36Sopenharmony_ci uc->psil_paired = false; 236762306a36Sopenharmony_cierr_res_free: 236862306a36Sopenharmony_ci udma_free_tx_resources(uc); 236962306a36Sopenharmony_ci udma_free_rx_resources(uc); 237062306a36Sopenharmony_cierr_cleanup: 237162306a36Sopenharmony_ci udma_reset_uchan(uc); 237262306a36Sopenharmony_ci 237362306a36Sopenharmony_ci if (uc->use_dma_pool) { 237462306a36Sopenharmony_ci dma_pool_destroy(uc->hdesc_pool); 237562306a36Sopenharmony_ci uc->use_dma_pool = false; 237662306a36Sopenharmony_ci } 237762306a36Sopenharmony_ci 237862306a36Sopenharmony_ci return ret; 237962306a36Sopenharmony_ci} 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_cistatic int bcdma_alloc_chan_resources(struct dma_chan *chan) 238262306a36Sopenharmony_ci{ 238362306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 238462306a36Sopenharmony_ci struct udma_dev *ud = to_udma_dev(chan->device); 238562306a36Sopenharmony_ci const struct udma_oes_offsets *oes = &ud->soc_data->oes; 238662306a36Sopenharmony_ci u32 irq_udma_idx, irq_ring_idx; 238762306a36Sopenharmony_ci int ret; 238862306a36Sopenharmony_ci 238962306a36Sopenharmony_ci /* Only TR mode is supported */ 239062306a36Sopenharmony_ci uc->config.pkt_mode = false; 239162306a36Sopenharmony_ci 239262306a36Sopenharmony_ci /* 239362306a36Sopenharmony_ci * Make sure that the completion is in a known state: 239462306a36Sopenharmony_ci * No teardown, the channel is idle 239562306a36Sopenharmony_ci */ 239662306a36Sopenharmony_ci reinit_completion(&uc->teardown_completed); 239762306a36Sopenharmony_ci complete_all(&uc->teardown_completed); 239862306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_IDLE; 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci switch (uc->config.dir) { 240162306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 240262306a36Sopenharmony_ci /* Non synchronized - mem to mem type of transfer */ 240362306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-MEM\n", __func__, 240462306a36Sopenharmony_ci uc->id); 240562306a36Sopenharmony_ci 240662306a36Sopenharmony_ci ret = bcdma_alloc_bchan_resources(uc); 240762306a36Sopenharmony_ci if (ret) 240862306a36Sopenharmony_ci return ret; 240962306a36Sopenharmony_ci 241062306a36Sopenharmony_ci irq_ring_idx = uc->bchan->id + oes->bcdma_bchan_ring; 241162306a36Sopenharmony_ci irq_udma_idx = uc->bchan->id + oes->bcdma_bchan_data; 241262306a36Sopenharmony_ci 241362306a36Sopenharmony_ci ret = bcdma_tisci_m2m_channel_config(uc); 241462306a36Sopenharmony_ci break; 241562306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 241662306a36Sopenharmony_ci /* Slave transfer synchronized - mem to dev (TX) trasnfer */ 241762306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__, 241862306a36Sopenharmony_ci uc->id); 241962306a36Sopenharmony_ci 242062306a36Sopenharmony_ci ret = udma_alloc_tx_resources(uc); 242162306a36Sopenharmony_ci if (ret) { 242262306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 242362306a36Sopenharmony_ci return ret; 242462306a36Sopenharmony_ci } 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci uc->config.src_thread = ud->psil_base + uc->tchan->id; 242762306a36Sopenharmony_ci uc->config.dst_thread = uc->config.remote_thread_id; 242862306a36Sopenharmony_ci uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET; 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci irq_ring_idx = uc->tchan->id + oes->bcdma_tchan_ring; 243162306a36Sopenharmony_ci irq_udma_idx = uc->tchan->id + oes->bcdma_tchan_data; 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci ret = bcdma_tisci_tx_channel_config(uc); 243462306a36Sopenharmony_ci break; 243562306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 243662306a36Sopenharmony_ci /* Slave transfer synchronized - dev to mem (RX) trasnfer */ 243762306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__, 243862306a36Sopenharmony_ci uc->id); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci ret = udma_alloc_rx_resources(uc); 244162306a36Sopenharmony_ci if (ret) { 244262306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 244362306a36Sopenharmony_ci return ret; 244462306a36Sopenharmony_ci } 244562306a36Sopenharmony_ci 244662306a36Sopenharmony_ci uc->config.src_thread = uc->config.remote_thread_id; 244762306a36Sopenharmony_ci uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 244862306a36Sopenharmony_ci K3_PSIL_DST_THREAD_ID_OFFSET; 244962306a36Sopenharmony_ci 245062306a36Sopenharmony_ci irq_ring_idx = uc->rchan->id + oes->bcdma_rchan_ring; 245162306a36Sopenharmony_ci irq_udma_idx = uc->rchan->id + oes->bcdma_rchan_data; 245262306a36Sopenharmony_ci 245362306a36Sopenharmony_ci ret = bcdma_tisci_rx_channel_config(uc); 245462306a36Sopenharmony_ci break; 245562306a36Sopenharmony_ci default: 245662306a36Sopenharmony_ci /* Can not happen */ 245762306a36Sopenharmony_ci dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n", 245862306a36Sopenharmony_ci __func__, uc->id, uc->config.dir); 245962306a36Sopenharmony_ci return -EINVAL; 246062306a36Sopenharmony_ci } 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci /* check if the channel configuration was successful */ 246362306a36Sopenharmony_ci if (ret) 246462306a36Sopenharmony_ci goto err_res_free; 246562306a36Sopenharmony_ci 246662306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 246762306a36Sopenharmony_ci dev_warn(ud->dev, "chan%d: is running!\n", uc->id); 246862306a36Sopenharmony_ci udma_reset_chan(uc, false); 246962306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 247062306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); 247162306a36Sopenharmony_ci ret = -EBUSY; 247262306a36Sopenharmony_ci goto err_res_free; 247362306a36Sopenharmony_ci } 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci uc->dma_dev = dmaengine_get_dma_device(chan); 247762306a36Sopenharmony_ci if (uc->config.dir == DMA_MEM_TO_MEM && !uc->config.tr_trigger_type) { 247862306a36Sopenharmony_ci uc->config.hdesc_size = cppi5_trdesc_calc_size( 247962306a36Sopenharmony_ci sizeof(struct cppi5_tr_type15_t), 2); 248062306a36Sopenharmony_ci 248162306a36Sopenharmony_ci uc->hdesc_pool = dma_pool_create(uc->name, ud->ddev.dev, 248262306a36Sopenharmony_ci uc->config.hdesc_size, 248362306a36Sopenharmony_ci ud->desc_align, 248462306a36Sopenharmony_ci 0); 248562306a36Sopenharmony_ci if (!uc->hdesc_pool) { 248662306a36Sopenharmony_ci dev_err(ud->ddev.dev, 248762306a36Sopenharmony_ci "Descriptor pool allocation failed\n"); 248862306a36Sopenharmony_ci uc->use_dma_pool = false; 248962306a36Sopenharmony_ci ret = -ENOMEM; 249062306a36Sopenharmony_ci goto err_res_free; 249162306a36Sopenharmony_ci } 249262306a36Sopenharmony_ci 249362306a36Sopenharmony_ci uc->use_dma_pool = true; 249462306a36Sopenharmony_ci } else if (uc->config.dir != DMA_MEM_TO_MEM) { 249562306a36Sopenharmony_ci /* PSI-L pairing */ 249662306a36Sopenharmony_ci ret = navss_psil_pair(ud, uc->config.src_thread, 249762306a36Sopenharmony_ci uc->config.dst_thread); 249862306a36Sopenharmony_ci if (ret) { 249962306a36Sopenharmony_ci dev_err(ud->dev, 250062306a36Sopenharmony_ci "PSI-L pairing failed: 0x%04x -> 0x%04x\n", 250162306a36Sopenharmony_ci uc->config.src_thread, uc->config.dst_thread); 250262306a36Sopenharmony_ci goto err_res_free; 250362306a36Sopenharmony_ci } 250462306a36Sopenharmony_ci 250562306a36Sopenharmony_ci uc->psil_paired = true; 250662306a36Sopenharmony_ci } 250762306a36Sopenharmony_ci 250862306a36Sopenharmony_ci uc->irq_num_ring = msi_get_virq(ud->dev, irq_ring_idx); 250962306a36Sopenharmony_ci if (uc->irq_num_ring <= 0) { 251062306a36Sopenharmony_ci dev_err(ud->dev, "Failed to get ring irq (index: %u)\n", 251162306a36Sopenharmony_ci irq_ring_idx); 251262306a36Sopenharmony_ci ret = -EINVAL; 251362306a36Sopenharmony_ci goto err_psi_free; 251462306a36Sopenharmony_ci } 251562306a36Sopenharmony_ci 251662306a36Sopenharmony_ci ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler, 251762306a36Sopenharmony_ci IRQF_TRIGGER_HIGH, uc->name, uc); 251862306a36Sopenharmony_ci if (ret) { 251962306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id); 252062306a36Sopenharmony_ci goto err_irq_free; 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci 252362306a36Sopenharmony_ci /* Event from BCDMA (TR events) only needed for slave channels */ 252462306a36Sopenharmony_ci if (is_slave_direction(uc->config.dir)) { 252562306a36Sopenharmony_ci uc->irq_num_udma = msi_get_virq(ud->dev, irq_udma_idx); 252662306a36Sopenharmony_ci if (uc->irq_num_udma <= 0) { 252762306a36Sopenharmony_ci dev_err(ud->dev, "Failed to get bcdma irq (index: %u)\n", 252862306a36Sopenharmony_ci irq_udma_idx); 252962306a36Sopenharmony_ci free_irq(uc->irq_num_ring, uc); 253062306a36Sopenharmony_ci ret = -EINVAL; 253162306a36Sopenharmony_ci goto err_irq_free; 253262306a36Sopenharmony_ci } 253362306a36Sopenharmony_ci 253462306a36Sopenharmony_ci ret = request_irq(uc->irq_num_udma, udma_udma_irq_handler, 0, 253562306a36Sopenharmony_ci uc->name, uc); 253662306a36Sopenharmony_ci if (ret) { 253762306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: BCDMA irq request failed\n", 253862306a36Sopenharmony_ci uc->id); 253962306a36Sopenharmony_ci free_irq(uc->irq_num_ring, uc); 254062306a36Sopenharmony_ci goto err_irq_free; 254162306a36Sopenharmony_ci } 254262306a36Sopenharmony_ci } else { 254362306a36Sopenharmony_ci uc->irq_num_udma = 0; 254462306a36Sopenharmony_ci } 254562306a36Sopenharmony_ci 254662306a36Sopenharmony_ci udma_reset_rings(uc); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work, 254962306a36Sopenharmony_ci udma_check_tx_completion); 255062306a36Sopenharmony_ci return 0; 255162306a36Sopenharmony_ci 255262306a36Sopenharmony_cierr_irq_free: 255362306a36Sopenharmony_ci uc->irq_num_ring = 0; 255462306a36Sopenharmony_ci uc->irq_num_udma = 0; 255562306a36Sopenharmony_cierr_psi_free: 255662306a36Sopenharmony_ci if (uc->psil_paired) 255762306a36Sopenharmony_ci navss_psil_unpair(ud, uc->config.src_thread, 255862306a36Sopenharmony_ci uc->config.dst_thread); 255962306a36Sopenharmony_ci uc->psil_paired = false; 256062306a36Sopenharmony_cierr_res_free: 256162306a36Sopenharmony_ci bcdma_free_bchan_resources(uc); 256262306a36Sopenharmony_ci udma_free_tx_resources(uc); 256362306a36Sopenharmony_ci udma_free_rx_resources(uc); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci udma_reset_uchan(uc); 256662306a36Sopenharmony_ci 256762306a36Sopenharmony_ci if (uc->use_dma_pool) { 256862306a36Sopenharmony_ci dma_pool_destroy(uc->hdesc_pool); 256962306a36Sopenharmony_ci uc->use_dma_pool = false; 257062306a36Sopenharmony_ci } 257162306a36Sopenharmony_ci 257262306a36Sopenharmony_ci return ret; 257362306a36Sopenharmony_ci} 257462306a36Sopenharmony_ci 257562306a36Sopenharmony_cistatic int bcdma_router_config(struct dma_chan *chan) 257662306a36Sopenharmony_ci{ 257762306a36Sopenharmony_ci struct k3_event_route_data *router_data = chan->route_data; 257862306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 257962306a36Sopenharmony_ci u32 trigger_event; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci if (!uc->bchan) 258262306a36Sopenharmony_ci return -EINVAL; 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci if (uc->config.tr_trigger_type != 1 && uc->config.tr_trigger_type != 2) 258562306a36Sopenharmony_ci return -EINVAL; 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci trigger_event = uc->ud->soc_data->bcdma_trigger_event_offset; 258862306a36Sopenharmony_ci trigger_event += (uc->bchan->id * 2) + uc->config.tr_trigger_type - 1; 258962306a36Sopenharmony_ci 259062306a36Sopenharmony_ci return router_data->set_event(router_data->priv, trigger_event); 259162306a36Sopenharmony_ci} 259262306a36Sopenharmony_ci 259362306a36Sopenharmony_cistatic int pktdma_alloc_chan_resources(struct dma_chan *chan) 259462306a36Sopenharmony_ci{ 259562306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 259662306a36Sopenharmony_ci struct udma_dev *ud = to_udma_dev(chan->device); 259762306a36Sopenharmony_ci const struct udma_oes_offsets *oes = &ud->soc_data->oes; 259862306a36Sopenharmony_ci u32 irq_ring_idx; 259962306a36Sopenharmony_ci int ret; 260062306a36Sopenharmony_ci 260162306a36Sopenharmony_ci /* 260262306a36Sopenharmony_ci * Make sure that the completion is in a known state: 260362306a36Sopenharmony_ci * No teardown, the channel is idle 260462306a36Sopenharmony_ci */ 260562306a36Sopenharmony_ci reinit_completion(&uc->teardown_completed); 260662306a36Sopenharmony_ci complete_all(&uc->teardown_completed); 260762306a36Sopenharmony_ci uc->state = UDMA_CHAN_IS_IDLE; 260862306a36Sopenharmony_ci 260962306a36Sopenharmony_ci switch (uc->config.dir) { 261062306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 261162306a36Sopenharmony_ci /* Slave transfer synchronized - mem to dev (TX) trasnfer */ 261262306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as MEM-to-DEV\n", __func__, 261362306a36Sopenharmony_ci uc->id); 261462306a36Sopenharmony_ci 261562306a36Sopenharmony_ci ret = udma_alloc_tx_resources(uc); 261662306a36Sopenharmony_ci if (ret) { 261762306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 261862306a36Sopenharmony_ci return ret; 261962306a36Sopenharmony_ci } 262062306a36Sopenharmony_ci 262162306a36Sopenharmony_ci uc->config.src_thread = ud->psil_base + uc->tchan->id; 262262306a36Sopenharmony_ci uc->config.dst_thread = uc->config.remote_thread_id; 262362306a36Sopenharmony_ci uc->config.dst_thread |= K3_PSIL_DST_THREAD_ID_OFFSET; 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci irq_ring_idx = uc->tchan->tflow_id + oes->pktdma_tchan_flow; 262662306a36Sopenharmony_ci 262762306a36Sopenharmony_ci ret = pktdma_tisci_tx_channel_config(uc); 262862306a36Sopenharmony_ci break; 262962306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 263062306a36Sopenharmony_ci /* Slave transfer synchronized - dev to mem (RX) trasnfer */ 263162306a36Sopenharmony_ci dev_dbg(uc->ud->dev, "%s: chan%d as DEV-to-MEM\n", __func__, 263262306a36Sopenharmony_ci uc->id); 263362306a36Sopenharmony_ci 263462306a36Sopenharmony_ci ret = udma_alloc_rx_resources(uc); 263562306a36Sopenharmony_ci if (ret) { 263662306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 263762306a36Sopenharmony_ci return ret; 263862306a36Sopenharmony_ci } 263962306a36Sopenharmony_ci 264062306a36Sopenharmony_ci uc->config.src_thread = uc->config.remote_thread_id; 264162306a36Sopenharmony_ci uc->config.dst_thread = (ud->psil_base + uc->rchan->id) | 264262306a36Sopenharmony_ci K3_PSIL_DST_THREAD_ID_OFFSET; 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_ci irq_ring_idx = uc->rflow->id + oes->pktdma_rchan_flow; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci ret = pktdma_tisci_rx_channel_config(uc); 264762306a36Sopenharmony_ci break; 264862306a36Sopenharmony_ci default: 264962306a36Sopenharmony_ci /* Can not happen */ 265062306a36Sopenharmony_ci dev_err(uc->ud->dev, "%s: chan%d invalid direction (%u)\n", 265162306a36Sopenharmony_ci __func__, uc->id, uc->config.dir); 265262306a36Sopenharmony_ci return -EINVAL; 265362306a36Sopenharmony_ci } 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci /* check if the channel configuration was successful */ 265662306a36Sopenharmony_ci if (ret) 265762306a36Sopenharmony_ci goto err_res_free; 265862306a36Sopenharmony_ci 265962306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 266062306a36Sopenharmony_ci dev_warn(ud->dev, "chan%d: is running!\n", uc->id); 266162306a36Sopenharmony_ci udma_reset_chan(uc, false); 266262306a36Sopenharmony_ci if (udma_is_chan_running(uc)) { 266362306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: won't stop!\n", uc->id); 266462306a36Sopenharmony_ci ret = -EBUSY; 266562306a36Sopenharmony_ci goto err_res_free; 266662306a36Sopenharmony_ci } 266762306a36Sopenharmony_ci } 266862306a36Sopenharmony_ci 266962306a36Sopenharmony_ci uc->dma_dev = dmaengine_get_dma_device(chan); 267062306a36Sopenharmony_ci uc->hdesc_pool = dma_pool_create(uc->name, uc->dma_dev, 267162306a36Sopenharmony_ci uc->config.hdesc_size, ud->desc_align, 267262306a36Sopenharmony_ci 0); 267362306a36Sopenharmony_ci if (!uc->hdesc_pool) { 267462306a36Sopenharmony_ci dev_err(ud->ddev.dev, 267562306a36Sopenharmony_ci "Descriptor pool allocation failed\n"); 267662306a36Sopenharmony_ci uc->use_dma_pool = false; 267762306a36Sopenharmony_ci ret = -ENOMEM; 267862306a36Sopenharmony_ci goto err_res_free; 267962306a36Sopenharmony_ci } 268062306a36Sopenharmony_ci 268162306a36Sopenharmony_ci uc->use_dma_pool = true; 268262306a36Sopenharmony_ci 268362306a36Sopenharmony_ci /* PSI-L pairing */ 268462306a36Sopenharmony_ci ret = navss_psil_pair(ud, uc->config.src_thread, uc->config.dst_thread); 268562306a36Sopenharmony_ci if (ret) { 268662306a36Sopenharmony_ci dev_err(ud->dev, "PSI-L pairing failed: 0x%04x -> 0x%04x\n", 268762306a36Sopenharmony_ci uc->config.src_thread, uc->config.dst_thread); 268862306a36Sopenharmony_ci goto err_res_free; 268962306a36Sopenharmony_ci } 269062306a36Sopenharmony_ci 269162306a36Sopenharmony_ci uc->psil_paired = true; 269262306a36Sopenharmony_ci 269362306a36Sopenharmony_ci uc->irq_num_ring = msi_get_virq(ud->dev, irq_ring_idx); 269462306a36Sopenharmony_ci if (uc->irq_num_ring <= 0) { 269562306a36Sopenharmony_ci dev_err(ud->dev, "Failed to get ring irq (index: %u)\n", 269662306a36Sopenharmony_ci irq_ring_idx); 269762306a36Sopenharmony_ci ret = -EINVAL; 269862306a36Sopenharmony_ci goto err_psi_free; 269962306a36Sopenharmony_ci } 270062306a36Sopenharmony_ci 270162306a36Sopenharmony_ci ret = request_irq(uc->irq_num_ring, udma_ring_irq_handler, 270262306a36Sopenharmony_ci IRQF_TRIGGER_HIGH, uc->name, uc); 270362306a36Sopenharmony_ci if (ret) { 270462306a36Sopenharmony_ci dev_err(ud->dev, "chan%d: ring irq request failed\n", uc->id); 270562306a36Sopenharmony_ci goto err_irq_free; 270662306a36Sopenharmony_ci } 270762306a36Sopenharmony_ci 270862306a36Sopenharmony_ci uc->irq_num_udma = 0; 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci udma_reset_rings(uc); 271162306a36Sopenharmony_ci 271262306a36Sopenharmony_ci INIT_DELAYED_WORK_ONSTACK(&uc->tx_drain.work, 271362306a36Sopenharmony_ci udma_check_tx_completion); 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci if (uc->tchan) 271662306a36Sopenharmony_ci dev_dbg(ud->dev, 271762306a36Sopenharmony_ci "chan%d: tchan%d, tflow%d, Remote thread: 0x%04x\n", 271862306a36Sopenharmony_ci uc->id, uc->tchan->id, uc->tchan->tflow_id, 271962306a36Sopenharmony_ci uc->config.remote_thread_id); 272062306a36Sopenharmony_ci else if (uc->rchan) 272162306a36Sopenharmony_ci dev_dbg(ud->dev, 272262306a36Sopenharmony_ci "chan%d: rchan%d, rflow%d, Remote thread: 0x%04x\n", 272362306a36Sopenharmony_ci uc->id, uc->rchan->id, uc->rflow->id, 272462306a36Sopenharmony_ci uc->config.remote_thread_id); 272562306a36Sopenharmony_ci return 0; 272662306a36Sopenharmony_ci 272762306a36Sopenharmony_cierr_irq_free: 272862306a36Sopenharmony_ci uc->irq_num_ring = 0; 272962306a36Sopenharmony_cierr_psi_free: 273062306a36Sopenharmony_ci navss_psil_unpair(ud, uc->config.src_thread, uc->config.dst_thread); 273162306a36Sopenharmony_ci uc->psil_paired = false; 273262306a36Sopenharmony_cierr_res_free: 273362306a36Sopenharmony_ci udma_free_tx_resources(uc); 273462306a36Sopenharmony_ci udma_free_rx_resources(uc); 273562306a36Sopenharmony_ci 273662306a36Sopenharmony_ci udma_reset_uchan(uc); 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci dma_pool_destroy(uc->hdesc_pool); 273962306a36Sopenharmony_ci uc->use_dma_pool = false; 274062306a36Sopenharmony_ci 274162306a36Sopenharmony_ci return ret; 274262306a36Sopenharmony_ci} 274362306a36Sopenharmony_ci 274462306a36Sopenharmony_cistatic int udma_slave_config(struct dma_chan *chan, 274562306a36Sopenharmony_ci struct dma_slave_config *cfg) 274662306a36Sopenharmony_ci{ 274762306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 274862306a36Sopenharmony_ci 274962306a36Sopenharmony_ci memcpy(&uc->cfg, cfg, sizeof(uc->cfg)); 275062306a36Sopenharmony_ci 275162306a36Sopenharmony_ci return 0; 275262306a36Sopenharmony_ci} 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_cistatic struct udma_desc *udma_alloc_tr_desc(struct udma_chan *uc, 275562306a36Sopenharmony_ci size_t tr_size, int tr_count, 275662306a36Sopenharmony_ci enum dma_transfer_direction dir) 275762306a36Sopenharmony_ci{ 275862306a36Sopenharmony_ci struct udma_hwdesc *hwdesc; 275962306a36Sopenharmony_ci struct cppi5_desc_hdr_t *tr_desc; 276062306a36Sopenharmony_ci struct udma_desc *d; 276162306a36Sopenharmony_ci u32 reload_count = 0; 276262306a36Sopenharmony_ci u32 ring_id; 276362306a36Sopenharmony_ci 276462306a36Sopenharmony_ci switch (tr_size) { 276562306a36Sopenharmony_ci case 16: 276662306a36Sopenharmony_ci case 32: 276762306a36Sopenharmony_ci case 64: 276862306a36Sopenharmony_ci case 128: 276962306a36Sopenharmony_ci break; 277062306a36Sopenharmony_ci default: 277162306a36Sopenharmony_ci dev_err(uc->ud->dev, "Unsupported TR size of %zu\n", tr_size); 277262306a36Sopenharmony_ci return NULL; 277362306a36Sopenharmony_ci } 277462306a36Sopenharmony_ci 277562306a36Sopenharmony_ci /* We have only one descriptor containing multiple TRs */ 277662306a36Sopenharmony_ci d = kzalloc(sizeof(*d) + sizeof(d->hwdesc[0]), GFP_NOWAIT); 277762306a36Sopenharmony_ci if (!d) 277862306a36Sopenharmony_ci return NULL; 277962306a36Sopenharmony_ci 278062306a36Sopenharmony_ci d->sglen = tr_count; 278162306a36Sopenharmony_ci 278262306a36Sopenharmony_ci d->hwdesc_count = 1; 278362306a36Sopenharmony_ci hwdesc = &d->hwdesc[0]; 278462306a36Sopenharmony_ci 278562306a36Sopenharmony_ci /* Allocate memory for DMA ring descriptor */ 278662306a36Sopenharmony_ci if (uc->use_dma_pool) { 278762306a36Sopenharmony_ci hwdesc->cppi5_desc_size = uc->config.hdesc_size; 278862306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool, 278962306a36Sopenharmony_ci GFP_NOWAIT, 279062306a36Sopenharmony_ci &hwdesc->cppi5_desc_paddr); 279162306a36Sopenharmony_ci } else { 279262306a36Sopenharmony_ci hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size, 279362306a36Sopenharmony_ci tr_count); 279462306a36Sopenharmony_ci hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size, 279562306a36Sopenharmony_ci uc->ud->desc_align); 279662306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = dma_alloc_coherent(uc->ud->dev, 279762306a36Sopenharmony_ci hwdesc->cppi5_desc_size, 279862306a36Sopenharmony_ci &hwdesc->cppi5_desc_paddr, 279962306a36Sopenharmony_ci GFP_NOWAIT); 280062306a36Sopenharmony_ci } 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ci if (!hwdesc->cppi5_desc_vaddr) { 280362306a36Sopenharmony_ci kfree(d); 280462306a36Sopenharmony_ci return NULL; 280562306a36Sopenharmony_ci } 280662306a36Sopenharmony_ci 280762306a36Sopenharmony_ci /* Start of the TR req records */ 280862306a36Sopenharmony_ci hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size; 280962306a36Sopenharmony_ci /* Start address of the TR response array */ 281062306a36Sopenharmony_ci hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size * tr_count; 281162306a36Sopenharmony_ci 281262306a36Sopenharmony_ci tr_desc = hwdesc->cppi5_desc_vaddr; 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_ci if (uc->cyclic) 281562306a36Sopenharmony_ci reload_count = CPPI5_INFO0_TRDESC_RLDCNT_INFINITE; 281662306a36Sopenharmony_ci 281762306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) 281862306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring); 281962306a36Sopenharmony_ci else 282062306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring); 282162306a36Sopenharmony_ci 282262306a36Sopenharmony_ci cppi5_trdesc_init(tr_desc, tr_count, tr_size, 0, reload_count); 282362306a36Sopenharmony_ci cppi5_desc_set_pktids(tr_desc, uc->id, 282462306a36Sopenharmony_ci CPPI5_INFO1_DESC_FLOWID_DEFAULT); 282562306a36Sopenharmony_ci cppi5_desc_set_retpolicy(tr_desc, 0, ring_id); 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci return d; 282862306a36Sopenharmony_ci} 282962306a36Sopenharmony_ci 283062306a36Sopenharmony_ci/** 283162306a36Sopenharmony_ci * udma_get_tr_counters - calculate TR counters for a given length 283262306a36Sopenharmony_ci * @len: Length of the trasnfer 283362306a36Sopenharmony_ci * @align_to: Preferred alignment 283462306a36Sopenharmony_ci * @tr0_cnt0: First TR icnt0 283562306a36Sopenharmony_ci * @tr0_cnt1: First TR icnt1 283662306a36Sopenharmony_ci * @tr1_cnt0: Second (if used) TR icnt0 283762306a36Sopenharmony_ci * 283862306a36Sopenharmony_ci * For len < SZ_64K only one TR is enough, tr1_cnt0 is not updated 283962306a36Sopenharmony_ci * For len >= SZ_64K two TRs are used in a simple way: 284062306a36Sopenharmony_ci * First TR: SZ_64K-alignment blocks (tr0_cnt0, tr0_cnt1) 284162306a36Sopenharmony_ci * Second TR: the remaining length (tr1_cnt0) 284262306a36Sopenharmony_ci * 284362306a36Sopenharmony_ci * Returns the number of TRs the length needs (1 or 2) 284462306a36Sopenharmony_ci * -EINVAL if the length can not be supported 284562306a36Sopenharmony_ci */ 284662306a36Sopenharmony_cistatic int udma_get_tr_counters(size_t len, unsigned long align_to, 284762306a36Sopenharmony_ci u16 *tr0_cnt0, u16 *tr0_cnt1, u16 *tr1_cnt0) 284862306a36Sopenharmony_ci{ 284962306a36Sopenharmony_ci if (len < SZ_64K) { 285062306a36Sopenharmony_ci *tr0_cnt0 = len; 285162306a36Sopenharmony_ci *tr0_cnt1 = 1; 285262306a36Sopenharmony_ci 285362306a36Sopenharmony_ci return 1; 285462306a36Sopenharmony_ci } 285562306a36Sopenharmony_ci 285662306a36Sopenharmony_ci if (align_to > 3) 285762306a36Sopenharmony_ci align_to = 3; 285862306a36Sopenharmony_ci 285962306a36Sopenharmony_cirealign: 286062306a36Sopenharmony_ci *tr0_cnt0 = SZ_64K - BIT(align_to); 286162306a36Sopenharmony_ci if (len / *tr0_cnt0 >= SZ_64K) { 286262306a36Sopenharmony_ci if (align_to) { 286362306a36Sopenharmony_ci align_to--; 286462306a36Sopenharmony_ci goto realign; 286562306a36Sopenharmony_ci } 286662306a36Sopenharmony_ci return -EINVAL; 286762306a36Sopenharmony_ci } 286862306a36Sopenharmony_ci 286962306a36Sopenharmony_ci *tr0_cnt1 = len / *tr0_cnt0; 287062306a36Sopenharmony_ci *tr1_cnt0 = len % *tr0_cnt0; 287162306a36Sopenharmony_ci 287262306a36Sopenharmony_ci return 2; 287362306a36Sopenharmony_ci} 287462306a36Sopenharmony_ci 287562306a36Sopenharmony_cistatic struct udma_desc * 287662306a36Sopenharmony_ciudma_prep_slave_sg_tr(struct udma_chan *uc, struct scatterlist *sgl, 287762306a36Sopenharmony_ci unsigned int sglen, enum dma_transfer_direction dir, 287862306a36Sopenharmony_ci unsigned long tx_flags, void *context) 287962306a36Sopenharmony_ci{ 288062306a36Sopenharmony_ci struct scatterlist *sgent; 288162306a36Sopenharmony_ci struct udma_desc *d; 288262306a36Sopenharmony_ci struct cppi5_tr_type1_t *tr_req = NULL; 288362306a36Sopenharmony_ci u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; 288462306a36Sopenharmony_ci unsigned int i; 288562306a36Sopenharmony_ci size_t tr_size; 288662306a36Sopenharmony_ci int num_tr = 0; 288762306a36Sopenharmony_ci int tr_idx = 0; 288862306a36Sopenharmony_ci u64 asel; 288962306a36Sopenharmony_ci 289062306a36Sopenharmony_ci /* estimate the number of TRs we will need */ 289162306a36Sopenharmony_ci for_each_sg(sgl, sgent, sglen, i) { 289262306a36Sopenharmony_ci if (sg_dma_len(sgent) < SZ_64K) 289362306a36Sopenharmony_ci num_tr++; 289462306a36Sopenharmony_ci else 289562306a36Sopenharmony_ci num_tr += 2; 289662306a36Sopenharmony_ci } 289762306a36Sopenharmony_ci 289862306a36Sopenharmony_ci /* Now allocate and setup the descriptor. */ 289962306a36Sopenharmony_ci tr_size = sizeof(struct cppi5_tr_type1_t); 290062306a36Sopenharmony_ci d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir); 290162306a36Sopenharmony_ci if (!d) 290262306a36Sopenharmony_ci return NULL; 290362306a36Sopenharmony_ci 290462306a36Sopenharmony_ci d->sglen = sglen; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_UDMA) 290762306a36Sopenharmony_ci asel = 0; 290862306a36Sopenharmony_ci else 290962306a36Sopenharmony_ci asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci tr_req = d->hwdesc[0].tr_req_base; 291262306a36Sopenharmony_ci for_each_sg(sgl, sgent, sglen, i) { 291362306a36Sopenharmony_ci dma_addr_t sg_addr = sg_dma_address(sgent); 291462306a36Sopenharmony_ci 291562306a36Sopenharmony_ci num_tr = udma_get_tr_counters(sg_dma_len(sgent), __ffs(sg_addr), 291662306a36Sopenharmony_ci &tr0_cnt0, &tr0_cnt1, &tr1_cnt0); 291762306a36Sopenharmony_ci if (num_tr < 0) { 291862306a36Sopenharmony_ci dev_err(uc->ud->dev, "size %u is not supported\n", 291962306a36Sopenharmony_ci sg_dma_len(sgent)); 292062306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 292162306a36Sopenharmony_ci kfree(d); 292262306a36Sopenharmony_ci return NULL; 292362306a36Sopenharmony_ci } 292462306a36Sopenharmony_ci 292562306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, 292662306a36Sopenharmony_ci false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 292762306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, CPPI5_TR_CSF_SUPR_EVT); 292862306a36Sopenharmony_ci 292962306a36Sopenharmony_ci sg_addr |= asel; 293062306a36Sopenharmony_ci tr_req[tr_idx].addr = sg_addr; 293162306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr0_cnt0; 293262306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr0_cnt1; 293362306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr0_cnt0; 293462306a36Sopenharmony_ci tr_idx++; 293562306a36Sopenharmony_ci 293662306a36Sopenharmony_ci if (num_tr == 2) { 293762306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, 293862306a36Sopenharmony_ci false, false, 293962306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 294062306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, 294162306a36Sopenharmony_ci CPPI5_TR_CSF_SUPR_EVT); 294262306a36Sopenharmony_ci 294362306a36Sopenharmony_ci tr_req[tr_idx].addr = sg_addr + tr0_cnt1 * tr0_cnt0; 294462306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr1_cnt0; 294562306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = 1; 294662306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr1_cnt0; 294762306a36Sopenharmony_ci tr_idx++; 294862306a36Sopenharmony_ci } 294962306a36Sopenharmony_ci 295062306a36Sopenharmony_ci d->residue += sg_dma_len(sgent); 295162306a36Sopenharmony_ci } 295262306a36Sopenharmony_ci 295362306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, 295462306a36Sopenharmony_ci CPPI5_TR_CSF_SUPR_EVT | CPPI5_TR_CSF_EOP); 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci return d; 295762306a36Sopenharmony_ci} 295862306a36Sopenharmony_ci 295962306a36Sopenharmony_cistatic struct udma_desc * 296062306a36Sopenharmony_ciudma_prep_slave_sg_triggered_tr(struct udma_chan *uc, struct scatterlist *sgl, 296162306a36Sopenharmony_ci unsigned int sglen, 296262306a36Sopenharmony_ci enum dma_transfer_direction dir, 296362306a36Sopenharmony_ci unsigned long tx_flags, void *context) 296462306a36Sopenharmony_ci{ 296562306a36Sopenharmony_ci struct scatterlist *sgent; 296662306a36Sopenharmony_ci struct cppi5_tr_type15_t *tr_req = NULL; 296762306a36Sopenharmony_ci enum dma_slave_buswidth dev_width; 296862306a36Sopenharmony_ci u32 csf = CPPI5_TR_CSF_SUPR_EVT; 296962306a36Sopenharmony_ci u16 tr_cnt0, tr_cnt1; 297062306a36Sopenharmony_ci dma_addr_t dev_addr; 297162306a36Sopenharmony_ci struct udma_desc *d; 297262306a36Sopenharmony_ci unsigned int i; 297362306a36Sopenharmony_ci size_t tr_size, sg_len; 297462306a36Sopenharmony_ci int num_tr = 0; 297562306a36Sopenharmony_ci int tr_idx = 0; 297662306a36Sopenharmony_ci u32 burst, trigger_size, port_window; 297762306a36Sopenharmony_ci u64 asel; 297862306a36Sopenharmony_ci 297962306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) { 298062306a36Sopenharmony_ci dev_addr = uc->cfg.src_addr; 298162306a36Sopenharmony_ci dev_width = uc->cfg.src_addr_width; 298262306a36Sopenharmony_ci burst = uc->cfg.src_maxburst; 298362306a36Sopenharmony_ci port_window = uc->cfg.src_port_window_size; 298462306a36Sopenharmony_ci } else if (dir == DMA_MEM_TO_DEV) { 298562306a36Sopenharmony_ci dev_addr = uc->cfg.dst_addr; 298662306a36Sopenharmony_ci dev_width = uc->cfg.dst_addr_width; 298762306a36Sopenharmony_ci burst = uc->cfg.dst_maxburst; 298862306a36Sopenharmony_ci port_window = uc->cfg.dst_port_window_size; 298962306a36Sopenharmony_ci } else { 299062306a36Sopenharmony_ci dev_err(uc->ud->dev, "%s: bad direction?\n", __func__); 299162306a36Sopenharmony_ci return NULL; 299262306a36Sopenharmony_ci } 299362306a36Sopenharmony_ci 299462306a36Sopenharmony_ci if (!burst) 299562306a36Sopenharmony_ci burst = 1; 299662306a36Sopenharmony_ci 299762306a36Sopenharmony_ci if (port_window) { 299862306a36Sopenharmony_ci if (port_window != burst) { 299962306a36Sopenharmony_ci dev_err(uc->ud->dev, 300062306a36Sopenharmony_ci "The burst must be equal to port_window\n"); 300162306a36Sopenharmony_ci return NULL; 300262306a36Sopenharmony_ci } 300362306a36Sopenharmony_ci 300462306a36Sopenharmony_ci tr_cnt0 = dev_width * port_window; 300562306a36Sopenharmony_ci tr_cnt1 = 1; 300662306a36Sopenharmony_ci } else { 300762306a36Sopenharmony_ci tr_cnt0 = dev_width; 300862306a36Sopenharmony_ci tr_cnt1 = burst; 300962306a36Sopenharmony_ci } 301062306a36Sopenharmony_ci trigger_size = tr_cnt0 * tr_cnt1; 301162306a36Sopenharmony_ci 301262306a36Sopenharmony_ci /* estimate the number of TRs we will need */ 301362306a36Sopenharmony_ci for_each_sg(sgl, sgent, sglen, i) { 301462306a36Sopenharmony_ci sg_len = sg_dma_len(sgent); 301562306a36Sopenharmony_ci 301662306a36Sopenharmony_ci if (sg_len % trigger_size) { 301762306a36Sopenharmony_ci dev_err(uc->ud->dev, 301862306a36Sopenharmony_ci "Not aligned SG entry (%zu for %u)\n", sg_len, 301962306a36Sopenharmony_ci trigger_size); 302062306a36Sopenharmony_ci return NULL; 302162306a36Sopenharmony_ci } 302262306a36Sopenharmony_ci 302362306a36Sopenharmony_ci if (sg_len / trigger_size < SZ_64K) 302462306a36Sopenharmony_ci num_tr++; 302562306a36Sopenharmony_ci else 302662306a36Sopenharmony_ci num_tr += 2; 302762306a36Sopenharmony_ci } 302862306a36Sopenharmony_ci 302962306a36Sopenharmony_ci /* Now allocate and setup the descriptor. */ 303062306a36Sopenharmony_ci tr_size = sizeof(struct cppi5_tr_type15_t); 303162306a36Sopenharmony_ci d = udma_alloc_tr_desc(uc, tr_size, num_tr, dir); 303262306a36Sopenharmony_ci if (!d) 303362306a36Sopenharmony_ci return NULL; 303462306a36Sopenharmony_ci 303562306a36Sopenharmony_ci d->sglen = sglen; 303662306a36Sopenharmony_ci 303762306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_UDMA) { 303862306a36Sopenharmony_ci asel = 0; 303962306a36Sopenharmony_ci csf |= CPPI5_TR_CSF_EOL_ICNT0; 304062306a36Sopenharmony_ci } else { 304162306a36Sopenharmony_ci asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; 304262306a36Sopenharmony_ci dev_addr |= asel; 304362306a36Sopenharmony_ci } 304462306a36Sopenharmony_ci 304562306a36Sopenharmony_ci tr_req = d->hwdesc[0].tr_req_base; 304662306a36Sopenharmony_ci for_each_sg(sgl, sgent, sglen, i) { 304762306a36Sopenharmony_ci u16 tr0_cnt2, tr0_cnt3, tr1_cnt2; 304862306a36Sopenharmony_ci dma_addr_t sg_addr = sg_dma_address(sgent); 304962306a36Sopenharmony_ci 305062306a36Sopenharmony_ci sg_len = sg_dma_len(sgent); 305162306a36Sopenharmony_ci num_tr = udma_get_tr_counters(sg_len / trigger_size, 0, 305262306a36Sopenharmony_ci &tr0_cnt2, &tr0_cnt3, &tr1_cnt2); 305362306a36Sopenharmony_ci if (num_tr < 0) { 305462306a36Sopenharmony_ci dev_err(uc->ud->dev, "size %zu is not supported\n", 305562306a36Sopenharmony_ci sg_len); 305662306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 305762306a36Sopenharmony_ci kfree(d); 305862306a36Sopenharmony_ci return NULL; 305962306a36Sopenharmony_ci } 306062306a36Sopenharmony_ci 306162306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, false, 306262306a36Sopenharmony_ci true, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 306362306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); 306462306a36Sopenharmony_ci cppi5_tr_set_trigger(&tr_req[tr_idx].flags, 306562306a36Sopenharmony_ci uc->config.tr_trigger_type, 306662306a36Sopenharmony_ci CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 0, 0); 306762306a36Sopenharmony_ci 306862306a36Sopenharmony_ci sg_addr |= asel; 306962306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) { 307062306a36Sopenharmony_ci tr_req[tr_idx].addr = dev_addr; 307162306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr_cnt0; 307262306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr_cnt1; 307362306a36Sopenharmony_ci tr_req[tr_idx].icnt2 = tr0_cnt2; 307462306a36Sopenharmony_ci tr_req[tr_idx].icnt3 = tr0_cnt3; 307562306a36Sopenharmony_ci tr_req[tr_idx].dim1 = (-1) * tr_cnt0; 307662306a36Sopenharmony_ci 307762306a36Sopenharmony_ci tr_req[tr_idx].daddr = sg_addr; 307862306a36Sopenharmony_ci tr_req[tr_idx].dicnt0 = tr_cnt0; 307962306a36Sopenharmony_ci tr_req[tr_idx].dicnt1 = tr_cnt1; 308062306a36Sopenharmony_ci tr_req[tr_idx].dicnt2 = tr0_cnt2; 308162306a36Sopenharmony_ci tr_req[tr_idx].dicnt3 = tr0_cnt3; 308262306a36Sopenharmony_ci tr_req[tr_idx].ddim1 = tr_cnt0; 308362306a36Sopenharmony_ci tr_req[tr_idx].ddim2 = trigger_size; 308462306a36Sopenharmony_ci tr_req[tr_idx].ddim3 = trigger_size * tr0_cnt2; 308562306a36Sopenharmony_ci } else { 308662306a36Sopenharmony_ci tr_req[tr_idx].addr = sg_addr; 308762306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr_cnt0; 308862306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr_cnt1; 308962306a36Sopenharmony_ci tr_req[tr_idx].icnt2 = tr0_cnt2; 309062306a36Sopenharmony_ci tr_req[tr_idx].icnt3 = tr0_cnt3; 309162306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr_cnt0; 309262306a36Sopenharmony_ci tr_req[tr_idx].dim2 = trigger_size; 309362306a36Sopenharmony_ci tr_req[tr_idx].dim3 = trigger_size * tr0_cnt2; 309462306a36Sopenharmony_ci 309562306a36Sopenharmony_ci tr_req[tr_idx].daddr = dev_addr; 309662306a36Sopenharmony_ci tr_req[tr_idx].dicnt0 = tr_cnt0; 309762306a36Sopenharmony_ci tr_req[tr_idx].dicnt1 = tr_cnt1; 309862306a36Sopenharmony_ci tr_req[tr_idx].dicnt2 = tr0_cnt2; 309962306a36Sopenharmony_ci tr_req[tr_idx].dicnt3 = tr0_cnt3; 310062306a36Sopenharmony_ci tr_req[tr_idx].ddim1 = (-1) * tr_cnt0; 310162306a36Sopenharmony_ci } 310262306a36Sopenharmony_ci 310362306a36Sopenharmony_ci tr_idx++; 310462306a36Sopenharmony_ci 310562306a36Sopenharmony_ci if (num_tr == 2) { 310662306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE15, 310762306a36Sopenharmony_ci false, true, 310862306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 310962306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, csf); 311062306a36Sopenharmony_ci cppi5_tr_set_trigger(&tr_req[tr_idx].flags, 311162306a36Sopenharmony_ci uc->config.tr_trigger_type, 311262306a36Sopenharmony_ci CPPI5_TR_TRIGGER_TYPE_ICNT2_DEC, 311362306a36Sopenharmony_ci 0, 0); 311462306a36Sopenharmony_ci 311562306a36Sopenharmony_ci sg_addr += trigger_size * tr0_cnt2 * tr0_cnt3; 311662306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) { 311762306a36Sopenharmony_ci tr_req[tr_idx].addr = dev_addr; 311862306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr_cnt0; 311962306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr_cnt1; 312062306a36Sopenharmony_ci tr_req[tr_idx].icnt2 = tr1_cnt2; 312162306a36Sopenharmony_ci tr_req[tr_idx].icnt3 = 1; 312262306a36Sopenharmony_ci tr_req[tr_idx].dim1 = (-1) * tr_cnt0; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_ci tr_req[tr_idx].daddr = sg_addr; 312562306a36Sopenharmony_ci tr_req[tr_idx].dicnt0 = tr_cnt0; 312662306a36Sopenharmony_ci tr_req[tr_idx].dicnt1 = tr_cnt1; 312762306a36Sopenharmony_ci tr_req[tr_idx].dicnt2 = tr1_cnt2; 312862306a36Sopenharmony_ci tr_req[tr_idx].dicnt3 = 1; 312962306a36Sopenharmony_ci tr_req[tr_idx].ddim1 = tr_cnt0; 313062306a36Sopenharmony_ci tr_req[tr_idx].ddim2 = trigger_size; 313162306a36Sopenharmony_ci } else { 313262306a36Sopenharmony_ci tr_req[tr_idx].addr = sg_addr; 313362306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr_cnt0; 313462306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr_cnt1; 313562306a36Sopenharmony_ci tr_req[tr_idx].icnt2 = tr1_cnt2; 313662306a36Sopenharmony_ci tr_req[tr_idx].icnt3 = 1; 313762306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr_cnt0; 313862306a36Sopenharmony_ci tr_req[tr_idx].dim2 = trigger_size; 313962306a36Sopenharmony_ci 314062306a36Sopenharmony_ci tr_req[tr_idx].daddr = dev_addr; 314162306a36Sopenharmony_ci tr_req[tr_idx].dicnt0 = tr_cnt0; 314262306a36Sopenharmony_ci tr_req[tr_idx].dicnt1 = tr_cnt1; 314362306a36Sopenharmony_ci tr_req[tr_idx].dicnt2 = tr1_cnt2; 314462306a36Sopenharmony_ci tr_req[tr_idx].dicnt3 = 1; 314562306a36Sopenharmony_ci tr_req[tr_idx].ddim1 = (-1) * tr_cnt0; 314662306a36Sopenharmony_ci } 314762306a36Sopenharmony_ci tr_idx++; 314862306a36Sopenharmony_ci } 314962306a36Sopenharmony_ci 315062306a36Sopenharmony_ci d->residue += sg_len; 315162306a36Sopenharmony_ci } 315262306a36Sopenharmony_ci 315362306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx - 1].flags, csf | CPPI5_TR_CSF_EOP); 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci return d; 315662306a36Sopenharmony_ci} 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_cistatic int udma_configure_statictr(struct udma_chan *uc, struct udma_desc *d, 315962306a36Sopenharmony_ci enum dma_slave_buswidth dev_width, 316062306a36Sopenharmony_ci u16 elcnt) 316162306a36Sopenharmony_ci{ 316262306a36Sopenharmony_ci if (uc->config.ep_type != PSIL_EP_PDMA_XY) 316362306a36Sopenharmony_ci return 0; 316462306a36Sopenharmony_ci 316562306a36Sopenharmony_ci /* Bus width translates to the element size (ES) */ 316662306a36Sopenharmony_ci switch (dev_width) { 316762306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_1_BYTE: 316862306a36Sopenharmony_ci d->static_tr.elsize = 0; 316962306a36Sopenharmony_ci break; 317062306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_2_BYTES: 317162306a36Sopenharmony_ci d->static_tr.elsize = 1; 317262306a36Sopenharmony_ci break; 317362306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_3_BYTES: 317462306a36Sopenharmony_ci d->static_tr.elsize = 2; 317562306a36Sopenharmony_ci break; 317662306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_4_BYTES: 317762306a36Sopenharmony_ci d->static_tr.elsize = 3; 317862306a36Sopenharmony_ci break; 317962306a36Sopenharmony_ci case DMA_SLAVE_BUSWIDTH_8_BYTES: 318062306a36Sopenharmony_ci d->static_tr.elsize = 4; 318162306a36Sopenharmony_ci break; 318262306a36Sopenharmony_ci default: /* not reached */ 318362306a36Sopenharmony_ci return -EINVAL; 318462306a36Sopenharmony_ci } 318562306a36Sopenharmony_ci 318662306a36Sopenharmony_ci d->static_tr.elcnt = elcnt; 318762306a36Sopenharmony_ci 318862306a36Sopenharmony_ci /* 318962306a36Sopenharmony_ci * PDMA must to close the packet when the channel is in packet mode. 319062306a36Sopenharmony_ci * For TR mode when the channel is not cyclic we also need PDMA to close 319162306a36Sopenharmony_ci * the packet otherwise the transfer will stall because PDMA holds on 319262306a36Sopenharmony_ci * the data it has received from the peripheral. 319362306a36Sopenharmony_ci */ 319462306a36Sopenharmony_ci if (uc->config.pkt_mode || !uc->cyclic) { 319562306a36Sopenharmony_ci unsigned int div = dev_width * elcnt; 319662306a36Sopenharmony_ci 319762306a36Sopenharmony_ci if (uc->cyclic) 319862306a36Sopenharmony_ci d->static_tr.bstcnt = d->residue / d->sglen / div; 319962306a36Sopenharmony_ci else 320062306a36Sopenharmony_ci d->static_tr.bstcnt = d->residue / div; 320162306a36Sopenharmony_ci 320262306a36Sopenharmony_ci if (uc->config.dir == DMA_DEV_TO_MEM && 320362306a36Sopenharmony_ci d->static_tr.bstcnt > uc->ud->match_data->statictr_z_mask) 320462306a36Sopenharmony_ci return -EINVAL; 320562306a36Sopenharmony_ci } else { 320662306a36Sopenharmony_ci d->static_tr.bstcnt = 0; 320762306a36Sopenharmony_ci } 320862306a36Sopenharmony_ci 320962306a36Sopenharmony_ci return 0; 321062306a36Sopenharmony_ci} 321162306a36Sopenharmony_ci 321262306a36Sopenharmony_cistatic struct udma_desc * 321362306a36Sopenharmony_ciudma_prep_slave_sg_pkt(struct udma_chan *uc, struct scatterlist *sgl, 321462306a36Sopenharmony_ci unsigned int sglen, enum dma_transfer_direction dir, 321562306a36Sopenharmony_ci unsigned long tx_flags, void *context) 321662306a36Sopenharmony_ci{ 321762306a36Sopenharmony_ci struct scatterlist *sgent; 321862306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc = NULL; 321962306a36Sopenharmony_ci struct udma_desc *d; 322062306a36Sopenharmony_ci u32 ring_id; 322162306a36Sopenharmony_ci unsigned int i; 322262306a36Sopenharmony_ci u64 asel; 322362306a36Sopenharmony_ci 322462306a36Sopenharmony_ci d = kzalloc(struct_size(d, hwdesc, sglen), GFP_NOWAIT); 322562306a36Sopenharmony_ci if (!d) 322662306a36Sopenharmony_ci return NULL; 322762306a36Sopenharmony_ci 322862306a36Sopenharmony_ci d->sglen = sglen; 322962306a36Sopenharmony_ci d->hwdesc_count = sglen; 323062306a36Sopenharmony_ci 323162306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) 323262306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring); 323362306a36Sopenharmony_ci else 323462306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring); 323562306a36Sopenharmony_ci 323662306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_UDMA) 323762306a36Sopenharmony_ci asel = 0; 323862306a36Sopenharmony_ci else 323962306a36Sopenharmony_ci asel = (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; 324062306a36Sopenharmony_ci 324162306a36Sopenharmony_ci for_each_sg(sgl, sgent, sglen, i) { 324262306a36Sopenharmony_ci struct udma_hwdesc *hwdesc = &d->hwdesc[i]; 324362306a36Sopenharmony_ci dma_addr_t sg_addr = sg_dma_address(sgent); 324462306a36Sopenharmony_ci struct cppi5_host_desc_t *desc; 324562306a36Sopenharmony_ci size_t sg_len = sg_dma_len(sgent); 324662306a36Sopenharmony_ci 324762306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool, 324862306a36Sopenharmony_ci GFP_NOWAIT, 324962306a36Sopenharmony_ci &hwdesc->cppi5_desc_paddr); 325062306a36Sopenharmony_ci if (!hwdesc->cppi5_desc_vaddr) { 325162306a36Sopenharmony_ci dev_err(uc->ud->dev, 325262306a36Sopenharmony_ci "descriptor%d allocation failed\n", i); 325362306a36Sopenharmony_ci 325462306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 325562306a36Sopenharmony_ci kfree(d); 325662306a36Sopenharmony_ci return NULL; 325762306a36Sopenharmony_ci } 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci d->residue += sg_len; 326062306a36Sopenharmony_ci hwdesc->cppi5_desc_size = uc->config.hdesc_size; 326162306a36Sopenharmony_ci desc = hwdesc->cppi5_desc_vaddr; 326262306a36Sopenharmony_ci 326362306a36Sopenharmony_ci if (i == 0) { 326462306a36Sopenharmony_ci cppi5_hdesc_init(desc, 0, 0); 326562306a36Sopenharmony_ci /* Flow and Packed ID */ 326662306a36Sopenharmony_ci cppi5_desc_set_pktids(&desc->hdr, uc->id, 326762306a36Sopenharmony_ci CPPI5_INFO1_DESC_FLOWID_DEFAULT); 326862306a36Sopenharmony_ci cppi5_desc_set_retpolicy(&desc->hdr, 0, ring_id); 326962306a36Sopenharmony_ci } else { 327062306a36Sopenharmony_ci cppi5_hdesc_reset_hbdesc(desc); 327162306a36Sopenharmony_ci cppi5_desc_set_retpolicy(&desc->hdr, 0, 0xffff); 327262306a36Sopenharmony_ci } 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci /* attach the sg buffer to the descriptor */ 327562306a36Sopenharmony_ci sg_addr |= asel; 327662306a36Sopenharmony_ci cppi5_hdesc_attach_buf(desc, sg_addr, sg_len, sg_addr, sg_len); 327762306a36Sopenharmony_ci 327862306a36Sopenharmony_ci /* Attach link as host buffer descriptor */ 327962306a36Sopenharmony_ci if (h_desc) 328062306a36Sopenharmony_ci cppi5_hdesc_link_hbdesc(h_desc, 328162306a36Sopenharmony_ci hwdesc->cppi5_desc_paddr | asel); 328262306a36Sopenharmony_ci 328362306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_PKTDMA || 328462306a36Sopenharmony_ci dir == DMA_MEM_TO_DEV) 328562306a36Sopenharmony_ci h_desc = desc; 328662306a36Sopenharmony_ci } 328762306a36Sopenharmony_ci 328862306a36Sopenharmony_ci if (d->residue >= SZ_4M) { 328962306a36Sopenharmony_ci dev_err(uc->ud->dev, 329062306a36Sopenharmony_ci "%s: Transfer size %u is over the supported 4M range\n", 329162306a36Sopenharmony_ci __func__, d->residue); 329262306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 329362306a36Sopenharmony_ci kfree(d); 329462306a36Sopenharmony_ci return NULL; 329562306a36Sopenharmony_ci } 329662306a36Sopenharmony_ci 329762306a36Sopenharmony_ci h_desc = d->hwdesc[0].cppi5_desc_vaddr; 329862306a36Sopenharmony_ci cppi5_hdesc_set_pktlen(h_desc, d->residue); 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci return d; 330162306a36Sopenharmony_ci} 330262306a36Sopenharmony_ci 330362306a36Sopenharmony_cistatic int udma_attach_metadata(struct dma_async_tx_descriptor *desc, 330462306a36Sopenharmony_ci void *data, size_t len) 330562306a36Sopenharmony_ci{ 330662306a36Sopenharmony_ci struct udma_desc *d = to_udma_desc(desc); 330762306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(desc->chan); 330862306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc; 330962306a36Sopenharmony_ci u32 psd_size = len; 331062306a36Sopenharmony_ci u32 flags = 0; 331162306a36Sopenharmony_ci 331262306a36Sopenharmony_ci if (!uc->config.pkt_mode || !uc->config.metadata_size) 331362306a36Sopenharmony_ci return -ENOTSUPP; 331462306a36Sopenharmony_ci 331562306a36Sopenharmony_ci if (!data || len > uc->config.metadata_size) 331662306a36Sopenharmony_ci return -EINVAL; 331762306a36Sopenharmony_ci 331862306a36Sopenharmony_ci if (uc->config.needs_epib && len < CPPI5_INFO0_HDESC_EPIB_SIZE) 331962306a36Sopenharmony_ci return -EINVAL; 332062306a36Sopenharmony_ci 332162306a36Sopenharmony_ci h_desc = d->hwdesc[0].cppi5_desc_vaddr; 332262306a36Sopenharmony_ci if (d->dir == DMA_MEM_TO_DEV) 332362306a36Sopenharmony_ci memcpy(h_desc->epib, data, len); 332462306a36Sopenharmony_ci 332562306a36Sopenharmony_ci if (uc->config.needs_epib) 332662306a36Sopenharmony_ci psd_size -= CPPI5_INFO0_HDESC_EPIB_SIZE; 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci d->metadata = data; 332962306a36Sopenharmony_ci d->metadata_size = len; 333062306a36Sopenharmony_ci if (uc->config.needs_epib) 333162306a36Sopenharmony_ci flags |= CPPI5_INFO0_HDESC_EPIB_PRESENT; 333262306a36Sopenharmony_ci 333362306a36Sopenharmony_ci cppi5_hdesc_update_flags(h_desc, flags); 333462306a36Sopenharmony_ci cppi5_hdesc_update_psdata_size(h_desc, psd_size); 333562306a36Sopenharmony_ci 333662306a36Sopenharmony_ci return 0; 333762306a36Sopenharmony_ci} 333862306a36Sopenharmony_ci 333962306a36Sopenharmony_cistatic void *udma_get_metadata_ptr(struct dma_async_tx_descriptor *desc, 334062306a36Sopenharmony_ci size_t *payload_len, size_t *max_len) 334162306a36Sopenharmony_ci{ 334262306a36Sopenharmony_ci struct udma_desc *d = to_udma_desc(desc); 334362306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(desc->chan); 334462306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc; 334562306a36Sopenharmony_ci 334662306a36Sopenharmony_ci if (!uc->config.pkt_mode || !uc->config.metadata_size) 334762306a36Sopenharmony_ci return ERR_PTR(-ENOTSUPP); 334862306a36Sopenharmony_ci 334962306a36Sopenharmony_ci h_desc = d->hwdesc[0].cppi5_desc_vaddr; 335062306a36Sopenharmony_ci 335162306a36Sopenharmony_ci *max_len = uc->config.metadata_size; 335262306a36Sopenharmony_ci 335362306a36Sopenharmony_ci *payload_len = cppi5_hdesc_epib_present(&h_desc->hdr) ? 335462306a36Sopenharmony_ci CPPI5_INFO0_HDESC_EPIB_SIZE : 0; 335562306a36Sopenharmony_ci *payload_len += cppi5_hdesc_get_psdata_size(h_desc); 335662306a36Sopenharmony_ci 335762306a36Sopenharmony_ci return h_desc->epib; 335862306a36Sopenharmony_ci} 335962306a36Sopenharmony_ci 336062306a36Sopenharmony_cistatic int udma_set_metadata_len(struct dma_async_tx_descriptor *desc, 336162306a36Sopenharmony_ci size_t payload_len) 336262306a36Sopenharmony_ci{ 336362306a36Sopenharmony_ci struct udma_desc *d = to_udma_desc(desc); 336462306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(desc->chan); 336562306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc; 336662306a36Sopenharmony_ci u32 psd_size = payload_len; 336762306a36Sopenharmony_ci u32 flags = 0; 336862306a36Sopenharmony_ci 336962306a36Sopenharmony_ci if (!uc->config.pkt_mode || !uc->config.metadata_size) 337062306a36Sopenharmony_ci return -ENOTSUPP; 337162306a36Sopenharmony_ci 337262306a36Sopenharmony_ci if (payload_len > uc->config.metadata_size) 337362306a36Sopenharmony_ci return -EINVAL; 337462306a36Sopenharmony_ci 337562306a36Sopenharmony_ci if (uc->config.needs_epib && payload_len < CPPI5_INFO0_HDESC_EPIB_SIZE) 337662306a36Sopenharmony_ci return -EINVAL; 337762306a36Sopenharmony_ci 337862306a36Sopenharmony_ci h_desc = d->hwdesc[0].cppi5_desc_vaddr; 337962306a36Sopenharmony_ci 338062306a36Sopenharmony_ci if (uc->config.needs_epib) { 338162306a36Sopenharmony_ci psd_size -= CPPI5_INFO0_HDESC_EPIB_SIZE; 338262306a36Sopenharmony_ci flags |= CPPI5_INFO0_HDESC_EPIB_PRESENT; 338362306a36Sopenharmony_ci } 338462306a36Sopenharmony_ci 338562306a36Sopenharmony_ci cppi5_hdesc_update_flags(h_desc, flags); 338662306a36Sopenharmony_ci cppi5_hdesc_update_psdata_size(h_desc, psd_size); 338762306a36Sopenharmony_ci 338862306a36Sopenharmony_ci return 0; 338962306a36Sopenharmony_ci} 339062306a36Sopenharmony_ci 339162306a36Sopenharmony_cistatic struct dma_descriptor_metadata_ops metadata_ops = { 339262306a36Sopenharmony_ci .attach = udma_attach_metadata, 339362306a36Sopenharmony_ci .get_ptr = udma_get_metadata_ptr, 339462306a36Sopenharmony_ci .set_len = udma_set_metadata_len, 339562306a36Sopenharmony_ci}; 339662306a36Sopenharmony_ci 339762306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 339862306a36Sopenharmony_ciudma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, 339962306a36Sopenharmony_ci unsigned int sglen, enum dma_transfer_direction dir, 340062306a36Sopenharmony_ci unsigned long tx_flags, void *context) 340162306a36Sopenharmony_ci{ 340262306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 340362306a36Sopenharmony_ci enum dma_slave_buswidth dev_width; 340462306a36Sopenharmony_ci struct udma_desc *d; 340562306a36Sopenharmony_ci u32 burst; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci if (dir != uc->config.dir && 340862306a36Sopenharmony_ci (uc->config.dir == DMA_MEM_TO_MEM && !uc->config.tr_trigger_type)) { 340962306a36Sopenharmony_ci dev_err(chan->device->dev, 341062306a36Sopenharmony_ci "%s: chan%d is for %s, not supporting %s\n", 341162306a36Sopenharmony_ci __func__, uc->id, 341262306a36Sopenharmony_ci dmaengine_get_direction_text(uc->config.dir), 341362306a36Sopenharmony_ci dmaengine_get_direction_text(dir)); 341462306a36Sopenharmony_ci return NULL; 341562306a36Sopenharmony_ci } 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) { 341862306a36Sopenharmony_ci dev_width = uc->cfg.src_addr_width; 341962306a36Sopenharmony_ci burst = uc->cfg.src_maxburst; 342062306a36Sopenharmony_ci } else if (dir == DMA_MEM_TO_DEV) { 342162306a36Sopenharmony_ci dev_width = uc->cfg.dst_addr_width; 342262306a36Sopenharmony_ci burst = uc->cfg.dst_maxburst; 342362306a36Sopenharmony_ci } else { 342462306a36Sopenharmony_ci dev_err(chan->device->dev, "%s: bad direction?\n", __func__); 342562306a36Sopenharmony_ci return NULL; 342662306a36Sopenharmony_ci } 342762306a36Sopenharmony_ci 342862306a36Sopenharmony_ci if (!burst) 342962306a36Sopenharmony_ci burst = 1; 343062306a36Sopenharmony_ci 343162306a36Sopenharmony_ci uc->config.tx_flags = tx_flags; 343262306a36Sopenharmony_ci 343362306a36Sopenharmony_ci if (uc->config.pkt_mode) 343462306a36Sopenharmony_ci d = udma_prep_slave_sg_pkt(uc, sgl, sglen, dir, tx_flags, 343562306a36Sopenharmony_ci context); 343662306a36Sopenharmony_ci else if (is_slave_direction(uc->config.dir)) 343762306a36Sopenharmony_ci d = udma_prep_slave_sg_tr(uc, sgl, sglen, dir, tx_flags, 343862306a36Sopenharmony_ci context); 343962306a36Sopenharmony_ci else 344062306a36Sopenharmony_ci d = udma_prep_slave_sg_triggered_tr(uc, sgl, sglen, dir, 344162306a36Sopenharmony_ci tx_flags, context); 344262306a36Sopenharmony_ci 344362306a36Sopenharmony_ci if (!d) 344462306a36Sopenharmony_ci return NULL; 344562306a36Sopenharmony_ci 344662306a36Sopenharmony_ci d->dir = dir; 344762306a36Sopenharmony_ci d->desc_idx = 0; 344862306a36Sopenharmony_ci d->tr_idx = 0; 344962306a36Sopenharmony_ci 345062306a36Sopenharmony_ci /* static TR for remote PDMA */ 345162306a36Sopenharmony_ci if (udma_configure_statictr(uc, d, dev_width, burst)) { 345262306a36Sopenharmony_ci dev_err(uc->ud->dev, 345362306a36Sopenharmony_ci "%s: StaticTR Z is limited to maximum 4095 (%u)\n", 345462306a36Sopenharmony_ci __func__, d->static_tr.bstcnt); 345562306a36Sopenharmony_ci 345662306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 345762306a36Sopenharmony_ci kfree(d); 345862306a36Sopenharmony_ci return NULL; 345962306a36Sopenharmony_ci } 346062306a36Sopenharmony_ci 346162306a36Sopenharmony_ci if (uc->config.metadata_size) 346262306a36Sopenharmony_ci d->vd.tx.metadata_ops = &metadata_ops; 346362306a36Sopenharmony_ci 346462306a36Sopenharmony_ci return vchan_tx_prep(&uc->vc, &d->vd, tx_flags); 346562306a36Sopenharmony_ci} 346662306a36Sopenharmony_ci 346762306a36Sopenharmony_cistatic struct udma_desc * 346862306a36Sopenharmony_ciudma_prep_dma_cyclic_tr(struct udma_chan *uc, dma_addr_t buf_addr, 346962306a36Sopenharmony_ci size_t buf_len, size_t period_len, 347062306a36Sopenharmony_ci enum dma_transfer_direction dir, unsigned long flags) 347162306a36Sopenharmony_ci{ 347262306a36Sopenharmony_ci struct udma_desc *d; 347362306a36Sopenharmony_ci size_t tr_size, period_addr; 347462306a36Sopenharmony_ci struct cppi5_tr_type1_t *tr_req; 347562306a36Sopenharmony_ci unsigned int periods = buf_len / period_len; 347662306a36Sopenharmony_ci u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; 347762306a36Sopenharmony_ci unsigned int i; 347862306a36Sopenharmony_ci int num_tr; 347962306a36Sopenharmony_ci 348062306a36Sopenharmony_ci num_tr = udma_get_tr_counters(period_len, __ffs(buf_addr), &tr0_cnt0, 348162306a36Sopenharmony_ci &tr0_cnt1, &tr1_cnt0); 348262306a36Sopenharmony_ci if (num_tr < 0) { 348362306a36Sopenharmony_ci dev_err(uc->ud->dev, "size %zu is not supported\n", 348462306a36Sopenharmony_ci period_len); 348562306a36Sopenharmony_ci return NULL; 348662306a36Sopenharmony_ci } 348762306a36Sopenharmony_ci 348862306a36Sopenharmony_ci /* Now allocate and setup the descriptor. */ 348962306a36Sopenharmony_ci tr_size = sizeof(struct cppi5_tr_type1_t); 349062306a36Sopenharmony_ci d = udma_alloc_tr_desc(uc, tr_size, periods * num_tr, dir); 349162306a36Sopenharmony_ci if (!d) 349262306a36Sopenharmony_ci return NULL; 349362306a36Sopenharmony_ci 349462306a36Sopenharmony_ci tr_req = d->hwdesc[0].tr_req_base; 349562306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_UDMA) 349662306a36Sopenharmony_ci period_addr = buf_addr; 349762306a36Sopenharmony_ci else 349862306a36Sopenharmony_ci period_addr = buf_addr | 349962306a36Sopenharmony_ci ((u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT); 350062306a36Sopenharmony_ci 350162306a36Sopenharmony_ci for (i = 0; i < periods; i++) { 350262306a36Sopenharmony_ci int tr_idx = i * num_tr; 350362306a36Sopenharmony_ci 350462306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, false, 350562306a36Sopenharmony_ci false, CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 350662306a36Sopenharmony_ci 350762306a36Sopenharmony_ci tr_req[tr_idx].addr = period_addr; 350862306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr0_cnt0; 350962306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = tr0_cnt1; 351062306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr0_cnt0; 351162306a36Sopenharmony_ci 351262306a36Sopenharmony_ci if (num_tr == 2) { 351362306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, 351462306a36Sopenharmony_ci CPPI5_TR_CSF_SUPR_EVT); 351562306a36Sopenharmony_ci tr_idx++; 351662306a36Sopenharmony_ci 351762306a36Sopenharmony_ci cppi5_tr_init(&tr_req[tr_idx].flags, CPPI5_TR_TYPE1, 351862306a36Sopenharmony_ci false, false, 351962306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 352062306a36Sopenharmony_ci 352162306a36Sopenharmony_ci tr_req[tr_idx].addr = period_addr + tr0_cnt1 * tr0_cnt0; 352262306a36Sopenharmony_ci tr_req[tr_idx].icnt0 = tr1_cnt0; 352362306a36Sopenharmony_ci tr_req[tr_idx].icnt1 = 1; 352462306a36Sopenharmony_ci tr_req[tr_idx].dim1 = tr1_cnt0; 352562306a36Sopenharmony_ci } 352662306a36Sopenharmony_ci 352762306a36Sopenharmony_ci if (!(flags & DMA_PREP_INTERRUPT)) 352862306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[tr_idx].flags, 352962306a36Sopenharmony_ci CPPI5_TR_CSF_SUPR_EVT); 353062306a36Sopenharmony_ci 353162306a36Sopenharmony_ci period_addr += period_len; 353262306a36Sopenharmony_ci } 353362306a36Sopenharmony_ci 353462306a36Sopenharmony_ci return d; 353562306a36Sopenharmony_ci} 353662306a36Sopenharmony_ci 353762306a36Sopenharmony_cistatic struct udma_desc * 353862306a36Sopenharmony_ciudma_prep_dma_cyclic_pkt(struct udma_chan *uc, dma_addr_t buf_addr, 353962306a36Sopenharmony_ci size_t buf_len, size_t period_len, 354062306a36Sopenharmony_ci enum dma_transfer_direction dir, unsigned long flags) 354162306a36Sopenharmony_ci{ 354262306a36Sopenharmony_ci struct udma_desc *d; 354362306a36Sopenharmony_ci u32 ring_id; 354462306a36Sopenharmony_ci int i; 354562306a36Sopenharmony_ci int periods = buf_len / period_len; 354662306a36Sopenharmony_ci 354762306a36Sopenharmony_ci if (periods > (K3_UDMA_DEFAULT_RING_SIZE - 1)) 354862306a36Sopenharmony_ci return NULL; 354962306a36Sopenharmony_ci 355062306a36Sopenharmony_ci if (period_len >= SZ_4M) 355162306a36Sopenharmony_ci return NULL; 355262306a36Sopenharmony_ci 355362306a36Sopenharmony_ci d = kzalloc(struct_size(d, hwdesc, periods), GFP_NOWAIT); 355462306a36Sopenharmony_ci if (!d) 355562306a36Sopenharmony_ci return NULL; 355662306a36Sopenharmony_ci 355762306a36Sopenharmony_ci d->hwdesc_count = periods; 355862306a36Sopenharmony_ci 355962306a36Sopenharmony_ci /* TODO: re-check this... */ 356062306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) 356162306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->rflow->r_ring); 356262306a36Sopenharmony_ci else 356362306a36Sopenharmony_ci ring_id = k3_ringacc_get_ring_id(uc->tchan->tc_ring); 356462306a36Sopenharmony_ci 356562306a36Sopenharmony_ci if (uc->ud->match_data->type != DMA_TYPE_UDMA) 356662306a36Sopenharmony_ci buf_addr |= (u64)uc->config.asel << K3_ADDRESS_ASEL_SHIFT; 356762306a36Sopenharmony_ci 356862306a36Sopenharmony_ci for (i = 0; i < periods; i++) { 356962306a36Sopenharmony_ci struct udma_hwdesc *hwdesc = &d->hwdesc[i]; 357062306a36Sopenharmony_ci dma_addr_t period_addr = buf_addr + (period_len * i); 357162306a36Sopenharmony_ci struct cppi5_host_desc_t *h_desc; 357262306a36Sopenharmony_ci 357362306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = dma_pool_zalloc(uc->hdesc_pool, 357462306a36Sopenharmony_ci GFP_NOWAIT, 357562306a36Sopenharmony_ci &hwdesc->cppi5_desc_paddr); 357662306a36Sopenharmony_ci if (!hwdesc->cppi5_desc_vaddr) { 357762306a36Sopenharmony_ci dev_err(uc->ud->dev, 357862306a36Sopenharmony_ci "descriptor%d allocation failed\n", i); 357962306a36Sopenharmony_ci 358062306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 358162306a36Sopenharmony_ci kfree(d); 358262306a36Sopenharmony_ci return NULL; 358362306a36Sopenharmony_ci } 358462306a36Sopenharmony_ci 358562306a36Sopenharmony_ci hwdesc->cppi5_desc_size = uc->config.hdesc_size; 358662306a36Sopenharmony_ci h_desc = hwdesc->cppi5_desc_vaddr; 358762306a36Sopenharmony_ci 358862306a36Sopenharmony_ci cppi5_hdesc_init(h_desc, 0, 0); 358962306a36Sopenharmony_ci cppi5_hdesc_set_pktlen(h_desc, period_len); 359062306a36Sopenharmony_ci 359162306a36Sopenharmony_ci /* Flow and Packed ID */ 359262306a36Sopenharmony_ci cppi5_desc_set_pktids(&h_desc->hdr, uc->id, 359362306a36Sopenharmony_ci CPPI5_INFO1_DESC_FLOWID_DEFAULT); 359462306a36Sopenharmony_ci cppi5_desc_set_retpolicy(&h_desc->hdr, 0, ring_id); 359562306a36Sopenharmony_ci 359662306a36Sopenharmony_ci /* attach each period to a new descriptor */ 359762306a36Sopenharmony_ci cppi5_hdesc_attach_buf(h_desc, 359862306a36Sopenharmony_ci period_addr, period_len, 359962306a36Sopenharmony_ci period_addr, period_len); 360062306a36Sopenharmony_ci } 360162306a36Sopenharmony_ci 360262306a36Sopenharmony_ci return d; 360362306a36Sopenharmony_ci} 360462306a36Sopenharmony_ci 360562306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 360662306a36Sopenharmony_ciudma_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len, 360762306a36Sopenharmony_ci size_t period_len, enum dma_transfer_direction dir, 360862306a36Sopenharmony_ci unsigned long flags) 360962306a36Sopenharmony_ci{ 361062306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 361162306a36Sopenharmony_ci enum dma_slave_buswidth dev_width; 361262306a36Sopenharmony_ci struct udma_desc *d; 361362306a36Sopenharmony_ci u32 burst; 361462306a36Sopenharmony_ci 361562306a36Sopenharmony_ci if (dir != uc->config.dir) { 361662306a36Sopenharmony_ci dev_err(chan->device->dev, 361762306a36Sopenharmony_ci "%s: chan%d is for %s, not supporting %s\n", 361862306a36Sopenharmony_ci __func__, uc->id, 361962306a36Sopenharmony_ci dmaengine_get_direction_text(uc->config.dir), 362062306a36Sopenharmony_ci dmaengine_get_direction_text(dir)); 362162306a36Sopenharmony_ci return NULL; 362262306a36Sopenharmony_ci } 362362306a36Sopenharmony_ci 362462306a36Sopenharmony_ci uc->cyclic = true; 362562306a36Sopenharmony_ci 362662306a36Sopenharmony_ci if (dir == DMA_DEV_TO_MEM) { 362762306a36Sopenharmony_ci dev_width = uc->cfg.src_addr_width; 362862306a36Sopenharmony_ci burst = uc->cfg.src_maxburst; 362962306a36Sopenharmony_ci } else if (dir == DMA_MEM_TO_DEV) { 363062306a36Sopenharmony_ci dev_width = uc->cfg.dst_addr_width; 363162306a36Sopenharmony_ci burst = uc->cfg.dst_maxburst; 363262306a36Sopenharmony_ci } else { 363362306a36Sopenharmony_ci dev_err(uc->ud->dev, "%s: bad direction?\n", __func__); 363462306a36Sopenharmony_ci return NULL; 363562306a36Sopenharmony_ci } 363662306a36Sopenharmony_ci 363762306a36Sopenharmony_ci if (!burst) 363862306a36Sopenharmony_ci burst = 1; 363962306a36Sopenharmony_ci 364062306a36Sopenharmony_ci if (uc->config.pkt_mode) 364162306a36Sopenharmony_ci d = udma_prep_dma_cyclic_pkt(uc, buf_addr, buf_len, period_len, 364262306a36Sopenharmony_ci dir, flags); 364362306a36Sopenharmony_ci else 364462306a36Sopenharmony_ci d = udma_prep_dma_cyclic_tr(uc, buf_addr, buf_len, period_len, 364562306a36Sopenharmony_ci dir, flags); 364662306a36Sopenharmony_ci 364762306a36Sopenharmony_ci if (!d) 364862306a36Sopenharmony_ci return NULL; 364962306a36Sopenharmony_ci 365062306a36Sopenharmony_ci d->sglen = buf_len / period_len; 365162306a36Sopenharmony_ci 365262306a36Sopenharmony_ci d->dir = dir; 365362306a36Sopenharmony_ci d->residue = buf_len; 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci /* static TR for remote PDMA */ 365662306a36Sopenharmony_ci if (udma_configure_statictr(uc, d, dev_width, burst)) { 365762306a36Sopenharmony_ci dev_err(uc->ud->dev, 365862306a36Sopenharmony_ci "%s: StaticTR Z is limited to maximum 4095 (%u)\n", 365962306a36Sopenharmony_ci __func__, d->static_tr.bstcnt); 366062306a36Sopenharmony_ci 366162306a36Sopenharmony_ci udma_free_hwdesc(uc, d); 366262306a36Sopenharmony_ci kfree(d); 366362306a36Sopenharmony_ci return NULL; 366462306a36Sopenharmony_ci } 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci if (uc->config.metadata_size) 366762306a36Sopenharmony_ci d->vd.tx.metadata_ops = &metadata_ops; 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci return vchan_tx_prep(&uc->vc, &d->vd, flags); 367062306a36Sopenharmony_ci} 367162306a36Sopenharmony_ci 367262306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 367362306a36Sopenharmony_ciudma_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, 367462306a36Sopenharmony_ci size_t len, unsigned long tx_flags) 367562306a36Sopenharmony_ci{ 367662306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 367762306a36Sopenharmony_ci struct udma_desc *d; 367862306a36Sopenharmony_ci struct cppi5_tr_type15_t *tr_req; 367962306a36Sopenharmony_ci int num_tr; 368062306a36Sopenharmony_ci size_t tr_size = sizeof(struct cppi5_tr_type15_t); 368162306a36Sopenharmony_ci u16 tr0_cnt0, tr0_cnt1, tr1_cnt0; 368262306a36Sopenharmony_ci u32 csf = CPPI5_TR_CSF_SUPR_EVT; 368362306a36Sopenharmony_ci 368462306a36Sopenharmony_ci if (uc->config.dir != DMA_MEM_TO_MEM) { 368562306a36Sopenharmony_ci dev_err(chan->device->dev, 368662306a36Sopenharmony_ci "%s: chan%d is for %s, not supporting %s\n", 368762306a36Sopenharmony_ci __func__, uc->id, 368862306a36Sopenharmony_ci dmaengine_get_direction_text(uc->config.dir), 368962306a36Sopenharmony_ci dmaengine_get_direction_text(DMA_MEM_TO_MEM)); 369062306a36Sopenharmony_ci return NULL; 369162306a36Sopenharmony_ci } 369262306a36Sopenharmony_ci 369362306a36Sopenharmony_ci num_tr = udma_get_tr_counters(len, __ffs(src | dest), &tr0_cnt0, 369462306a36Sopenharmony_ci &tr0_cnt1, &tr1_cnt0); 369562306a36Sopenharmony_ci if (num_tr < 0) { 369662306a36Sopenharmony_ci dev_err(uc->ud->dev, "size %zu is not supported\n", 369762306a36Sopenharmony_ci len); 369862306a36Sopenharmony_ci return NULL; 369962306a36Sopenharmony_ci } 370062306a36Sopenharmony_ci 370162306a36Sopenharmony_ci d = udma_alloc_tr_desc(uc, tr_size, num_tr, DMA_MEM_TO_MEM); 370262306a36Sopenharmony_ci if (!d) 370362306a36Sopenharmony_ci return NULL; 370462306a36Sopenharmony_ci 370562306a36Sopenharmony_ci d->dir = DMA_MEM_TO_MEM; 370662306a36Sopenharmony_ci d->desc_idx = 0; 370762306a36Sopenharmony_ci d->tr_idx = 0; 370862306a36Sopenharmony_ci d->residue = len; 370962306a36Sopenharmony_ci 371062306a36Sopenharmony_ci if (uc->ud->match_data->type != DMA_TYPE_UDMA) { 371162306a36Sopenharmony_ci src |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; 371262306a36Sopenharmony_ci dest |= (u64)uc->ud->asel << K3_ADDRESS_ASEL_SHIFT; 371362306a36Sopenharmony_ci } else { 371462306a36Sopenharmony_ci csf |= CPPI5_TR_CSF_EOL_ICNT0; 371562306a36Sopenharmony_ci } 371662306a36Sopenharmony_ci 371762306a36Sopenharmony_ci tr_req = d->hwdesc[0].tr_req_base; 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci cppi5_tr_init(&tr_req[0].flags, CPPI5_TR_TYPE15, false, true, 372062306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 372162306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[0].flags, csf); 372262306a36Sopenharmony_ci 372362306a36Sopenharmony_ci tr_req[0].addr = src; 372462306a36Sopenharmony_ci tr_req[0].icnt0 = tr0_cnt0; 372562306a36Sopenharmony_ci tr_req[0].icnt1 = tr0_cnt1; 372662306a36Sopenharmony_ci tr_req[0].icnt2 = 1; 372762306a36Sopenharmony_ci tr_req[0].icnt3 = 1; 372862306a36Sopenharmony_ci tr_req[0].dim1 = tr0_cnt0; 372962306a36Sopenharmony_ci 373062306a36Sopenharmony_ci tr_req[0].daddr = dest; 373162306a36Sopenharmony_ci tr_req[0].dicnt0 = tr0_cnt0; 373262306a36Sopenharmony_ci tr_req[0].dicnt1 = tr0_cnt1; 373362306a36Sopenharmony_ci tr_req[0].dicnt2 = 1; 373462306a36Sopenharmony_ci tr_req[0].dicnt3 = 1; 373562306a36Sopenharmony_ci tr_req[0].ddim1 = tr0_cnt0; 373662306a36Sopenharmony_ci 373762306a36Sopenharmony_ci if (num_tr == 2) { 373862306a36Sopenharmony_ci cppi5_tr_init(&tr_req[1].flags, CPPI5_TR_TYPE15, false, true, 373962306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 374062306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[1].flags, csf); 374162306a36Sopenharmony_ci 374262306a36Sopenharmony_ci tr_req[1].addr = src + tr0_cnt1 * tr0_cnt0; 374362306a36Sopenharmony_ci tr_req[1].icnt0 = tr1_cnt0; 374462306a36Sopenharmony_ci tr_req[1].icnt1 = 1; 374562306a36Sopenharmony_ci tr_req[1].icnt2 = 1; 374662306a36Sopenharmony_ci tr_req[1].icnt3 = 1; 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci tr_req[1].daddr = dest + tr0_cnt1 * tr0_cnt0; 374962306a36Sopenharmony_ci tr_req[1].dicnt0 = tr1_cnt0; 375062306a36Sopenharmony_ci tr_req[1].dicnt1 = 1; 375162306a36Sopenharmony_ci tr_req[1].dicnt2 = 1; 375262306a36Sopenharmony_ci tr_req[1].dicnt3 = 1; 375362306a36Sopenharmony_ci } 375462306a36Sopenharmony_ci 375562306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req[num_tr - 1].flags, csf | CPPI5_TR_CSF_EOP); 375662306a36Sopenharmony_ci 375762306a36Sopenharmony_ci if (uc->config.metadata_size) 375862306a36Sopenharmony_ci d->vd.tx.metadata_ops = &metadata_ops; 375962306a36Sopenharmony_ci 376062306a36Sopenharmony_ci return vchan_tx_prep(&uc->vc, &d->vd, tx_flags); 376162306a36Sopenharmony_ci} 376262306a36Sopenharmony_ci 376362306a36Sopenharmony_cistatic void udma_issue_pending(struct dma_chan *chan) 376462306a36Sopenharmony_ci{ 376562306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 376662306a36Sopenharmony_ci unsigned long flags; 376762306a36Sopenharmony_ci 376862306a36Sopenharmony_ci spin_lock_irqsave(&uc->vc.lock, flags); 376962306a36Sopenharmony_ci 377062306a36Sopenharmony_ci /* If we have something pending and no active descriptor, then */ 377162306a36Sopenharmony_ci if (vchan_issue_pending(&uc->vc) && !uc->desc) { 377262306a36Sopenharmony_ci /* 377362306a36Sopenharmony_ci * start a descriptor if the channel is NOT [marked as 377462306a36Sopenharmony_ci * terminating _and_ it is still running (teardown has not 377562306a36Sopenharmony_ci * completed yet)]. 377662306a36Sopenharmony_ci */ 377762306a36Sopenharmony_ci if (!(uc->state == UDMA_CHAN_IS_TERMINATING && 377862306a36Sopenharmony_ci udma_is_chan_running(uc))) 377962306a36Sopenharmony_ci udma_start(uc); 378062306a36Sopenharmony_ci } 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci spin_unlock_irqrestore(&uc->vc.lock, flags); 378362306a36Sopenharmony_ci} 378462306a36Sopenharmony_ci 378562306a36Sopenharmony_cistatic enum dma_status udma_tx_status(struct dma_chan *chan, 378662306a36Sopenharmony_ci dma_cookie_t cookie, 378762306a36Sopenharmony_ci struct dma_tx_state *txstate) 378862306a36Sopenharmony_ci{ 378962306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 379062306a36Sopenharmony_ci enum dma_status ret; 379162306a36Sopenharmony_ci unsigned long flags; 379262306a36Sopenharmony_ci 379362306a36Sopenharmony_ci spin_lock_irqsave(&uc->vc.lock, flags); 379462306a36Sopenharmony_ci 379562306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 379662306a36Sopenharmony_ci 379762306a36Sopenharmony_ci if (!udma_is_chan_running(uc)) 379862306a36Sopenharmony_ci ret = DMA_COMPLETE; 379962306a36Sopenharmony_ci 380062306a36Sopenharmony_ci if (ret == DMA_IN_PROGRESS && udma_is_chan_paused(uc)) 380162306a36Sopenharmony_ci ret = DMA_PAUSED; 380262306a36Sopenharmony_ci 380362306a36Sopenharmony_ci if (ret == DMA_COMPLETE || !txstate) 380462306a36Sopenharmony_ci goto out; 380562306a36Sopenharmony_ci 380662306a36Sopenharmony_ci if (uc->desc && uc->desc->vd.tx.cookie == cookie) { 380762306a36Sopenharmony_ci u32 peer_bcnt = 0; 380862306a36Sopenharmony_ci u32 bcnt = 0; 380962306a36Sopenharmony_ci u32 residue = uc->desc->residue; 381062306a36Sopenharmony_ci u32 delay = 0; 381162306a36Sopenharmony_ci 381262306a36Sopenharmony_ci if (uc->desc->dir == DMA_MEM_TO_DEV) { 381362306a36Sopenharmony_ci bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_SBCNT_REG); 381462306a36Sopenharmony_ci 381562306a36Sopenharmony_ci if (uc->config.ep_type != PSIL_EP_NATIVE) { 381662306a36Sopenharmony_ci peer_bcnt = udma_tchanrt_read(uc, 381762306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_BCNT_REG); 381862306a36Sopenharmony_ci 381962306a36Sopenharmony_ci if (bcnt > peer_bcnt) 382062306a36Sopenharmony_ci delay = bcnt - peer_bcnt; 382162306a36Sopenharmony_ci } 382262306a36Sopenharmony_ci } else if (uc->desc->dir == DMA_DEV_TO_MEM) { 382362306a36Sopenharmony_ci bcnt = udma_rchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci if (uc->config.ep_type != PSIL_EP_NATIVE) { 382662306a36Sopenharmony_ci peer_bcnt = udma_rchanrt_read(uc, 382762306a36Sopenharmony_ci UDMA_CHAN_RT_PEER_BCNT_REG); 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci if (peer_bcnt > bcnt) 383062306a36Sopenharmony_ci delay = peer_bcnt - bcnt; 383162306a36Sopenharmony_ci } 383262306a36Sopenharmony_ci } else { 383362306a36Sopenharmony_ci bcnt = udma_tchanrt_read(uc, UDMA_CHAN_RT_BCNT_REG); 383462306a36Sopenharmony_ci } 383562306a36Sopenharmony_ci 383662306a36Sopenharmony_ci if (bcnt && !(bcnt % uc->desc->residue)) 383762306a36Sopenharmony_ci residue = 0; 383862306a36Sopenharmony_ci else 383962306a36Sopenharmony_ci residue -= bcnt % uc->desc->residue; 384062306a36Sopenharmony_ci 384162306a36Sopenharmony_ci if (!residue && (uc->config.dir == DMA_DEV_TO_MEM || !delay)) { 384262306a36Sopenharmony_ci ret = DMA_COMPLETE; 384362306a36Sopenharmony_ci delay = 0; 384462306a36Sopenharmony_ci } 384562306a36Sopenharmony_ci 384662306a36Sopenharmony_ci dma_set_residue(txstate, residue); 384762306a36Sopenharmony_ci dma_set_in_flight_bytes(txstate, delay); 384862306a36Sopenharmony_ci 384962306a36Sopenharmony_ci } else { 385062306a36Sopenharmony_ci ret = DMA_COMPLETE; 385162306a36Sopenharmony_ci } 385262306a36Sopenharmony_ci 385362306a36Sopenharmony_ciout: 385462306a36Sopenharmony_ci spin_unlock_irqrestore(&uc->vc.lock, flags); 385562306a36Sopenharmony_ci return ret; 385662306a36Sopenharmony_ci} 385762306a36Sopenharmony_ci 385862306a36Sopenharmony_cistatic int udma_pause(struct dma_chan *chan) 385962306a36Sopenharmony_ci{ 386062306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 386162306a36Sopenharmony_ci 386262306a36Sopenharmony_ci /* pause the channel */ 386362306a36Sopenharmony_ci switch (uc->config.dir) { 386462306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 386562306a36Sopenharmony_ci udma_rchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 386662306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE, 386762306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE); 386862306a36Sopenharmony_ci break; 386962306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 387062306a36Sopenharmony_ci udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 387162306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE, 387262306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE); 387362306a36Sopenharmony_ci break; 387462306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 387562306a36Sopenharmony_ci udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_CTL_REG, 387662306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_PAUSE, 387762306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_PAUSE); 387862306a36Sopenharmony_ci break; 387962306a36Sopenharmony_ci default: 388062306a36Sopenharmony_ci return -EINVAL; 388162306a36Sopenharmony_ci } 388262306a36Sopenharmony_ci 388362306a36Sopenharmony_ci return 0; 388462306a36Sopenharmony_ci} 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_cistatic int udma_resume(struct dma_chan *chan) 388762306a36Sopenharmony_ci{ 388862306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 388962306a36Sopenharmony_ci 389062306a36Sopenharmony_ci /* resume the channel */ 389162306a36Sopenharmony_ci switch (uc->config.dir) { 389262306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 389362306a36Sopenharmony_ci udma_rchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 389462306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE, 0); 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci break; 389762306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 389862306a36Sopenharmony_ci udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_PEER_RT_EN_REG, 389962306a36Sopenharmony_ci UDMA_PEER_RT_EN_PAUSE, 0); 390062306a36Sopenharmony_ci break; 390162306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 390262306a36Sopenharmony_ci udma_tchanrt_update_bits(uc, UDMA_CHAN_RT_CTL_REG, 390362306a36Sopenharmony_ci UDMA_CHAN_RT_CTL_PAUSE, 0); 390462306a36Sopenharmony_ci break; 390562306a36Sopenharmony_ci default: 390662306a36Sopenharmony_ci return -EINVAL; 390762306a36Sopenharmony_ci } 390862306a36Sopenharmony_ci 390962306a36Sopenharmony_ci return 0; 391062306a36Sopenharmony_ci} 391162306a36Sopenharmony_ci 391262306a36Sopenharmony_cistatic int udma_terminate_all(struct dma_chan *chan) 391362306a36Sopenharmony_ci{ 391462306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 391562306a36Sopenharmony_ci unsigned long flags; 391662306a36Sopenharmony_ci LIST_HEAD(head); 391762306a36Sopenharmony_ci 391862306a36Sopenharmony_ci spin_lock_irqsave(&uc->vc.lock, flags); 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci if (udma_is_chan_running(uc)) 392162306a36Sopenharmony_ci udma_stop(uc); 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_ci if (uc->desc) { 392462306a36Sopenharmony_ci uc->terminated_desc = uc->desc; 392562306a36Sopenharmony_ci uc->desc = NULL; 392662306a36Sopenharmony_ci uc->terminated_desc->terminated = true; 392762306a36Sopenharmony_ci cancel_delayed_work(&uc->tx_drain.work); 392862306a36Sopenharmony_ci } 392962306a36Sopenharmony_ci 393062306a36Sopenharmony_ci uc->paused = false; 393162306a36Sopenharmony_ci 393262306a36Sopenharmony_ci vchan_get_all_descriptors(&uc->vc, &head); 393362306a36Sopenharmony_ci spin_unlock_irqrestore(&uc->vc.lock, flags); 393462306a36Sopenharmony_ci vchan_dma_desc_free_list(&uc->vc, &head); 393562306a36Sopenharmony_ci 393662306a36Sopenharmony_ci return 0; 393762306a36Sopenharmony_ci} 393862306a36Sopenharmony_ci 393962306a36Sopenharmony_cistatic void udma_synchronize(struct dma_chan *chan) 394062306a36Sopenharmony_ci{ 394162306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 394262306a36Sopenharmony_ci unsigned long timeout = msecs_to_jiffies(1000); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci vchan_synchronize(&uc->vc); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci if (uc->state == UDMA_CHAN_IS_TERMINATING) { 394762306a36Sopenharmony_ci timeout = wait_for_completion_timeout(&uc->teardown_completed, 394862306a36Sopenharmony_ci timeout); 394962306a36Sopenharmony_ci if (!timeout) { 395062306a36Sopenharmony_ci dev_warn(uc->ud->dev, "chan%d teardown timeout!\n", 395162306a36Sopenharmony_ci uc->id); 395262306a36Sopenharmony_ci udma_dump_chan_stdata(uc); 395362306a36Sopenharmony_ci udma_reset_chan(uc, true); 395462306a36Sopenharmony_ci } 395562306a36Sopenharmony_ci } 395662306a36Sopenharmony_ci 395762306a36Sopenharmony_ci udma_reset_chan(uc, false); 395862306a36Sopenharmony_ci if (udma_is_chan_running(uc)) 395962306a36Sopenharmony_ci dev_warn(uc->ud->dev, "chan%d refused to stop!\n", uc->id); 396062306a36Sopenharmony_ci 396162306a36Sopenharmony_ci cancel_delayed_work_sync(&uc->tx_drain.work); 396262306a36Sopenharmony_ci udma_reset_rings(uc); 396362306a36Sopenharmony_ci} 396462306a36Sopenharmony_ci 396562306a36Sopenharmony_cistatic void udma_desc_pre_callback(struct virt_dma_chan *vc, 396662306a36Sopenharmony_ci struct virt_dma_desc *vd, 396762306a36Sopenharmony_ci struct dmaengine_result *result) 396862306a36Sopenharmony_ci{ 396962306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(&vc->chan); 397062306a36Sopenharmony_ci struct udma_desc *d; 397162306a36Sopenharmony_ci u8 status; 397262306a36Sopenharmony_ci 397362306a36Sopenharmony_ci if (!vd) 397462306a36Sopenharmony_ci return; 397562306a36Sopenharmony_ci 397662306a36Sopenharmony_ci d = to_udma_desc(&vd->tx); 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci if (d->metadata_size) 397962306a36Sopenharmony_ci udma_fetch_epib(uc, d); 398062306a36Sopenharmony_ci 398162306a36Sopenharmony_ci if (result) { 398262306a36Sopenharmony_ci void *desc_vaddr = udma_curr_cppi5_desc_vaddr(d, d->desc_idx); 398362306a36Sopenharmony_ci 398462306a36Sopenharmony_ci if (cppi5_desc_get_type(desc_vaddr) == 398562306a36Sopenharmony_ci CPPI5_INFO0_DESC_TYPE_VAL_HOST) { 398662306a36Sopenharmony_ci /* Provide residue information for the client */ 398762306a36Sopenharmony_ci result->residue = d->residue - 398862306a36Sopenharmony_ci cppi5_hdesc_get_pktlen(desc_vaddr); 398962306a36Sopenharmony_ci if (result->residue) 399062306a36Sopenharmony_ci result->result = DMA_TRANS_ABORTED; 399162306a36Sopenharmony_ci else 399262306a36Sopenharmony_ci result->result = DMA_TRANS_NOERROR; 399362306a36Sopenharmony_ci } else { 399462306a36Sopenharmony_ci result->residue = 0; 399562306a36Sopenharmony_ci /* Propagate TR Response errors to the client */ 399662306a36Sopenharmony_ci status = d->hwdesc[0].tr_resp_base->status; 399762306a36Sopenharmony_ci if (status) 399862306a36Sopenharmony_ci result->result = DMA_TRANS_ABORTED; 399962306a36Sopenharmony_ci else 400062306a36Sopenharmony_ci result->result = DMA_TRANS_NOERROR; 400162306a36Sopenharmony_ci } 400262306a36Sopenharmony_ci } 400362306a36Sopenharmony_ci} 400462306a36Sopenharmony_ci 400562306a36Sopenharmony_ci/* 400662306a36Sopenharmony_ci * This tasklet handles the completion of a DMA descriptor by 400762306a36Sopenharmony_ci * calling its callback and freeing it. 400862306a36Sopenharmony_ci */ 400962306a36Sopenharmony_cistatic void udma_vchan_complete(struct tasklet_struct *t) 401062306a36Sopenharmony_ci{ 401162306a36Sopenharmony_ci struct virt_dma_chan *vc = from_tasklet(vc, t, task); 401262306a36Sopenharmony_ci struct virt_dma_desc *vd, *_vd; 401362306a36Sopenharmony_ci struct dmaengine_desc_callback cb; 401462306a36Sopenharmony_ci LIST_HEAD(head); 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci spin_lock_irq(&vc->lock); 401762306a36Sopenharmony_ci list_splice_tail_init(&vc->desc_completed, &head); 401862306a36Sopenharmony_ci vd = vc->cyclic; 401962306a36Sopenharmony_ci if (vd) { 402062306a36Sopenharmony_ci vc->cyclic = NULL; 402162306a36Sopenharmony_ci dmaengine_desc_get_callback(&vd->tx, &cb); 402262306a36Sopenharmony_ci } else { 402362306a36Sopenharmony_ci memset(&cb, 0, sizeof(cb)); 402462306a36Sopenharmony_ci } 402562306a36Sopenharmony_ci spin_unlock_irq(&vc->lock); 402662306a36Sopenharmony_ci 402762306a36Sopenharmony_ci udma_desc_pre_callback(vc, vd, NULL); 402862306a36Sopenharmony_ci dmaengine_desc_callback_invoke(&cb, NULL); 402962306a36Sopenharmony_ci 403062306a36Sopenharmony_ci list_for_each_entry_safe(vd, _vd, &head, node) { 403162306a36Sopenharmony_ci struct dmaengine_result result; 403262306a36Sopenharmony_ci 403362306a36Sopenharmony_ci dmaengine_desc_get_callback(&vd->tx, &cb); 403462306a36Sopenharmony_ci 403562306a36Sopenharmony_ci list_del(&vd->node); 403662306a36Sopenharmony_ci 403762306a36Sopenharmony_ci udma_desc_pre_callback(vc, vd, &result); 403862306a36Sopenharmony_ci dmaengine_desc_callback_invoke(&cb, &result); 403962306a36Sopenharmony_ci 404062306a36Sopenharmony_ci vchan_vdesc_fini(vd); 404162306a36Sopenharmony_ci } 404262306a36Sopenharmony_ci} 404362306a36Sopenharmony_ci 404462306a36Sopenharmony_cistatic void udma_free_chan_resources(struct dma_chan *chan) 404562306a36Sopenharmony_ci{ 404662306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 404762306a36Sopenharmony_ci struct udma_dev *ud = to_udma_dev(chan->device); 404862306a36Sopenharmony_ci 404962306a36Sopenharmony_ci udma_terminate_all(chan); 405062306a36Sopenharmony_ci if (uc->terminated_desc) { 405162306a36Sopenharmony_ci udma_reset_chan(uc, false); 405262306a36Sopenharmony_ci udma_reset_rings(uc); 405362306a36Sopenharmony_ci } 405462306a36Sopenharmony_ci 405562306a36Sopenharmony_ci cancel_delayed_work_sync(&uc->tx_drain.work); 405662306a36Sopenharmony_ci 405762306a36Sopenharmony_ci if (uc->irq_num_ring > 0) { 405862306a36Sopenharmony_ci free_irq(uc->irq_num_ring, uc); 405962306a36Sopenharmony_ci 406062306a36Sopenharmony_ci uc->irq_num_ring = 0; 406162306a36Sopenharmony_ci } 406262306a36Sopenharmony_ci if (uc->irq_num_udma > 0) { 406362306a36Sopenharmony_ci free_irq(uc->irq_num_udma, uc); 406462306a36Sopenharmony_ci 406562306a36Sopenharmony_ci uc->irq_num_udma = 0; 406662306a36Sopenharmony_ci } 406762306a36Sopenharmony_ci 406862306a36Sopenharmony_ci /* Release PSI-L pairing */ 406962306a36Sopenharmony_ci if (uc->psil_paired) { 407062306a36Sopenharmony_ci navss_psil_unpair(ud, uc->config.src_thread, 407162306a36Sopenharmony_ci uc->config.dst_thread); 407262306a36Sopenharmony_ci uc->psil_paired = false; 407362306a36Sopenharmony_ci } 407462306a36Sopenharmony_ci 407562306a36Sopenharmony_ci vchan_free_chan_resources(&uc->vc); 407662306a36Sopenharmony_ci tasklet_kill(&uc->vc.task); 407762306a36Sopenharmony_ci 407862306a36Sopenharmony_ci bcdma_free_bchan_resources(uc); 407962306a36Sopenharmony_ci udma_free_tx_resources(uc); 408062306a36Sopenharmony_ci udma_free_rx_resources(uc); 408162306a36Sopenharmony_ci udma_reset_uchan(uc); 408262306a36Sopenharmony_ci 408362306a36Sopenharmony_ci if (uc->use_dma_pool) { 408462306a36Sopenharmony_ci dma_pool_destroy(uc->hdesc_pool); 408562306a36Sopenharmony_ci uc->use_dma_pool = false; 408662306a36Sopenharmony_ci } 408762306a36Sopenharmony_ci} 408862306a36Sopenharmony_ci 408962306a36Sopenharmony_cistatic struct platform_driver udma_driver; 409062306a36Sopenharmony_cistatic struct platform_driver bcdma_driver; 409162306a36Sopenharmony_cistatic struct platform_driver pktdma_driver; 409262306a36Sopenharmony_ci 409362306a36Sopenharmony_cistruct udma_filter_param { 409462306a36Sopenharmony_ci int remote_thread_id; 409562306a36Sopenharmony_ci u32 atype; 409662306a36Sopenharmony_ci u32 asel; 409762306a36Sopenharmony_ci u32 tr_trigger_type; 409862306a36Sopenharmony_ci}; 409962306a36Sopenharmony_ci 410062306a36Sopenharmony_cistatic bool udma_dma_filter_fn(struct dma_chan *chan, void *param) 410162306a36Sopenharmony_ci{ 410262306a36Sopenharmony_ci struct udma_chan_config *ucc; 410362306a36Sopenharmony_ci struct psil_endpoint_config *ep_config; 410462306a36Sopenharmony_ci struct udma_filter_param *filter_param; 410562306a36Sopenharmony_ci struct udma_chan *uc; 410662306a36Sopenharmony_ci struct udma_dev *ud; 410762306a36Sopenharmony_ci 410862306a36Sopenharmony_ci if (chan->device->dev->driver != &udma_driver.driver && 410962306a36Sopenharmony_ci chan->device->dev->driver != &bcdma_driver.driver && 411062306a36Sopenharmony_ci chan->device->dev->driver != &pktdma_driver.driver) 411162306a36Sopenharmony_ci return false; 411262306a36Sopenharmony_ci 411362306a36Sopenharmony_ci uc = to_udma_chan(chan); 411462306a36Sopenharmony_ci ucc = &uc->config; 411562306a36Sopenharmony_ci ud = uc->ud; 411662306a36Sopenharmony_ci filter_param = param; 411762306a36Sopenharmony_ci 411862306a36Sopenharmony_ci if (filter_param->atype > 2) { 411962306a36Sopenharmony_ci dev_err(ud->dev, "Invalid channel atype: %u\n", 412062306a36Sopenharmony_ci filter_param->atype); 412162306a36Sopenharmony_ci return false; 412262306a36Sopenharmony_ci } 412362306a36Sopenharmony_ci 412462306a36Sopenharmony_ci if (filter_param->asel > 15) { 412562306a36Sopenharmony_ci dev_err(ud->dev, "Invalid channel asel: %u\n", 412662306a36Sopenharmony_ci filter_param->asel); 412762306a36Sopenharmony_ci return false; 412862306a36Sopenharmony_ci } 412962306a36Sopenharmony_ci 413062306a36Sopenharmony_ci ucc->remote_thread_id = filter_param->remote_thread_id; 413162306a36Sopenharmony_ci ucc->atype = filter_param->atype; 413262306a36Sopenharmony_ci ucc->asel = filter_param->asel; 413362306a36Sopenharmony_ci ucc->tr_trigger_type = filter_param->tr_trigger_type; 413462306a36Sopenharmony_ci 413562306a36Sopenharmony_ci if (ucc->tr_trigger_type) { 413662306a36Sopenharmony_ci ucc->dir = DMA_MEM_TO_MEM; 413762306a36Sopenharmony_ci goto triggered_bchan; 413862306a36Sopenharmony_ci } else if (ucc->remote_thread_id & K3_PSIL_DST_THREAD_ID_OFFSET) { 413962306a36Sopenharmony_ci ucc->dir = DMA_MEM_TO_DEV; 414062306a36Sopenharmony_ci } else { 414162306a36Sopenharmony_ci ucc->dir = DMA_DEV_TO_MEM; 414262306a36Sopenharmony_ci } 414362306a36Sopenharmony_ci 414462306a36Sopenharmony_ci ep_config = psil_get_ep_config(ucc->remote_thread_id); 414562306a36Sopenharmony_ci if (IS_ERR(ep_config)) { 414662306a36Sopenharmony_ci dev_err(ud->dev, "No configuration for psi-l thread 0x%04x\n", 414762306a36Sopenharmony_ci ucc->remote_thread_id); 414862306a36Sopenharmony_ci ucc->dir = DMA_MEM_TO_MEM; 414962306a36Sopenharmony_ci ucc->remote_thread_id = -1; 415062306a36Sopenharmony_ci ucc->atype = 0; 415162306a36Sopenharmony_ci ucc->asel = 0; 415262306a36Sopenharmony_ci return false; 415362306a36Sopenharmony_ci } 415462306a36Sopenharmony_ci 415562306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_BCDMA && 415662306a36Sopenharmony_ci ep_config->pkt_mode) { 415762306a36Sopenharmony_ci dev_err(ud->dev, 415862306a36Sopenharmony_ci "Only TR mode is supported (psi-l thread 0x%04x)\n", 415962306a36Sopenharmony_ci ucc->remote_thread_id); 416062306a36Sopenharmony_ci ucc->dir = DMA_MEM_TO_MEM; 416162306a36Sopenharmony_ci ucc->remote_thread_id = -1; 416262306a36Sopenharmony_ci ucc->atype = 0; 416362306a36Sopenharmony_ci ucc->asel = 0; 416462306a36Sopenharmony_ci return false; 416562306a36Sopenharmony_ci } 416662306a36Sopenharmony_ci 416762306a36Sopenharmony_ci ucc->pkt_mode = ep_config->pkt_mode; 416862306a36Sopenharmony_ci ucc->channel_tpl = ep_config->channel_tpl; 416962306a36Sopenharmony_ci ucc->notdpkt = ep_config->notdpkt; 417062306a36Sopenharmony_ci ucc->ep_type = ep_config->ep_type; 417162306a36Sopenharmony_ci 417262306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_PKTDMA && 417362306a36Sopenharmony_ci ep_config->mapped_channel_id >= 0) { 417462306a36Sopenharmony_ci ucc->mapped_channel_id = ep_config->mapped_channel_id; 417562306a36Sopenharmony_ci ucc->default_flow_id = ep_config->default_flow_id; 417662306a36Sopenharmony_ci } else { 417762306a36Sopenharmony_ci ucc->mapped_channel_id = -1; 417862306a36Sopenharmony_ci ucc->default_flow_id = -1; 417962306a36Sopenharmony_ci } 418062306a36Sopenharmony_ci 418162306a36Sopenharmony_ci if (ucc->ep_type != PSIL_EP_NATIVE) { 418262306a36Sopenharmony_ci const struct udma_match_data *match_data = ud->match_data; 418362306a36Sopenharmony_ci 418462306a36Sopenharmony_ci if (match_data->flags & UDMA_FLAG_PDMA_ACC32) 418562306a36Sopenharmony_ci ucc->enable_acc32 = ep_config->pdma_acc32; 418662306a36Sopenharmony_ci if (match_data->flags & UDMA_FLAG_PDMA_BURST) 418762306a36Sopenharmony_ci ucc->enable_burst = ep_config->pdma_burst; 418862306a36Sopenharmony_ci } 418962306a36Sopenharmony_ci 419062306a36Sopenharmony_ci ucc->needs_epib = ep_config->needs_epib; 419162306a36Sopenharmony_ci ucc->psd_size = ep_config->psd_size; 419262306a36Sopenharmony_ci ucc->metadata_size = 419362306a36Sopenharmony_ci (ucc->needs_epib ? CPPI5_INFO0_HDESC_EPIB_SIZE : 0) + 419462306a36Sopenharmony_ci ucc->psd_size; 419562306a36Sopenharmony_ci 419662306a36Sopenharmony_ci if (ucc->pkt_mode) 419762306a36Sopenharmony_ci ucc->hdesc_size = ALIGN(sizeof(struct cppi5_host_desc_t) + 419862306a36Sopenharmony_ci ucc->metadata_size, ud->desc_align); 419962306a36Sopenharmony_ci 420062306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: Remote thread: 0x%04x (%s)\n", uc->id, 420162306a36Sopenharmony_ci ucc->remote_thread_id, dmaengine_get_direction_text(ucc->dir)); 420262306a36Sopenharmony_ci 420362306a36Sopenharmony_ci return true; 420462306a36Sopenharmony_ci 420562306a36Sopenharmony_citriggered_bchan: 420662306a36Sopenharmony_ci dev_dbg(ud->dev, "chan%d: triggered channel (type: %u)\n", uc->id, 420762306a36Sopenharmony_ci ucc->tr_trigger_type); 420862306a36Sopenharmony_ci 420962306a36Sopenharmony_ci return true; 421062306a36Sopenharmony_ci 421162306a36Sopenharmony_ci} 421262306a36Sopenharmony_ci 421362306a36Sopenharmony_cistatic struct dma_chan *udma_of_xlate(struct of_phandle_args *dma_spec, 421462306a36Sopenharmony_ci struct of_dma *ofdma) 421562306a36Sopenharmony_ci{ 421662306a36Sopenharmony_ci struct udma_dev *ud = ofdma->of_dma_data; 421762306a36Sopenharmony_ci dma_cap_mask_t mask = ud->ddev.cap_mask; 421862306a36Sopenharmony_ci struct udma_filter_param filter_param; 421962306a36Sopenharmony_ci struct dma_chan *chan; 422062306a36Sopenharmony_ci 422162306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_BCDMA) { 422262306a36Sopenharmony_ci if (dma_spec->args_count != 3) 422362306a36Sopenharmony_ci return NULL; 422462306a36Sopenharmony_ci 422562306a36Sopenharmony_ci filter_param.tr_trigger_type = dma_spec->args[0]; 422662306a36Sopenharmony_ci filter_param.remote_thread_id = dma_spec->args[1]; 422762306a36Sopenharmony_ci filter_param.asel = dma_spec->args[2]; 422862306a36Sopenharmony_ci filter_param.atype = 0; 422962306a36Sopenharmony_ci } else { 423062306a36Sopenharmony_ci if (dma_spec->args_count != 1 && dma_spec->args_count != 2) 423162306a36Sopenharmony_ci return NULL; 423262306a36Sopenharmony_ci 423362306a36Sopenharmony_ci filter_param.remote_thread_id = dma_spec->args[0]; 423462306a36Sopenharmony_ci filter_param.tr_trigger_type = 0; 423562306a36Sopenharmony_ci if (dma_spec->args_count == 2) { 423662306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_UDMA) { 423762306a36Sopenharmony_ci filter_param.atype = dma_spec->args[1]; 423862306a36Sopenharmony_ci filter_param.asel = 0; 423962306a36Sopenharmony_ci } else { 424062306a36Sopenharmony_ci filter_param.atype = 0; 424162306a36Sopenharmony_ci filter_param.asel = dma_spec->args[1]; 424262306a36Sopenharmony_ci } 424362306a36Sopenharmony_ci } else { 424462306a36Sopenharmony_ci filter_param.atype = 0; 424562306a36Sopenharmony_ci filter_param.asel = 0; 424662306a36Sopenharmony_ci } 424762306a36Sopenharmony_ci } 424862306a36Sopenharmony_ci 424962306a36Sopenharmony_ci chan = __dma_request_channel(&mask, udma_dma_filter_fn, &filter_param, 425062306a36Sopenharmony_ci ofdma->of_node); 425162306a36Sopenharmony_ci if (!chan) { 425262306a36Sopenharmony_ci dev_err(ud->dev, "get channel fail in %s.\n", __func__); 425362306a36Sopenharmony_ci return ERR_PTR(-EINVAL); 425462306a36Sopenharmony_ci } 425562306a36Sopenharmony_ci 425662306a36Sopenharmony_ci return chan; 425762306a36Sopenharmony_ci} 425862306a36Sopenharmony_ci 425962306a36Sopenharmony_cistatic struct udma_match_data am654_main_data = { 426062306a36Sopenharmony_ci .type = DMA_TYPE_UDMA, 426162306a36Sopenharmony_ci .psil_base = 0x1000, 426262306a36Sopenharmony_ci .enable_memcpy_support = true, 426362306a36Sopenharmony_ci .statictr_z_mask = GENMASK(11, 0), 426462306a36Sopenharmony_ci .burst_size = { 426562306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 426662306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* H Channels */ 426762306a36Sopenharmony_ci 0, /* No UH Channels */ 426862306a36Sopenharmony_ci }, 426962306a36Sopenharmony_ci}; 427062306a36Sopenharmony_ci 427162306a36Sopenharmony_cistatic struct udma_match_data am654_mcu_data = { 427262306a36Sopenharmony_ci .type = DMA_TYPE_UDMA, 427362306a36Sopenharmony_ci .psil_base = 0x6000, 427462306a36Sopenharmony_ci .enable_memcpy_support = false, 427562306a36Sopenharmony_ci .statictr_z_mask = GENMASK(11, 0), 427662306a36Sopenharmony_ci .burst_size = { 427762306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 427862306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* H Channels */ 427962306a36Sopenharmony_ci 0, /* No UH Channels */ 428062306a36Sopenharmony_ci }, 428162306a36Sopenharmony_ci}; 428262306a36Sopenharmony_ci 428362306a36Sopenharmony_cistatic struct udma_match_data j721e_main_data = { 428462306a36Sopenharmony_ci .type = DMA_TYPE_UDMA, 428562306a36Sopenharmony_ci .psil_base = 0x1000, 428662306a36Sopenharmony_ci .enable_memcpy_support = true, 428762306a36Sopenharmony_ci .flags = UDMA_FLAGS_J7_CLASS, 428862306a36Sopenharmony_ci .statictr_z_mask = GENMASK(23, 0), 428962306a36Sopenharmony_ci .burst_size = { 429062306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 429162306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES, /* H Channels */ 429262306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES, /* UH Channels */ 429362306a36Sopenharmony_ci }, 429462306a36Sopenharmony_ci}; 429562306a36Sopenharmony_ci 429662306a36Sopenharmony_cistatic struct udma_match_data j721e_mcu_data = { 429762306a36Sopenharmony_ci .type = DMA_TYPE_UDMA, 429862306a36Sopenharmony_ci .psil_base = 0x6000, 429962306a36Sopenharmony_ci .enable_memcpy_support = false, /* MEM_TO_MEM is slow via MCU UDMA */ 430062306a36Sopenharmony_ci .flags = UDMA_FLAGS_J7_CLASS, 430162306a36Sopenharmony_ci .statictr_z_mask = GENMASK(23, 0), 430262306a36Sopenharmony_ci .burst_size = { 430362306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 430462306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES, /* H Channels */ 430562306a36Sopenharmony_ci 0, /* No UH Channels */ 430662306a36Sopenharmony_ci }, 430762306a36Sopenharmony_ci}; 430862306a36Sopenharmony_ci 430962306a36Sopenharmony_cistatic struct udma_soc_data am62a_dmss_csi_soc_data = { 431062306a36Sopenharmony_ci .oes = { 431162306a36Sopenharmony_ci .bcdma_rchan_data = 0xe00, 431262306a36Sopenharmony_ci .bcdma_rchan_ring = 0x1000, 431362306a36Sopenharmony_ci }, 431462306a36Sopenharmony_ci}; 431562306a36Sopenharmony_ci 431662306a36Sopenharmony_cistatic struct udma_soc_data j721s2_bcdma_csi_soc_data = { 431762306a36Sopenharmony_ci .oes = { 431862306a36Sopenharmony_ci .bcdma_tchan_data = 0x800, 431962306a36Sopenharmony_ci .bcdma_tchan_ring = 0xa00, 432062306a36Sopenharmony_ci .bcdma_rchan_data = 0xe00, 432162306a36Sopenharmony_ci .bcdma_rchan_ring = 0x1000, 432262306a36Sopenharmony_ci }, 432362306a36Sopenharmony_ci}; 432462306a36Sopenharmony_ci 432562306a36Sopenharmony_cistatic struct udma_match_data am62a_bcdma_csirx_data = { 432662306a36Sopenharmony_ci .type = DMA_TYPE_BCDMA, 432762306a36Sopenharmony_ci .psil_base = 0x3100, 432862306a36Sopenharmony_ci .enable_memcpy_support = false, 432962306a36Sopenharmony_ci .burst_size = { 433062306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 433162306a36Sopenharmony_ci 0, /* No H Channels */ 433262306a36Sopenharmony_ci 0, /* No UH Channels */ 433362306a36Sopenharmony_ci }, 433462306a36Sopenharmony_ci .soc_data = &am62a_dmss_csi_soc_data, 433562306a36Sopenharmony_ci}; 433662306a36Sopenharmony_ci 433762306a36Sopenharmony_cistatic struct udma_match_data am64_bcdma_data = { 433862306a36Sopenharmony_ci .type = DMA_TYPE_BCDMA, 433962306a36Sopenharmony_ci .psil_base = 0x2000, /* for tchan and rchan, not applicable to bchan */ 434062306a36Sopenharmony_ci .enable_memcpy_support = true, /* Supported via bchan */ 434162306a36Sopenharmony_ci .flags = UDMA_FLAGS_J7_CLASS, 434262306a36Sopenharmony_ci .statictr_z_mask = GENMASK(23, 0), 434362306a36Sopenharmony_ci .burst_size = { 434462306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 434562306a36Sopenharmony_ci 0, /* No H Channels */ 434662306a36Sopenharmony_ci 0, /* No UH Channels */ 434762306a36Sopenharmony_ci }, 434862306a36Sopenharmony_ci}; 434962306a36Sopenharmony_ci 435062306a36Sopenharmony_cistatic struct udma_match_data am64_pktdma_data = { 435162306a36Sopenharmony_ci .type = DMA_TYPE_PKTDMA, 435262306a36Sopenharmony_ci .psil_base = 0x1000, 435362306a36Sopenharmony_ci .enable_memcpy_support = false, /* PKTDMA does not support MEM_TO_MEM */ 435462306a36Sopenharmony_ci .flags = UDMA_FLAGS_J7_CLASS, 435562306a36Sopenharmony_ci .statictr_z_mask = GENMASK(23, 0), 435662306a36Sopenharmony_ci .burst_size = { 435762306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 435862306a36Sopenharmony_ci 0, /* No H Channels */ 435962306a36Sopenharmony_ci 0, /* No UH Channels */ 436062306a36Sopenharmony_ci }, 436162306a36Sopenharmony_ci}; 436262306a36Sopenharmony_ci 436362306a36Sopenharmony_cistatic struct udma_match_data j721s2_bcdma_csi_data = { 436462306a36Sopenharmony_ci .type = DMA_TYPE_BCDMA, 436562306a36Sopenharmony_ci .psil_base = 0x2000, 436662306a36Sopenharmony_ci .enable_memcpy_support = false, 436762306a36Sopenharmony_ci .burst_size = { 436862306a36Sopenharmony_ci TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES, /* Normal Channels */ 436962306a36Sopenharmony_ci 0, /* No H Channels */ 437062306a36Sopenharmony_ci 0, /* No UH Channels */ 437162306a36Sopenharmony_ci }, 437262306a36Sopenharmony_ci .soc_data = &j721s2_bcdma_csi_soc_data, 437362306a36Sopenharmony_ci}; 437462306a36Sopenharmony_ci 437562306a36Sopenharmony_cistatic const struct of_device_id udma_of_match[] = { 437662306a36Sopenharmony_ci { 437762306a36Sopenharmony_ci .compatible = "ti,am654-navss-main-udmap", 437862306a36Sopenharmony_ci .data = &am654_main_data, 437962306a36Sopenharmony_ci }, 438062306a36Sopenharmony_ci { 438162306a36Sopenharmony_ci .compatible = "ti,am654-navss-mcu-udmap", 438262306a36Sopenharmony_ci .data = &am654_mcu_data, 438362306a36Sopenharmony_ci }, { 438462306a36Sopenharmony_ci .compatible = "ti,j721e-navss-main-udmap", 438562306a36Sopenharmony_ci .data = &j721e_main_data, 438662306a36Sopenharmony_ci }, { 438762306a36Sopenharmony_ci .compatible = "ti,j721e-navss-mcu-udmap", 438862306a36Sopenharmony_ci .data = &j721e_mcu_data, 438962306a36Sopenharmony_ci }, 439062306a36Sopenharmony_ci { 439162306a36Sopenharmony_ci .compatible = "ti,am64-dmss-bcdma", 439262306a36Sopenharmony_ci .data = &am64_bcdma_data, 439362306a36Sopenharmony_ci }, 439462306a36Sopenharmony_ci { 439562306a36Sopenharmony_ci .compatible = "ti,am64-dmss-pktdma", 439662306a36Sopenharmony_ci .data = &am64_pktdma_data, 439762306a36Sopenharmony_ci }, 439862306a36Sopenharmony_ci { 439962306a36Sopenharmony_ci .compatible = "ti,am62a-dmss-bcdma-csirx", 440062306a36Sopenharmony_ci .data = &am62a_bcdma_csirx_data, 440162306a36Sopenharmony_ci }, 440262306a36Sopenharmony_ci { 440362306a36Sopenharmony_ci .compatible = "ti,j721s2-dmss-bcdma-csi", 440462306a36Sopenharmony_ci .data = &j721s2_bcdma_csi_data, 440562306a36Sopenharmony_ci }, 440662306a36Sopenharmony_ci { /* Sentinel */ }, 440762306a36Sopenharmony_ci}; 440862306a36Sopenharmony_ci 440962306a36Sopenharmony_cistatic struct udma_soc_data am654_soc_data = { 441062306a36Sopenharmony_ci .oes = { 441162306a36Sopenharmony_ci .udma_rchan = 0x200, 441262306a36Sopenharmony_ci }, 441362306a36Sopenharmony_ci}; 441462306a36Sopenharmony_ci 441562306a36Sopenharmony_cistatic struct udma_soc_data j721e_soc_data = { 441662306a36Sopenharmony_ci .oes = { 441762306a36Sopenharmony_ci .udma_rchan = 0x400, 441862306a36Sopenharmony_ci }, 441962306a36Sopenharmony_ci}; 442062306a36Sopenharmony_ci 442162306a36Sopenharmony_cistatic struct udma_soc_data j7200_soc_data = { 442262306a36Sopenharmony_ci .oes = { 442362306a36Sopenharmony_ci .udma_rchan = 0x80, 442462306a36Sopenharmony_ci }, 442562306a36Sopenharmony_ci}; 442662306a36Sopenharmony_ci 442762306a36Sopenharmony_cistatic struct udma_soc_data am64_soc_data = { 442862306a36Sopenharmony_ci .oes = { 442962306a36Sopenharmony_ci .bcdma_bchan_data = 0x2200, 443062306a36Sopenharmony_ci .bcdma_bchan_ring = 0x2400, 443162306a36Sopenharmony_ci .bcdma_tchan_data = 0x2800, 443262306a36Sopenharmony_ci .bcdma_tchan_ring = 0x2a00, 443362306a36Sopenharmony_ci .bcdma_rchan_data = 0x2e00, 443462306a36Sopenharmony_ci .bcdma_rchan_ring = 0x3000, 443562306a36Sopenharmony_ci .pktdma_tchan_flow = 0x1200, 443662306a36Sopenharmony_ci .pktdma_rchan_flow = 0x1600, 443762306a36Sopenharmony_ci }, 443862306a36Sopenharmony_ci .bcdma_trigger_event_offset = 0xc400, 443962306a36Sopenharmony_ci}; 444062306a36Sopenharmony_ci 444162306a36Sopenharmony_cistatic const struct soc_device_attribute k3_soc_devices[] = { 444262306a36Sopenharmony_ci { .family = "AM65X", .data = &am654_soc_data }, 444362306a36Sopenharmony_ci { .family = "J721E", .data = &j721e_soc_data }, 444462306a36Sopenharmony_ci { .family = "J7200", .data = &j7200_soc_data }, 444562306a36Sopenharmony_ci { .family = "AM64X", .data = &am64_soc_data }, 444662306a36Sopenharmony_ci { .family = "J721S2", .data = &j721e_soc_data}, 444762306a36Sopenharmony_ci { .family = "AM62X", .data = &am64_soc_data }, 444862306a36Sopenharmony_ci { .family = "AM62AX", .data = &am64_soc_data }, 444962306a36Sopenharmony_ci { .family = "J784S4", .data = &j721e_soc_data }, 445062306a36Sopenharmony_ci { /* sentinel */ } 445162306a36Sopenharmony_ci}; 445262306a36Sopenharmony_ci 445362306a36Sopenharmony_cistatic int udma_get_mmrs(struct platform_device *pdev, struct udma_dev *ud) 445462306a36Sopenharmony_ci{ 445562306a36Sopenharmony_ci u32 cap2, cap3, cap4; 445662306a36Sopenharmony_ci int i; 445762306a36Sopenharmony_ci 445862306a36Sopenharmony_ci ud->mmrs[MMR_GCFG] = devm_platform_ioremap_resource_byname(pdev, mmr_names[MMR_GCFG]); 445962306a36Sopenharmony_ci if (IS_ERR(ud->mmrs[MMR_GCFG])) 446062306a36Sopenharmony_ci return PTR_ERR(ud->mmrs[MMR_GCFG]); 446162306a36Sopenharmony_ci 446262306a36Sopenharmony_ci cap2 = udma_read(ud->mmrs[MMR_GCFG], 0x28); 446362306a36Sopenharmony_ci cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c); 446462306a36Sopenharmony_ci 446562306a36Sopenharmony_ci switch (ud->match_data->type) { 446662306a36Sopenharmony_ci case DMA_TYPE_UDMA: 446762306a36Sopenharmony_ci ud->rflow_cnt = UDMA_CAP3_RFLOW_CNT(cap3); 446862306a36Sopenharmony_ci ud->tchan_cnt = UDMA_CAP2_TCHAN_CNT(cap2); 446962306a36Sopenharmony_ci ud->echan_cnt = UDMA_CAP2_ECHAN_CNT(cap2); 447062306a36Sopenharmony_ci ud->rchan_cnt = UDMA_CAP2_RCHAN_CNT(cap2); 447162306a36Sopenharmony_ci break; 447262306a36Sopenharmony_ci case DMA_TYPE_BCDMA: 447362306a36Sopenharmony_ci ud->bchan_cnt = BCDMA_CAP2_BCHAN_CNT(cap2); 447462306a36Sopenharmony_ci ud->tchan_cnt = BCDMA_CAP2_TCHAN_CNT(cap2); 447562306a36Sopenharmony_ci ud->rchan_cnt = BCDMA_CAP2_RCHAN_CNT(cap2); 447662306a36Sopenharmony_ci ud->rflow_cnt = ud->rchan_cnt; 447762306a36Sopenharmony_ci break; 447862306a36Sopenharmony_ci case DMA_TYPE_PKTDMA: 447962306a36Sopenharmony_ci cap4 = udma_read(ud->mmrs[MMR_GCFG], 0x30); 448062306a36Sopenharmony_ci ud->tchan_cnt = UDMA_CAP2_TCHAN_CNT(cap2); 448162306a36Sopenharmony_ci ud->rchan_cnt = UDMA_CAP2_RCHAN_CNT(cap2); 448262306a36Sopenharmony_ci ud->rflow_cnt = UDMA_CAP3_RFLOW_CNT(cap3); 448362306a36Sopenharmony_ci ud->tflow_cnt = PKTDMA_CAP4_TFLOW_CNT(cap4); 448462306a36Sopenharmony_ci break; 448562306a36Sopenharmony_ci default: 448662306a36Sopenharmony_ci return -EINVAL; 448762306a36Sopenharmony_ci } 448862306a36Sopenharmony_ci 448962306a36Sopenharmony_ci for (i = 1; i < MMR_LAST; i++) { 449062306a36Sopenharmony_ci if (i == MMR_BCHANRT && ud->bchan_cnt == 0) 449162306a36Sopenharmony_ci continue; 449262306a36Sopenharmony_ci if (i == MMR_TCHANRT && ud->tchan_cnt == 0) 449362306a36Sopenharmony_ci continue; 449462306a36Sopenharmony_ci if (i == MMR_RCHANRT && ud->rchan_cnt == 0) 449562306a36Sopenharmony_ci continue; 449662306a36Sopenharmony_ci 449762306a36Sopenharmony_ci ud->mmrs[i] = devm_platform_ioremap_resource_byname(pdev, mmr_names[i]); 449862306a36Sopenharmony_ci if (IS_ERR(ud->mmrs[i])) 449962306a36Sopenharmony_ci return PTR_ERR(ud->mmrs[i]); 450062306a36Sopenharmony_ci } 450162306a36Sopenharmony_ci 450262306a36Sopenharmony_ci return 0; 450362306a36Sopenharmony_ci} 450462306a36Sopenharmony_ci 450562306a36Sopenharmony_cistatic void udma_mark_resource_ranges(struct udma_dev *ud, unsigned long *map, 450662306a36Sopenharmony_ci struct ti_sci_resource_desc *rm_desc, 450762306a36Sopenharmony_ci char *name) 450862306a36Sopenharmony_ci{ 450962306a36Sopenharmony_ci bitmap_clear(map, rm_desc->start, rm_desc->num); 451062306a36Sopenharmony_ci bitmap_clear(map, rm_desc->start_sec, rm_desc->num_sec); 451162306a36Sopenharmony_ci dev_dbg(ud->dev, "ti_sci resource range for %s: %d:%d | %d:%d\n", name, 451262306a36Sopenharmony_ci rm_desc->start, rm_desc->num, rm_desc->start_sec, 451362306a36Sopenharmony_ci rm_desc->num_sec); 451462306a36Sopenharmony_ci} 451562306a36Sopenharmony_ci 451662306a36Sopenharmony_cistatic const char * const range_names[] = { 451762306a36Sopenharmony_ci [RM_RANGE_BCHAN] = "ti,sci-rm-range-bchan", 451862306a36Sopenharmony_ci [RM_RANGE_TCHAN] = "ti,sci-rm-range-tchan", 451962306a36Sopenharmony_ci [RM_RANGE_RCHAN] = "ti,sci-rm-range-rchan", 452062306a36Sopenharmony_ci [RM_RANGE_RFLOW] = "ti,sci-rm-range-rflow", 452162306a36Sopenharmony_ci [RM_RANGE_TFLOW] = "ti,sci-rm-range-tflow", 452262306a36Sopenharmony_ci}; 452362306a36Sopenharmony_ci 452462306a36Sopenharmony_cistatic int udma_setup_resources(struct udma_dev *ud) 452562306a36Sopenharmony_ci{ 452662306a36Sopenharmony_ci int ret, i, j; 452762306a36Sopenharmony_ci struct device *dev = ud->dev; 452862306a36Sopenharmony_ci struct ti_sci_resource *rm_res, irq_res; 452962306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 453062306a36Sopenharmony_ci u32 cap3; 453162306a36Sopenharmony_ci 453262306a36Sopenharmony_ci /* Set up the throughput level start indexes */ 453362306a36Sopenharmony_ci cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c); 453462306a36Sopenharmony_ci if (of_device_is_compatible(dev->of_node, 453562306a36Sopenharmony_ci "ti,am654-navss-main-udmap")) { 453662306a36Sopenharmony_ci ud->tchan_tpl.levels = 2; 453762306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = 8; 453862306a36Sopenharmony_ci } else if (of_device_is_compatible(dev->of_node, 453962306a36Sopenharmony_ci "ti,am654-navss-mcu-udmap")) { 454062306a36Sopenharmony_ci ud->tchan_tpl.levels = 2; 454162306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = 2; 454262306a36Sopenharmony_ci } else if (UDMA_CAP3_UCHAN_CNT(cap3)) { 454362306a36Sopenharmony_ci ud->tchan_tpl.levels = 3; 454462306a36Sopenharmony_ci ud->tchan_tpl.start_idx[1] = UDMA_CAP3_UCHAN_CNT(cap3); 454562306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3); 454662306a36Sopenharmony_ci } else if (UDMA_CAP3_HCHAN_CNT(cap3)) { 454762306a36Sopenharmony_ci ud->tchan_tpl.levels = 2; 454862306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3); 454962306a36Sopenharmony_ci } else { 455062306a36Sopenharmony_ci ud->tchan_tpl.levels = 1; 455162306a36Sopenharmony_ci } 455262306a36Sopenharmony_ci 455362306a36Sopenharmony_ci ud->rchan_tpl.levels = ud->tchan_tpl.levels; 455462306a36Sopenharmony_ci ud->rchan_tpl.start_idx[0] = ud->tchan_tpl.start_idx[0]; 455562306a36Sopenharmony_ci ud->rchan_tpl.start_idx[1] = ud->tchan_tpl.start_idx[1]; 455662306a36Sopenharmony_ci 455762306a36Sopenharmony_ci ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt), 455862306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 455962306a36Sopenharmony_ci ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans), 456062306a36Sopenharmony_ci GFP_KERNEL); 456162306a36Sopenharmony_ci ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt), 456262306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 456362306a36Sopenharmony_ci ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans), 456462306a36Sopenharmony_ci GFP_KERNEL); 456562306a36Sopenharmony_ci ud->rflow_gp_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rflow_cnt), 456662306a36Sopenharmony_ci sizeof(unsigned long), 456762306a36Sopenharmony_ci GFP_KERNEL); 456862306a36Sopenharmony_ci ud->rflow_gp_map_allocated = devm_kcalloc(dev, 456962306a36Sopenharmony_ci BITS_TO_LONGS(ud->rflow_cnt), 457062306a36Sopenharmony_ci sizeof(unsigned long), 457162306a36Sopenharmony_ci GFP_KERNEL); 457262306a36Sopenharmony_ci ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rflow_cnt), 457362306a36Sopenharmony_ci sizeof(unsigned long), 457462306a36Sopenharmony_ci GFP_KERNEL); 457562306a36Sopenharmony_ci ud->rflows = devm_kcalloc(dev, ud->rflow_cnt, sizeof(*ud->rflows), 457662306a36Sopenharmony_ci GFP_KERNEL); 457762306a36Sopenharmony_ci 457862306a36Sopenharmony_ci if (!ud->tchan_map || !ud->rchan_map || !ud->rflow_gp_map || 457962306a36Sopenharmony_ci !ud->rflow_gp_map_allocated || !ud->tchans || !ud->rchans || 458062306a36Sopenharmony_ci !ud->rflows || !ud->rflow_in_use) 458162306a36Sopenharmony_ci return -ENOMEM; 458262306a36Sopenharmony_ci 458362306a36Sopenharmony_ci /* 458462306a36Sopenharmony_ci * RX flows with the same Ids as RX channels are reserved to be used 458562306a36Sopenharmony_ci * as default flows if remote HW can't generate flow_ids. Those 458662306a36Sopenharmony_ci * RX flows can be requested only explicitly by id. 458762306a36Sopenharmony_ci */ 458862306a36Sopenharmony_ci bitmap_set(ud->rflow_gp_map_allocated, 0, ud->rchan_cnt); 458962306a36Sopenharmony_ci 459062306a36Sopenharmony_ci /* by default no GP rflows are assigned to Linux */ 459162306a36Sopenharmony_ci bitmap_set(ud->rflow_gp_map, 0, ud->rflow_cnt); 459262306a36Sopenharmony_ci 459362306a36Sopenharmony_ci /* Get resource ranges from tisci */ 459462306a36Sopenharmony_ci for (i = 0; i < RM_RANGE_LAST; i++) { 459562306a36Sopenharmony_ci if (i == RM_RANGE_BCHAN || i == RM_RANGE_TFLOW) 459662306a36Sopenharmony_ci continue; 459762306a36Sopenharmony_ci 459862306a36Sopenharmony_ci tisci_rm->rm_ranges[i] = 459962306a36Sopenharmony_ci devm_ti_sci_get_of_resource(tisci_rm->tisci, dev, 460062306a36Sopenharmony_ci tisci_rm->tisci_dev_id, 460162306a36Sopenharmony_ci (char *)range_names[i]); 460262306a36Sopenharmony_ci } 460362306a36Sopenharmony_ci 460462306a36Sopenharmony_ci /* tchan ranges */ 460562306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; 460662306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 460762306a36Sopenharmony_ci bitmap_zero(ud->tchan_map, ud->tchan_cnt); 460862306a36Sopenharmony_ci irq_res.sets = 1; 460962306a36Sopenharmony_ci } else { 461062306a36Sopenharmony_ci bitmap_fill(ud->tchan_map, ud->tchan_cnt); 461162306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 461262306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->tchan_map, 461362306a36Sopenharmony_ci &rm_res->desc[i], "tchan"); 461462306a36Sopenharmony_ci irq_res.sets = rm_res->sets; 461562306a36Sopenharmony_ci } 461662306a36Sopenharmony_ci 461762306a36Sopenharmony_ci /* rchan and matching default flow ranges */ 461862306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; 461962306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 462062306a36Sopenharmony_ci bitmap_zero(ud->rchan_map, ud->rchan_cnt); 462162306a36Sopenharmony_ci irq_res.sets++; 462262306a36Sopenharmony_ci } else { 462362306a36Sopenharmony_ci bitmap_fill(ud->rchan_map, ud->rchan_cnt); 462462306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 462562306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->rchan_map, 462662306a36Sopenharmony_ci &rm_res->desc[i], "rchan"); 462762306a36Sopenharmony_ci irq_res.sets += rm_res->sets; 462862306a36Sopenharmony_ci } 462962306a36Sopenharmony_ci 463062306a36Sopenharmony_ci irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL); 463162306a36Sopenharmony_ci if (!irq_res.desc) 463262306a36Sopenharmony_ci return -ENOMEM; 463362306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; 463462306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 463562306a36Sopenharmony_ci irq_res.desc[0].start = 0; 463662306a36Sopenharmony_ci irq_res.desc[0].num = ud->tchan_cnt; 463762306a36Sopenharmony_ci i = 1; 463862306a36Sopenharmony_ci } else { 463962306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) { 464062306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[i].start; 464162306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[i].num; 464262306a36Sopenharmony_ci irq_res.desc[i].start_sec = rm_res->desc[i].start_sec; 464362306a36Sopenharmony_ci irq_res.desc[i].num_sec = rm_res->desc[i].num_sec; 464462306a36Sopenharmony_ci } 464562306a36Sopenharmony_ci } 464662306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; 464762306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 464862306a36Sopenharmony_ci irq_res.desc[i].start = 0; 464962306a36Sopenharmony_ci irq_res.desc[i].num = ud->rchan_cnt; 465062306a36Sopenharmony_ci } else { 465162306a36Sopenharmony_ci for (j = 0; j < rm_res->sets; j++, i++) { 465262306a36Sopenharmony_ci if (rm_res->desc[j].num) { 465362306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[j].start + 465462306a36Sopenharmony_ci ud->soc_data->oes.udma_rchan; 465562306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[j].num; 465662306a36Sopenharmony_ci } 465762306a36Sopenharmony_ci if (rm_res->desc[j].num_sec) { 465862306a36Sopenharmony_ci irq_res.desc[i].start_sec = rm_res->desc[j].start_sec + 465962306a36Sopenharmony_ci ud->soc_data->oes.udma_rchan; 466062306a36Sopenharmony_ci irq_res.desc[i].num_sec = rm_res->desc[j].num_sec; 466162306a36Sopenharmony_ci } 466262306a36Sopenharmony_ci } 466362306a36Sopenharmony_ci } 466462306a36Sopenharmony_ci ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res); 466562306a36Sopenharmony_ci kfree(irq_res.desc); 466662306a36Sopenharmony_ci if (ret) { 466762306a36Sopenharmony_ci dev_err(ud->dev, "Failed to allocate MSI interrupts\n"); 466862306a36Sopenharmony_ci return ret; 466962306a36Sopenharmony_ci } 467062306a36Sopenharmony_ci 467162306a36Sopenharmony_ci /* GP rflow ranges */ 467262306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW]; 467362306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 467462306a36Sopenharmony_ci /* all gp flows are assigned exclusively to Linux */ 467562306a36Sopenharmony_ci bitmap_clear(ud->rflow_gp_map, ud->rchan_cnt, 467662306a36Sopenharmony_ci ud->rflow_cnt - ud->rchan_cnt); 467762306a36Sopenharmony_ci } else { 467862306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 467962306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->rflow_gp_map, 468062306a36Sopenharmony_ci &rm_res->desc[i], "gp-rflow"); 468162306a36Sopenharmony_ci } 468262306a36Sopenharmony_ci 468362306a36Sopenharmony_ci return 0; 468462306a36Sopenharmony_ci} 468562306a36Sopenharmony_ci 468662306a36Sopenharmony_cistatic int bcdma_setup_resources(struct udma_dev *ud) 468762306a36Sopenharmony_ci{ 468862306a36Sopenharmony_ci int ret, i, j; 468962306a36Sopenharmony_ci struct device *dev = ud->dev; 469062306a36Sopenharmony_ci struct ti_sci_resource *rm_res, irq_res; 469162306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 469262306a36Sopenharmony_ci const struct udma_oes_offsets *oes = &ud->soc_data->oes; 469362306a36Sopenharmony_ci u32 cap; 469462306a36Sopenharmony_ci 469562306a36Sopenharmony_ci /* Set up the throughput level start indexes */ 469662306a36Sopenharmony_ci cap = udma_read(ud->mmrs[MMR_GCFG], 0x2c); 469762306a36Sopenharmony_ci if (BCDMA_CAP3_UBCHAN_CNT(cap)) { 469862306a36Sopenharmony_ci ud->bchan_tpl.levels = 3; 469962306a36Sopenharmony_ci ud->bchan_tpl.start_idx[1] = BCDMA_CAP3_UBCHAN_CNT(cap); 470062306a36Sopenharmony_ci ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap); 470162306a36Sopenharmony_ci } else if (BCDMA_CAP3_HBCHAN_CNT(cap)) { 470262306a36Sopenharmony_ci ud->bchan_tpl.levels = 2; 470362306a36Sopenharmony_ci ud->bchan_tpl.start_idx[0] = BCDMA_CAP3_HBCHAN_CNT(cap); 470462306a36Sopenharmony_ci } else { 470562306a36Sopenharmony_ci ud->bchan_tpl.levels = 1; 470662306a36Sopenharmony_ci } 470762306a36Sopenharmony_ci 470862306a36Sopenharmony_ci cap = udma_read(ud->mmrs[MMR_GCFG], 0x30); 470962306a36Sopenharmony_ci if (BCDMA_CAP4_URCHAN_CNT(cap)) { 471062306a36Sopenharmony_ci ud->rchan_tpl.levels = 3; 471162306a36Sopenharmony_ci ud->rchan_tpl.start_idx[1] = BCDMA_CAP4_URCHAN_CNT(cap); 471262306a36Sopenharmony_ci ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap); 471362306a36Sopenharmony_ci } else if (BCDMA_CAP4_HRCHAN_CNT(cap)) { 471462306a36Sopenharmony_ci ud->rchan_tpl.levels = 2; 471562306a36Sopenharmony_ci ud->rchan_tpl.start_idx[0] = BCDMA_CAP4_HRCHAN_CNT(cap); 471662306a36Sopenharmony_ci } else { 471762306a36Sopenharmony_ci ud->rchan_tpl.levels = 1; 471862306a36Sopenharmony_ci } 471962306a36Sopenharmony_ci 472062306a36Sopenharmony_ci if (BCDMA_CAP4_UTCHAN_CNT(cap)) { 472162306a36Sopenharmony_ci ud->tchan_tpl.levels = 3; 472262306a36Sopenharmony_ci ud->tchan_tpl.start_idx[1] = BCDMA_CAP4_UTCHAN_CNT(cap); 472362306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap); 472462306a36Sopenharmony_ci } else if (BCDMA_CAP4_HTCHAN_CNT(cap)) { 472562306a36Sopenharmony_ci ud->tchan_tpl.levels = 2; 472662306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = BCDMA_CAP4_HTCHAN_CNT(cap); 472762306a36Sopenharmony_ci } else { 472862306a36Sopenharmony_ci ud->tchan_tpl.levels = 1; 472962306a36Sopenharmony_ci } 473062306a36Sopenharmony_ci 473162306a36Sopenharmony_ci ud->bchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->bchan_cnt), 473262306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 473362306a36Sopenharmony_ci ud->bchans = devm_kcalloc(dev, ud->bchan_cnt, sizeof(*ud->bchans), 473462306a36Sopenharmony_ci GFP_KERNEL); 473562306a36Sopenharmony_ci ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt), 473662306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 473762306a36Sopenharmony_ci ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans), 473862306a36Sopenharmony_ci GFP_KERNEL); 473962306a36Sopenharmony_ci ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt), 474062306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 474162306a36Sopenharmony_ci ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans), 474262306a36Sopenharmony_ci GFP_KERNEL); 474362306a36Sopenharmony_ci /* BCDMA do not really have flows, but the driver expect it */ 474462306a36Sopenharmony_ci ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rchan_cnt), 474562306a36Sopenharmony_ci sizeof(unsigned long), 474662306a36Sopenharmony_ci GFP_KERNEL); 474762306a36Sopenharmony_ci ud->rflows = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rflows), 474862306a36Sopenharmony_ci GFP_KERNEL); 474962306a36Sopenharmony_ci 475062306a36Sopenharmony_ci if (!ud->bchan_map || !ud->tchan_map || !ud->rchan_map || 475162306a36Sopenharmony_ci !ud->rflow_in_use || !ud->bchans || !ud->tchans || !ud->rchans || 475262306a36Sopenharmony_ci !ud->rflows) 475362306a36Sopenharmony_ci return -ENOMEM; 475462306a36Sopenharmony_ci 475562306a36Sopenharmony_ci /* Get resource ranges from tisci */ 475662306a36Sopenharmony_ci for (i = 0; i < RM_RANGE_LAST; i++) { 475762306a36Sopenharmony_ci if (i == RM_RANGE_RFLOW || i == RM_RANGE_TFLOW) 475862306a36Sopenharmony_ci continue; 475962306a36Sopenharmony_ci if (i == RM_RANGE_BCHAN && ud->bchan_cnt == 0) 476062306a36Sopenharmony_ci continue; 476162306a36Sopenharmony_ci if (i == RM_RANGE_TCHAN && ud->tchan_cnt == 0) 476262306a36Sopenharmony_ci continue; 476362306a36Sopenharmony_ci if (i == RM_RANGE_RCHAN && ud->rchan_cnt == 0) 476462306a36Sopenharmony_ci continue; 476562306a36Sopenharmony_ci 476662306a36Sopenharmony_ci tisci_rm->rm_ranges[i] = 476762306a36Sopenharmony_ci devm_ti_sci_get_of_resource(tisci_rm->tisci, dev, 476862306a36Sopenharmony_ci tisci_rm->tisci_dev_id, 476962306a36Sopenharmony_ci (char *)range_names[i]); 477062306a36Sopenharmony_ci } 477162306a36Sopenharmony_ci 477262306a36Sopenharmony_ci irq_res.sets = 0; 477362306a36Sopenharmony_ci 477462306a36Sopenharmony_ci /* bchan ranges */ 477562306a36Sopenharmony_ci if (ud->bchan_cnt) { 477662306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN]; 477762306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 477862306a36Sopenharmony_ci bitmap_zero(ud->bchan_map, ud->bchan_cnt); 477962306a36Sopenharmony_ci irq_res.sets++; 478062306a36Sopenharmony_ci } else { 478162306a36Sopenharmony_ci bitmap_fill(ud->bchan_map, ud->bchan_cnt); 478262306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 478362306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->bchan_map, 478462306a36Sopenharmony_ci &rm_res->desc[i], 478562306a36Sopenharmony_ci "bchan"); 478662306a36Sopenharmony_ci irq_res.sets += rm_res->sets; 478762306a36Sopenharmony_ci } 478862306a36Sopenharmony_ci } 478962306a36Sopenharmony_ci 479062306a36Sopenharmony_ci /* tchan ranges */ 479162306a36Sopenharmony_ci if (ud->tchan_cnt) { 479262306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; 479362306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 479462306a36Sopenharmony_ci bitmap_zero(ud->tchan_map, ud->tchan_cnt); 479562306a36Sopenharmony_ci irq_res.sets += 2; 479662306a36Sopenharmony_ci } else { 479762306a36Sopenharmony_ci bitmap_fill(ud->tchan_map, ud->tchan_cnt); 479862306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 479962306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->tchan_map, 480062306a36Sopenharmony_ci &rm_res->desc[i], 480162306a36Sopenharmony_ci "tchan"); 480262306a36Sopenharmony_ci irq_res.sets += rm_res->sets * 2; 480362306a36Sopenharmony_ci } 480462306a36Sopenharmony_ci } 480562306a36Sopenharmony_ci 480662306a36Sopenharmony_ci /* rchan ranges */ 480762306a36Sopenharmony_ci if (ud->rchan_cnt) { 480862306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; 480962306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 481062306a36Sopenharmony_ci bitmap_zero(ud->rchan_map, ud->rchan_cnt); 481162306a36Sopenharmony_ci irq_res.sets += 2; 481262306a36Sopenharmony_ci } else { 481362306a36Sopenharmony_ci bitmap_fill(ud->rchan_map, ud->rchan_cnt); 481462306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 481562306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->rchan_map, 481662306a36Sopenharmony_ci &rm_res->desc[i], 481762306a36Sopenharmony_ci "rchan"); 481862306a36Sopenharmony_ci irq_res.sets += rm_res->sets * 2; 481962306a36Sopenharmony_ci } 482062306a36Sopenharmony_ci } 482162306a36Sopenharmony_ci 482262306a36Sopenharmony_ci irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL); 482362306a36Sopenharmony_ci if (!irq_res.desc) 482462306a36Sopenharmony_ci return -ENOMEM; 482562306a36Sopenharmony_ci if (ud->bchan_cnt) { 482662306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_BCHAN]; 482762306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 482862306a36Sopenharmony_ci irq_res.desc[0].start = oes->bcdma_bchan_ring; 482962306a36Sopenharmony_ci irq_res.desc[0].num = ud->bchan_cnt; 483062306a36Sopenharmony_ci i = 1; 483162306a36Sopenharmony_ci } else { 483262306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) { 483362306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[i].start + 483462306a36Sopenharmony_ci oes->bcdma_bchan_ring; 483562306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[i].num; 483662306a36Sopenharmony_ci } 483762306a36Sopenharmony_ci } 483862306a36Sopenharmony_ci } else { 483962306a36Sopenharmony_ci i = 0; 484062306a36Sopenharmony_ci } 484162306a36Sopenharmony_ci 484262306a36Sopenharmony_ci if (ud->tchan_cnt) { 484362306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; 484462306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 484562306a36Sopenharmony_ci irq_res.desc[i].start = oes->bcdma_tchan_data; 484662306a36Sopenharmony_ci irq_res.desc[i].num = ud->tchan_cnt; 484762306a36Sopenharmony_ci irq_res.desc[i + 1].start = oes->bcdma_tchan_ring; 484862306a36Sopenharmony_ci irq_res.desc[i + 1].num = ud->tchan_cnt; 484962306a36Sopenharmony_ci i += 2; 485062306a36Sopenharmony_ci } else { 485162306a36Sopenharmony_ci for (j = 0; j < rm_res->sets; j++, i += 2) { 485262306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[j].start + 485362306a36Sopenharmony_ci oes->bcdma_tchan_data; 485462306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[j].num; 485562306a36Sopenharmony_ci 485662306a36Sopenharmony_ci irq_res.desc[i + 1].start = rm_res->desc[j].start + 485762306a36Sopenharmony_ci oes->bcdma_tchan_ring; 485862306a36Sopenharmony_ci irq_res.desc[i + 1].num = rm_res->desc[j].num; 485962306a36Sopenharmony_ci } 486062306a36Sopenharmony_ci } 486162306a36Sopenharmony_ci } 486262306a36Sopenharmony_ci if (ud->rchan_cnt) { 486362306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; 486462306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 486562306a36Sopenharmony_ci irq_res.desc[i].start = oes->bcdma_rchan_data; 486662306a36Sopenharmony_ci irq_res.desc[i].num = ud->rchan_cnt; 486762306a36Sopenharmony_ci irq_res.desc[i + 1].start = oes->bcdma_rchan_ring; 486862306a36Sopenharmony_ci irq_res.desc[i + 1].num = ud->rchan_cnt; 486962306a36Sopenharmony_ci i += 2; 487062306a36Sopenharmony_ci } else { 487162306a36Sopenharmony_ci for (j = 0; j < rm_res->sets; j++, i += 2) { 487262306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[j].start + 487362306a36Sopenharmony_ci oes->bcdma_rchan_data; 487462306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[j].num; 487562306a36Sopenharmony_ci 487662306a36Sopenharmony_ci irq_res.desc[i + 1].start = rm_res->desc[j].start + 487762306a36Sopenharmony_ci oes->bcdma_rchan_ring; 487862306a36Sopenharmony_ci irq_res.desc[i + 1].num = rm_res->desc[j].num; 487962306a36Sopenharmony_ci } 488062306a36Sopenharmony_ci } 488162306a36Sopenharmony_ci } 488262306a36Sopenharmony_ci 488362306a36Sopenharmony_ci ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res); 488462306a36Sopenharmony_ci kfree(irq_res.desc); 488562306a36Sopenharmony_ci if (ret) { 488662306a36Sopenharmony_ci dev_err(ud->dev, "Failed to allocate MSI interrupts\n"); 488762306a36Sopenharmony_ci return ret; 488862306a36Sopenharmony_ci } 488962306a36Sopenharmony_ci 489062306a36Sopenharmony_ci return 0; 489162306a36Sopenharmony_ci} 489262306a36Sopenharmony_ci 489362306a36Sopenharmony_cistatic int pktdma_setup_resources(struct udma_dev *ud) 489462306a36Sopenharmony_ci{ 489562306a36Sopenharmony_ci int ret, i, j; 489662306a36Sopenharmony_ci struct device *dev = ud->dev; 489762306a36Sopenharmony_ci struct ti_sci_resource *rm_res, irq_res; 489862306a36Sopenharmony_ci struct udma_tisci_rm *tisci_rm = &ud->tisci_rm; 489962306a36Sopenharmony_ci const struct udma_oes_offsets *oes = &ud->soc_data->oes; 490062306a36Sopenharmony_ci u32 cap3; 490162306a36Sopenharmony_ci 490262306a36Sopenharmony_ci /* Set up the throughput level start indexes */ 490362306a36Sopenharmony_ci cap3 = udma_read(ud->mmrs[MMR_GCFG], 0x2c); 490462306a36Sopenharmony_ci if (UDMA_CAP3_UCHAN_CNT(cap3)) { 490562306a36Sopenharmony_ci ud->tchan_tpl.levels = 3; 490662306a36Sopenharmony_ci ud->tchan_tpl.start_idx[1] = UDMA_CAP3_UCHAN_CNT(cap3); 490762306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3); 490862306a36Sopenharmony_ci } else if (UDMA_CAP3_HCHAN_CNT(cap3)) { 490962306a36Sopenharmony_ci ud->tchan_tpl.levels = 2; 491062306a36Sopenharmony_ci ud->tchan_tpl.start_idx[0] = UDMA_CAP3_HCHAN_CNT(cap3); 491162306a36Sopenharmony_ci } else { 491262306a36Sopenharmony_ci ud->tchan_tpl.levels = 1; 491362306a36Sopenharmony_ci } 491462306a36Sopenharmony_ci 491562306a36Sopenharmony_ci ud->rchan_tpl.levels = ud->tchan_tpl.levels; 491662306a36Sopenharmony_ci ud->rchan_tpl.start_idx[0] = ud->tchan_tpl.start_idx[0]; 491762306a36Sopenharmony_ci ud->rchan_tpl.start_idx[1] = ud->tchan_tpl.start_idx[1]; 491862306a36Sopenharmony_ci 491962306a36Sopenharmony_ci ud->tchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tchan_cnt), 492062306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 492162306a36Sopenharmony_ci ud->tchans = devm_kcalloc(dev, ud->tchan_cnt, sizeof(*ud->tchans), 492262306a36Sopenharmony_ci GFP_KERNEL); 492362306a36Sopenharmony_ci ud->rchan_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->rchan_cnt), 492462306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 492562306a36Sopenharmony_ci ud->rchans = devm_kcalloc(dev, ud->rchan_cnt, sizeof(*ud->rchans), 492662306a36Sopenharmony_ci GFP_KERNEL); 492762306a36Sopenharmony_ci ud->rflow_in_use = devm_kcalloc(dev, BITS_TO_LONGS(ud->rflow_cnt), 492862306a36Sopenharmony_ci sizeof(unsigned long), 492962306a36Sopenharmony_ci GFP_KERNEL); 493062306a36Sopenharmony_ci ud->rflows = devm_kcalloc(dev, ud->rflow_cnt, sizeof(*ud->rflows), 493162306a36Sopenharmony_ci GFP_KERNEL); 493262306a36Sopenharmony_ci ud->tflow_map = devm_kmalloc_array(dev, BITS_TO_LONGS(ud->tflow_cnt), 493362306a36Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 493462306a36Sopenharmony_ci 493562306a36Sopenharmony_ci if (!ud->tchan_map || !ud->rchan_map || !ud->tflow_map || !ud->tchans || 493662306a36Sopenharmony_ci !ud->rchans || !ud->rflows || !ud->rflow_in_use) 493762306a36Sopenharmony_ci return -ENOMEM; 493862306a36Sopenharmony_ci 493962306a36Sopenharmony_ci /* Get resource ranges from tisci */ 494062306a36Sopenharmony_ci for (i = 0; i < RM_RANGE_LAST; i++) { 494162306a36Sopenharmony_ci if (i == RM_RANGE_BCHAN) 494262306a36Sopenharmony_ci continue; 494362306a36Sopenharmony_ci 494462306a36Sopenharmony_ci tisci_rm->rm_ranges[i] = 494562306a36Sopenharmony_ci devm_ti_sci_get_of_resource(tisci_rm->tisci, dev, 494662306a36Sopenharmony_ci tisci_rm->tisci_dev_id, 494762306a36Sopenharmony_ci (char *)range_names[i]); 494862306a36Sopenharmony_ci } 494962306a36Sopenharmony_ci 495062306a36Sopenharmony_ci /* tchan ranges */ 495162306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TCHAN]; 495262306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 495362306a36Sopenharmony_ci bitmap_zero(ud->tchan_map, ud->tchan_cnt); 495462306a36Sopenharmony_ci } else { 495562306a36Sopenharmony_ci bitmap_fill(ud->tchan_map, ud->tchan_cnt); 495662306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 495762306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->tchan_map, 495862306a36Sopenharmony_ci &rm_res->desc[i], "tchan"); 495962306a36Sopenharmony_ci } 496062306a36Sopenharmony_ci 496162306a36Sopenharmony_ci /* rchan ranges */ 496262306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RCHAN]; 496362306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 496462306a36Sopenharmony_ci bitmap_zero(ud->rchan_map, ud->rchan_cnt); 496562306a36Sopenharmony_ci } else { 496662306a36Sopenharmony_ci bitmap_fill(ud->rchan_map, ud->rchan_cnt); 496762306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 496862306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->rchan_map, 496962306a36Sopenharmony_ci &rm_res->desc[i], "rchan"); 497062306a36Sopenharmony_ci } 497162306a36Sopenharmony_ci 497262306a36Sopenharmony_ci /* rflow ranges */ 497362306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW]; 497462306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 497562306a36Sopenharmony_ci /* all rflows are assigned exclusively to Linux */ 497662306a36Sopenharmony_ci bitmap_zero(ud->rflow_in_use, ud->rflow_cnt); 497762306a36Sopenharmony_ci irq_res.sets = 1; 497862306a36Sopenharmony_ci } else { 497962306a36Sopenharmony_ci bitmap_fill(ud->rflow_in_use, ud->rflow_cnt); 498062306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 498162306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->rflow_in_use, 498262306a36Sopenharmony_ci &rm_res->desc[i], "rflow"); 498362306a36Sopenharmony_ci irq_res.sets = rm_res->sets; 498462306a36Sopenharmony_ci } 498562306a36Sopenharmony_ci 498662306a36Sopenharmony_ci /* tflow ranges */ 498762306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW]; 498862306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 498962306a36Sopenharmony_ci /* all tflows are assigned exclusively to Linux */ 499062306a36Sopenharmony_ci bitmap_zero(ud->tflow_map, ud->tflow_cnt); 499162306a36Sopenharmony_ci irq_res.sets++; 499262306a36Sopenharmony_ci } else { 499362306a36Sopenharmony_ci bitmap_fill(ud->tflow_map, ud->tflow_cnt); 499462306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) 499562306a36Sopenharmony_ci udma_mark_resource_ranges(ud, ud->tflow_map, 499662306a36Sopenharmony_ci &rm_res->desc[i], "tflow"); 499762306a36Sopenharmony_ci irq_res.sets += rm_res->sets; 499862306a36Sopenharmony_ci } 499962306a36Sopenharmony_ci 500062306a36Sopenharmony_ci irq_res.desc = kcalloc(irq_res.sets, sizeof(*irq_res.desc), GFP_KERNEL); 500162306a36Sopenharmony_ci if (!irq_res.desc) 500262306a36Sopenharmony_ci return -ENOMEM; 500362306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_TFLOW]; 500462306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 500562306a36Sopenharmony_ci irq_res.desc[0].start = oes->pktdma_tchan_flow; 500662306a36Sopenharmony_ci irq_res.desc[0].num = ud->tflow_cnt; 500762306a36Sopenharmony_ci i = 1; 500862306a36Sopenharmony_ci } else { 500962306a36Sopenharmony_ci for (i = 0; i < rm_res->sets; i++) { 501062306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[i].start + 501162306a36Sopenharmony_ci oes->pktdma_tchan_flow; 501262306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[i].num; 501362306a36Sopenharmony_ci } 501462306a36Sopenharmony_ci } 501562306a36Sopenharmony_ci rm_res = tisci_rm->rm_ranges[RM_RANGE_RFLOW]; 501662306a36Sopenharmony_ci if (IS_ERR(rm_res)) { 501762306a36Sopenharmony_ci irq_res.desc[i].start = oes->pktdma_rchan_flow; 501862306a36Sopenharmony_ci irq_res.desc[i].num = ud->rflow_cnt; 501962306a36Sopenharmony_ci } else { 502062306a36Sopenharmony_ci for (j = 0; j < rm_res->sets; j++, i++) { 502162306a36Sopenharmony_ci irq_res.desc[i].start = rm_res->desc[j].start + 502262306a36Sopenharmony_ci oes->pktdma_rchan_flow; 502362306a36Sopenharmony_ci irq_res.desc[i].num = rm_res->desc[j].num; 502462306a36Sopenharmony_ci } 502562306a36Sopenharmony_ci } 502662306a36Sopenharmony_ci ret = ti_sci_inta_msi_domain_alloc_irqs(ud->dev, &irq_res); 502762306a36Sopenharmony_ci kfree(irq_res.desc); 502862306a36Sopenharmony_ci if (ret) { 502962306a36Sopenharmony_ci dev_err(ud->dev, "Failed to allocate MSI interrupts\n"); 503062306a36Sopenharmony_ci return ret; 503162306a36Sopenharmony_ci } 503262306a36Sopenharmony_ci 503362306a36Sopenharmony_ci return 0; 503462306a36Sopenharmony_ci} 503562306a36Sopenharmony_ci 503662306a36Sopenharmony_cistatic int setup_resources(struct udma_dev *ud) 503762306a36Sopenharmony_ci{ 503862306a36Sopenharmony_ci struct device *dev = ud->dev; 503962306a36Sopenharmony_ci int ch_count, ret; 504062306a36Sopenharmony_ci 504162306a36Sopenharmony_ci switch (ud->match_data->type) { 504262306a36Sopenharmony_ci case DMA_TYPE_UDMA: 504362306a36Sopenharmony_ci ret = udma_setup_resources(ud); 504462306a36Sopenharmony_ci break; 504562306a36Sopenharmony_ci case DMA_TYPE_BCDMA: 504662306a36Sopenharmony_ci ret = bcdma_setup_resources(ud); 504762306a36Sopenharmony_ci break; 504862306a36Sopenharmony_ci case DMA_TYPE_PKTDMA: 504962306a36Sopenharmony_ci ret = pktdma_setup_resources(ud); 505062306a36Sopenharmony_ci break; 505162306a36Sopenharmony_ci default: 505262306a36Sopenharmony_ci return -EINVAL; 505362306a36Sopenharmony_ci } 505462306a36Sopenharmony_ci 505562306a36Sopenharmony_ci if (ret) 505662306a36Sopenharmony_ci return ret; 505762306a36Sopenharmony_ci 505862306a36Sopenharmony_ci ch_count = ud->bchan_cnt + ud->tchan_cnt + ud->rchan_cnt; 505962306a36Sopenharmony_ci if (ud->bchan_cnt) 506062306a36Sopenharmony_ci ch_count -= bitmap_weight(ud->bchan_map, ud->bchan_cnt); 506162306a36Sopenharmony_ci ch_count -= bitmap_weight(ud->tchan_map, ud->tchan_cnt); 506262306a36Sopenharmony_ci ch_count -= bitmap_weight(ud->rchan_map, ud->rchan_cnt); 506362306a36Sopenharmony_ci if (!ch_count) 506462306a36Sopenharmony_ci return -ENODEV; 506562306a36Sopenharmony_ci 506662306a36Sopenharmony_ci ud->channels = devm_kcalloc(dev, ch_count, sizeof(*ud->channels), 506762306a36Sopenharmony_ci GFP_KERNEL); 506862306a36Sopenharmony_ci if (!ud->channels) 506962306a36Sopenharmony_ci return -ENOMEM; 507062306a36Sopenharmony_ci 507162306a36Sopenharmony_ci switch (ud->match_data->type) { 507262306a36Sopenharmony_ci case DMA_TYPE_UDMA: 507362306a36Sopenharmony_ci dev_info(dev, 507462306a36Sopenharmony_ci "Channels: %d (tchan: %u, rchan: %u, gp-rflow: %u)\n", 507562306a36Sopenharmony_ci ch_count, 507662306a36Sopenharmony_ci ud->tchan_cnt - bitmap_weight(ud->tchan_map, 507762306a36Sopenharmony_ci ud->tchan_cnt), 507862306a36Sopenharmony_ci ud->rchan_cnt - bitmap_weight(ud->rchan_map, 507962306a36Sopenharmony_ci ud->rchan_cnt), 508062306a36Sopenharmony_ci ud->rflow_cnt - bitmap_weight(ud->rflow_gp_map, 508162306a36Sopenharmony_ci ud->rflow_cnt)); 508262306a36Sopenharmony_ci break; 508362306a36Sopenharmony_ci case DMA_TYPE_BCDMA: 508462306a36Sopenharmony_ci dev_info(dev, 508562306a36Sopenharmony_ci "Channels: %d (bchan: %u, tchan: %u, rchan: %u)\n", 508662306a36Sopenharmony_ci ch_count, 508762306a36Sopenharmony_ci ud->bchan_cnt - bitmap_weight(ud->bchan_map, 508862306a36Sopenharmony_ci ud->bchan_cnt), 508962306a36Sopenharmony_ci ud->tchan_cnt - bitmap_weight(ud->tchan_map, 509062306a36Sopenharmony_ci ud->tchan_cnt), 509162306a36Sopenharmony_ci ud->rchan_cnt - bitmap_weight(ud->rchan_map, 509262306a36Sopenharmony_ci ud->rchan_cnt)); 509362306a36Sopenharmony_ci break; 509462306a36Sopenharmony_ci case DMA_TYPE_PKTDMA: 509562306a36Sopenharmony_ci dev_info(dev, 509662306a36Sopenharmony_ci "Channels: %d (tchan: %u, rchan: %u)\n", 509762306a36Sopenharmony_ci ch_count, 509862306a36Sopenharmony_ci ud->tchan_cnt - bitmap_weight(ud->tchan_map, 509962306a36Sopenharmony_ci ud->tchan_cnt), 510062306a36Sopenharmony_ci ud->rchan_cnt - bitmap_weight(ud->rchan_map, 510162306a36Sopenharmony_ci ud->rchan_cnt)); 510262306a36Sopenharmony_ci break; 510362306a36Sopenharmony_ci default: 510462306a36Sopenharmony_ci break; 510562306a36Sopenharmony_ci } 510662306a36Sopenharmony_ci 510762306a36Sopenharmony_ci return ch_count; 510862306a36Sopenharmony_ci} 510962306a36Sopenharmony_ci 511062306a36Sopenharmony_cistatic int udma_setup_rx_flush(struct udma_dev *ud) 511162306a36Sopenharmony_ci{ 511262306a36Sopenharmony_ci struct udma_rx_flush *rx_flush = &ud->rx_flush; 511362306a36Sopenharmony_ci struct cppi5_desc_hdr_t *tr_desc; 511462306a36Sopenharmony_ci struct cppi5_tr_type1_t *tr_req; 511562306a36Sopenharmony_ci struct cppi5_host_desc_t *desc; 511662306a36Sopenharmony_ci struct device *dev = ud->dev; 511762306a36Sopenharmony_ci struct udma_hwdesc *hwdesc; 511862306a36Sopenharmony_ci size_t tr_size; 511962306a36Sopenharmony_ci 512062306a36Sopenharmony_ci /* Allocate 1K buffer for discarded data on RX channel teardown */ 512162306a36Sopenharmony_ci rx_flush->buffer_size = SZ_1K; 512262306a36Sopenharmony_ci rx_flush->buffer_vaddr = devm_kzalloc(dev, rx_flush->buffer_size, 512362306a36Sopenharmony_ci GFP_KERNEL); 512462306a36Sopenharmony_ci if (!rx_flush->buffer_vaddr) 512562306a36Sopenharmony_ci return -ENOMEM; 512662306a36Sopenharmony_ci 512762306a36Sopenharmony_ci rx_flush->buffer_paddr = dma_map_single(dev, rx_flush->buffer_vaddr, 512862306a36Sopenharmony_ci rx_flush->buffer_size, 512962306a36Sopenharmony_ci DMA_TO_DEVICE); 513062306a36Sopenharmony_ci if (dma_mapping_error(dev, rx_flush->buffer_paddr)) 513162306a36Sopenharmony_ci return -ENOMEM; 513262306a36Sopenharmony_ci 513362306a36Sopenharmony_ci /* Set up descriptor to be used for TR mode */ 513462306a36Sopenharmony_ci hwdesc = &rx_flush->hwdescs[0]; 513562306a36Sopenharmony_ci tr_size = sizeof(struct cppi5_tr_type1_t); 513662306a36Sopenharmony_ci hwdesc->cppi5_desc_size = cppi5_trdesc_calc_size(tr_size, 1); 513762306a36Sopenharmony_ci hwdesc->cppi5_desc_size = ALIGN(hwdesc->cppi5_desc_size, 513862306a36Sopenharmony_ci ud->desc_align); 513962306a36Sopenharmony_ci 514062306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size, 514162306a36Sopenharmony_ci GFP_KERNEL); 514262306a36Sopenharmony_ci if (!hwdesc->cppi5_desc_vaddr) 514362306a36Sopenharmony_ci return -ENOMEM; 514462306a36Sopenharmony_ci 514562306a36Sopenharmony_ci hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr, 514662306a36Sopenharmony_ci hwdesc->cppi5_desc_size, 514762306a36Sopenharmony_ci DMA_TO_DEVICE); 514862306a36Sopenharmony_ci if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr)) 514962306a36Sopenharmony_ci return -ENOMEM; 515062306a36Sopenharmony_ci 515162306a36Sopenharmony_ci /* Start of the TR req records */ 515262306a36Sopenharmony_ci hwdesc->tr_req_base = hwdesc->cppi5_desc_vaddr + tr_size; 515362306a36Sopenharmony_ci /* Start address of the TR response array */ 515462306a36Sopenharmony_ci hwdesc->tr_resp_base = hwdesc->tr_req_base + tr_size; 515562306a36Sopenharmony_ci 515662306a36Sopenharmony_ci tr_desc = hwdesc->cppi5_desc_vaddr; 515762306a36Sopenharmony_ci cppi5_trdesc_init(tr_desc, 1, tr_size, 0, 0); 515862306a36Sopenharmony_ci cppi5_desc_set_pktids(tr_desc, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT); 515962306a36Sopenharmony_ci cppi5_desc_set_retpolicy(tr_desc, 0, 0); 516062306a36Sopenharmony_ci 516162306a36Sopenharmony_ci tr_req = hwdesc->tr_req_base; 516262306a36Sopenharmony_ci cppi5_tr_init(&tr_req->flags, CPPI5_TR_TYPE1, false, false, 516362306a36Sopenharmony_ci CPPI5_TR_EVENT_SIZE_COMPLETION, 0); 516462306a36Sopenharmony_ci cppi5_tr_csf_set(&tr_req->flags, CPPI5_TR_CSF_SUPR_EVT); 516562306a36Sopenharmony_ci 516662306a36Sopenharmony_ci tr_req->addr = rx_flush->buffer_paddr; 516762306a36Sopenharmony_ci tr_req->icnt0 = rx_flush->buffer_size; 516862306a36Sopenharmony_ci tr_req->icnt1 = 1; 516962306a36Sopenharmony_ci 517062306a36Sopenharmony_ci dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr, 517162306a36Sopenharmony_ci hwdesc->cppi5_desc_size, DMA_TO_DEVICE); 517262306a36Sopenharmony_ci 517362306a36Sopenharmony_ci /* Set up descriptor to be used for packet mode */ 517462306a36Sopenharmony_ci hwdesc = &rx_flush->hwdescs[1]; 517562306a36Sopenharmony_ci hwdesc->cppi5_desc_size = ALIGN(sizeof(struct cppi5_host_desc_t) + 517662306a36Sopenharmony_ci CPPI5_INFO0_HDESC_EPIB_SIZE + 517762306a36Sopenharmony_ci CPPI5_INFO0_HDESC_PSDATA_MAX_SIZE, 517862306a36Sopenharmony_ci ud->desc_align); 517962306a36Sopenharmony_ci 518062306a36Sopenharmony_ci hwdesc->cppi5_desc_vaddr = devm_kzalloc(dev, hwdesc->cppi5_desc_size, 518162306a36Sopenharmony_ci GFP_KERNEL); 518262306a36Sopenharmony_ci if (!hwdesc->cppi5_desc_vaddr) 518362306a36Sopenharmony_ci return -ENOMEM; 518462306a36Sopenharmony_ci 518562306a36Sopenharmony_ci hwdesc->cppi5_desc_paddr = dma_map_single(dev, hwdesc->cppi5_desc_vaddr, 518662306a36Sopenharmony_ci hwdesc->cppi5_desc_size, 518762306a36Sopenharmony_ci DMA_TO_DEVICE); 518862306a36Sopenharmony_ci if (dma_mapping_error(dev, hwdesc->cppi5_desc_paddr)) 518962306a36Sopenharmony_ci return -ENOMEM; 519062306a36Sopenharmony_ci 519162306a36Sopenharmony_ci desc = hwdesc->cppi5_desc_vaddr; 519262306a36Sopenharmony_ci cppi5_hdesc_init(desc, 0, 0); 519362306a36Sopenharmony_ci cppi5_desc_set_pktids(&desc->hdr, 0, CPPI5_INFO1_DESC_FLOWID_DEFAULT); 519462306a36Sopenharmony_ci cppi5_desc_set_retpolicy(&desc->hdr, 0, 0); 519562306a36Sopenharmony_ci 519662306a36Sopenharmony_ci cppi5_hdesc_attach_buf(desc, 519762306a36Sopenharmony_ci rx_flush->buffer_paddr, rx_flush->buffer_size, 519862306a36Sopenharmony_ci rx_flush->buffer_paddr, rx_flush->buffer_size); 519962306a36Sopenharmony_ci 520062306a36Sopenharmony_ci dma_sync_single_for_device(dev, hwdesc->cppi5_desc_paddr, 520162306a36Sopenharmony_ci hwdesc->cppi5_desc_size, DMA_TO_DEVICE); 520262306a36Sopenharmony_ci return 0; 520362306a36Sopenharmony_ci} 520462306a36Sopenharmony_ci 520562306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 520662306a36Sopenharmony_cistatic void udma_dbg_summary_show_chan(struct seq_file *s, 520762306a36Sopenharmony_ci struct dma_chan *chan) 520862306a36Sopenharmony_ci{ 520962306a36Sopenharmony_ci struct udma_chan *uc = to_udma_chan(chan); 521062306a36Sopenharmony_ci struct udma_chan_config *ucc = &uc->config; 521162306a36Sopenharmony_ci 521262306a36Sopenharmony_ci seq_printf(s, " %-13s| %s", dma_chan_name(chan), 521362306a36Sopenharmony_ci chan->dbg_client_name ?: "in-use"); 521462306a36Sopenharmony_ci if (ucc->tr_trigger_type) 521562306a36Sopenharmony_ci seq_puts(s, " (triggered, "); 521662306a36Sopenharmony_ci else 521762306a36Sopenharmony_ci seq_printf(s, " (%s, ", 521862306a36Sopenharmony_ci dmaengine_get_direction_text(uc->config.dir)); 521962306a36Sopenharmony_ci 522062306a36Sopenharmony_ci switch (uc->config.dir) { 522162306a36Sopenharmony_ci case DMA_MEM_TO_MEM: 522262306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_BCDMA) { 522362306a36Sopenharmony_ci seq_printf(s, "bchan%d)\n", uc->bchan->id); 522462306a36Sopenharmony_ci return; 522562306a36Sopenharmony_ci } 522662306a36Sopenharmony_ci 522762306a36Sopenharmony_ci seq_printf(s, "chan%d pair [0x%04x -> 0x%04x], ", uc->tchan->id, 522862306a36Sopenharmony_ci ucc->src_thread, ucc->dst_thread); 522962306a36Sopenharmony_ci break; 523062306a36Sopenharmony_ci case DMA_DEV_TO_MEM: 523162306a36Sopenharmony_ci seq_printf(s, "rchan%d [0x%04x -> 0x%04x], ", uc->rchan->id, 523262306a36Sopenharmony_ci ucc->src_thread, ucc->dst_thread); 523362306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_PKTDMA) 523462306a36Sopenharmony_ci seq_printf(s, "rflow%d, ", uc->rflow->id); 523562306a36Sopenharmony_ci break; 523662306a36Sopenharmony_ci case DMA_MEM_TO_DEV: 523762306a36Sopenharmony_ci seq_printf(s, "tchan%d [0x%04x -> 0x%04x], ", uc->tchan->id, 523862306a36Sopenharmony_ci ucc->src_thread, ucc->dst_thread); 523962306a36Sopenharmony_ci if (uc->ud->match_data->type == DMA_TYPE_PKTDMA) 524062306a36Sopenharmony_ci seq_printf(s, "tflow%d, ", uc->tchan->tflow_id); 524162306a36Sopenharmony_ci break; 524262306a36Sopenharmony_ci default: 524362306a36Sopenharmony_ci seq_printf(s, ")\n"); 524462306a36Sopenharmony_ci return; 524562306a36Sopenharmony_ci } 524662306a36Sopenharmony_ci 524762306a36Sopenharmony_ci if (ucc->ep_type == PSIL_EP_NATIVE) { 524862306a36Sopenharmony_ci seq_printf(s, "PSI-L Native"); 524962306a36Sopenharmony_ci if (ucc->metadata_size) { 525062306a36Sopenharmony_ci seq_printf(s, "[%s", ucc->needs_epib ? " EPIB" : ""); 525162306a36Sopenharmony_ci if (ucc->psd_size) 525262306a36Sopenharmony_ci seq_printf(s, " PSDsize:%u", ucc->psd_size); 525362306a36Sopenharmony_ci seq_printf(s, " ]"); 525462306a36Sopenharmony_ci } 525562306a36Sopenharmony_ci } else { 525662306a36Sopenharmony_ci seq_printf(s, "PDMA"); 525762306a36Sopenharmony_ci if (ucc->enable_acc32 || ucc->enable_burst) 525862306a36Sopenharmony_ci seq_printf(s, "[%s%s ]", 525962306a36Sopenharmony_ci ucc->enable_acc32 ? " ACC32" : "", 526062306a36Sopenharmony_ci ucc->enable_burst ? " BURST" : ""); 526162306a36Sopenharmony_ci } 526262306a36Sopenharmony_ci 526362306a36Sopenharmony_ci seq_printf(s, ", %s)\n", ucc->pkt_mode ? "Packet mode" : "TR mode"); 526462306a36Sopenharmony_ci} 526562306a36Sopenharmony_ci 526662306a36Sopenharmony_cistatic void udma_dbg_summary_show(struct seq_file *s, 526762306a36Sopenharmony_ci struct dma_device *dma_dev) 526862306a36Sopenharmony_ci{ 526962306a36Sopenharmony_ci struct dma_chan *chan; 527062306a36Sopenharmony_ci 527162306a36Sopenharmony_ci list_for_each_entry(chan, &dma_dev->channels, device_node) { 527262306a36Sopenharmony_ci if (chan->client_count) 527362306a36Sopenharmony_ci udma_dbg_summary_show_chan(s, chan); 527462306a36Sopenharmony_ci } 527562306a36Sopenharmony_ci} 527662306a36Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 527762306a36Sopenharmony_ci 527862306a36Sopenharmony_cistatic enum dmaengine_alignment udma_get_copy_align(struct udma_dev *ud) 527962306a36Sopenharmony_ci{ 528062306a36Sopenharmony_ci const struct udma_match_data *match_data = ud->match_data; 528162306a36Sopenharmony_ci u8 tpl; 528262306a36Sopenharmony_ci 528362306a36Sopenharmony_ci if (!match_data->enable_memcpy_support) 528462306a36Sopenharmony_ci return DMAENGINE_ALIGN_8_BYTES; 528562306a36Sopenharmony_ci 528662306a36Sopenharmony_ci /* Get the highest TPL level the device supports for memcpy */ 528762306a36Sopenharmony_ci if (ud->bchan_cnt) 528862306a36Sopenharmony_ci tpl = udma_get_chan_tpl_index(&ud->bchan_tpl, 0); 528962306a36Sopenharmony_ci else if (ud->tchan_cnt) 529062306a36Sopenharmony_ci tpl = udma_get_chan_tpl_index(&ud->tchan_tpl, 0); 529162306a36Sopenharmony_ci else 529262306a36Sopenharmony_ci return DMAENGINE_ALIGN_8_BYTES; 529362306a36Sopenharmony_ci 529462306a36Sopenharmony_ci switch (match_data->burst_size[tpl]) { 529562306a36Sopenharmony_ci case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_256_BYTES: 529662306a36Sopenharmony_ci return DMAENGINE_ALIGN_256_BYTES; 529762306a36Sopenharmony_ci case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_128_BYTES: 529862306a36Sopenharmony_ci return DMAENGINE_ALIGN_128_BYTES; 529962306a36Sopenharmony_ci case TI_SCI_RM_UDMAP_CHAN_BURST_SIZE_64_BYTES: 530062306a36Sopenharmony_ci fallthrough; 530162306a36Sopenharmony_ci default: 530262306a36Sopenharmony_ci return DMAENGINE_ALIGN_64_BYTES; 530362306a36Sopenharmony_ci } 530462306a36Sopenharmony_ci} 530562306a36Sopenharmony_ci 530662306a36Sopenharmony_ci#define TI_UDMAC_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ 530762306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ 530862306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ 530962306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \ 531062306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)) 531162306a36Sopenharmony_ci 531262306a36Sopenharmony_cistatic int udma_probe(struct platform_device *pdev) 531362306a36Sopenharmony_ci{ 531462306a36Sopenharmony_ci struct device_node *navss_node = pdev->dev.parent->of_node; 531562306a36Sopenharmony_ci const struct soc_device_attribute *soc; 531662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 531762306a36Sopenharmony_ci struct udma_dev *ud; 531862306a36Sopenharmony_ci const struct of_device_id *match; 531962306a36Sopenharmony_ci int i, ret; 532062306a36Sopenharmony_ci int ch_count; 532162306a36Sopenharmony_ci 532262306a36Sopenharmony_ci ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(48)); 532362306a36Sopenharmony_ci if (ret) 532462306a36Sopenharmony_ci dev_err(dev, "failed to set dma mask stuff\n"); 532562306a36Sopenharmony_ci 532662306a36Sopenharmony_ci ud = devm_kzalloc(dev, sizeof(*ud), GFP_KERNEL); 532762306a36Sopenharmony_ci if (!ud) 532862306a36Sopenharmony_ci return -ENOMEM; 532962306a36Sopenharmony_ci 533062306a36Sopenharmony_ci match = of_match_node(udma_of_match, dev->of_node); 533162306a36Sopenharmony_ci if (!match) { 533262306a36Sopenharmony_ci dev_err(dev, "No compatible match found\n"); 533362306a36Sopenharmony_ci return -ENODEV; 533462306a36Sopenharmony_ci } 533562306a36Sopenharmony_ci ud->match_data = match->data; 533662306a36Sopenharmony_ci 533762306a36Sopenharmony_ci ud->soc_data = ud->match_data->soc_data; 533862306a36Sopenharmony_ci if (!ud->soc_data) { 533962306a36Sopenharmony_ci soc = soc_device_match(k3_soc_devices); 534062306a36Sopenharmony_ci if (!soc) { 534162306a36Sopenharmony_ci dev_err(dev, "No compatible SoC found\n"); 534262306a36Sopenharmony_ci return -ENODEV; 534362306a36Sopenharmony_ci } 534462306a36Sopenharmony_ci ud->soc_data = soc->data; 534562306a36Sopenharmony_ci } 534662306a36Sopenharmony_ci 534762306a36Sopenharmony_ci ret = udma_get_mmrs(pdev, ud); 534862306a36Sopenharmony_ci if (ret) 534962306a36Sopenharmony_ci return ret; 535062306a36Sopenharmony_ci 535162306a36Sopenharmony_ci ud->tisci_rm.tisci = ti_sci_get_by_phandle(dev->of_node, "ti,sci"); 535262306a36Sopenharmony_ci if (IS_ERR(ud->tisci_rm.tisci)) 535362306a36Sopenharmony_ci return PTR_ERR(ud->tisci_rm.tisci); 535462306a36Sopenharmony_ci 535562306a36Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", 535662306a36Sopenharmony_ci &ud->tisci_rm.tisci_dev_id); 535762306a36Sopenharmony_ci if (ret) { 535862306a36Sopenharmony_ci dev_err(dev, "ti,sci-dev-id read failure %d\n", ret); 535962306a36Sopenharmony_ci return ret; 536062306a36Sopenharmony_ci } 536162306a36Sopenharmony_ci pdev->id = ud->tisci_rm.tisci_dev_id; 536262306a36Sopenharmony_ci 536362306a36Sopenharmony_ci ret = of_property_read_u32(navss_node, "ti,sci-dev-id", 536462306a36Sopenharmony_ci &ud->tisci_rm.tisci_navss_dev_id); 536562306a36Sopenharmony_ci if (ret) { 536662306a36Sopenharmony_ci dev_err(dev, "NAVSS ti,sci-dev-id read failure %d\n", ret); 536762306a36Sopenharmony_ci return ret; 536862306a36Sopenharmony_ci } 536962306a36Sopenharmony_ci 537062306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_UDMA) { 537162306a36Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "ti,udma-atype", 537262306a36Sopenharmony_ci &ud->atype); 537362306a36Sopenharmony_ci if (!ret && ud->atype > 2) { 537462306a36Sopenharmony_ci dev_err(dev, "Invalid atype: %u\n", ud->atype); 537562306a36Sopenharmony_ci return -EINVAL; 537662306a36Sopenharmony_ci } 537762306a36Sopenharmony_ci } else { 537862306a36Sopenharmony_ci ret = of_property_read_u32(dev->of_node, "ti,asel", 537962306a36Sopenharmony_ci &ud->asel); 538062306a36Sopenharmony_ci if (!ret && ud->asel > 15) { 538162306a36Sopenharmony_ci dev_err(dev, "Invalid asel: %u\n", ud->asel); 538262306a36Sopenharmony_ci return -EINVAL; 538362306a36Sopenharmony_ci } 538462306a36Sopenharmony_ci } 538562306a36Sopenharmony_ci 538662306a36Sopenharmony_ci ud->tisci_rm.tisci_udmap_ops = &ud->tisci_rm.tisci->ops.rm_udmap_ops; 538762306a36Sopenharmony_ci ud->tisci_rm.tisci_psil_ops = &ud->tisci_rm.tisci->ops.rm_psil_ops; 538862306a36Sopenharmony_ci 538962306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_UDMA) { 539062306a36Sopenharmony_ci ud->ringacc = of_k3_ringacc_get_by_phandle(dev->of_node, "ti,ringacc"); 539162306a36Sopenharmony_ci } else { 539262306a36Sopenharmony_ci struct k3_ringacc_init_data ring_init_data; 539362306a36Sopenharmony_ci 539462306a36Sopenharmony_ci ring_init_data.tisci = ud->tisci_rm.tisci; 539562306a36Sopenharmony_ci ring_init_data.tisci_dev_id = ud->tisci_rm.tisci_dev_id; 539662306a36Sopenharmony_ci if (ud->match_data->type == DMA_TYPE_BCDMA) { 539762306a36Sopenharmony_ci ring_init_data.num_rings = ud->bchan_cnt + 539862306a36Sopenharmony_ci ud->tchan_cnt + 539962306a36Sopenharmony_ci ud->rchan_cnt; 540062306a36Sopenharmony_ci } else { 540162306a36Sopenharmony_ci ring_init_data.num_rings = ud->rflow_cnt + 540262306a36Sopenharmony_ci ud->tflow_cnt; 540362306a36Sopenharmony_ci } 540462306a36Sopenharmony_ci 540562306a36Sopenharmony_ci ud->ringacc = k3_ringacc_dmarings_init(pdev, &ring_init_data); 540662306a36Sopenharmony_ci } 540762306a36Sopenharmony_ci 540862306a36Sopenharmony_ci if (IS_ERR(ud->ringacc)) 540962306a36Sopenharmony_ci return PTR_ERR(ud->ringacc); 541062306a36Sopenharmony_ci 541162306a36Sopenharmony_ci dev->msi.domain = of_msi_get_domain(dev, dev->of_node, 541262306a36Sopenharmony_ci DOMAIN_BUS_TI_SCI_INTA_MSI); 541362306a36Sopenharmony_ci if (!dev->msi.domain) { 541462306a36Sopenharmony_ci return -EPROBE_DEFER; 541562306a36Sopenharmony_ci } 541662306a36Sopenharmony_ci 541762306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, ud->ddev.cap_mask); 541862306a36Sopenharmony_ci /* cyclic operation is not supported via PKTDMA */ 541962306a36Sopenharmony_ci if (ud->match_data->type != DMA_TYPE_PKTDMA) { 542062306a36Sopenharmony_ci dma_cap_set(DMA_CYCLIC, ud->ddev.cap_mask); 542162306a36Sopenharmony_ci ud->ddev.device_prep_dma_cyclic = udma_prep_dma_cyclic; 542262306a36Sopenharmony_ci } 542362306a36Sopenharmony_ci 542462306a36Sopenharmony_ci ud->ddev.device_config = udma_slave_config; 542562306a36Sopenharmony_ci ud->ddev.device_prep_slave_sg = udma_prep_slave_sg; 542662306a36Sopenharmony_ci ud->ddev.device_issue_pending = udma_issue_pending; 542762306a36Sopenharmony_ci ud->ddev.device_tx_status = udma_tx_status; 542862306a36Sopenharmony_ci ud->ddev.device_pause = udma_pause; 542962306a36Sopenharmony_ci ud->ddev.device_resume = udma_resume; 543062306a36Sopenharmony_ci ud->ddev.device_terminate_all = udma_terminate_all; 543162306a36Sopenharmony_ci ud->ddev.device_synchronize = udma_synchronize; 543262306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 543362306a36Sopenharmony_ci ud->ddev.dbg_summary_show = udma_dbg_summary_show; 543462306a36Sopenharmony_ci#endif 543562306a36Sopenharmony_ci 543662306a36Sopenharmony_ci switch (ud->match_data->type) { 543762306a36Sopenharmony_ci case DMA_TYPE_UDMA: 543862306a36Sopenharmony_ci ud->ddev.device_alloc_chan_resources = 543962306a36Sopenharmony_ci udma_alloc_chan_resources; 544062306a36Sopenharmony_ci break; 544162306a36Sopenharmony_ci case DMA_TYPE_BCDMA: 544262306a36Sopenharmony_ci ud->ddev.device_alloc_chan_resources = 544362306a36Sopenharmony_ci bcdma_alloc_chan_resources; 544462306a36Sopenharmony_ci ud->ddev.device_router_config = bcdma_router_config; 544562306a36Sopenharmony_ci break; 544662306a36Sopenharmony_ci case DMA_TYPE_PKTDMA: 544762306a36Sopenharmony_ci ud->ddev.device_alloc_chan_resources = 544862306a36Sopenharmony_ci pktdma_alloc_chan_resources; 544962306a36Sopenharmony_ci break; 545062306a36Sopenharmony_ci default: 545162306a36Sopenharmony_ci return -EINVAL; 545262306a36Sopenharmony_ci } 545362306a36Sopenharmony_ci ud->ddev.device_free_chan_resources = udma_free_chan_resources; 545462306a36Sopenharmony_ci 545562306a36Sopenharmony_ci ud->ddev.src_addr_widths = TI_UDMAC_BUSWIDTHS; 545662306a36Sopenharmony_ci ud->ddev.dst_addr_widths = TI_UDMAC_BUSWIDTHS; 545762306a36Sopenharmony_ci ud->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 545862306a36Sopenharmony_ci ud->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 545962306a36Sopenharmony_ci ud->ddev.desc_metadata_modes = DESC_METADATA_CLIENT | 546062306a36Sopenharmony_ci DESC_METADATA_ENGINE; 546162306a36Sopenharmony_ci if (ud->match_data->enable_memcpy_support && 546262306a36Sopenharmony_ci !(ud->match_data->type == DMA_TYPE_BCDMA && ud->bchan_cnt == 0)) { 546362306a36Sopenharmony_ci dma_cap_set(DMA_MEMCPY, ud->ddev.cap_mask); 546462306a36Sopenharmony_ci ud->ddev.device_prep_dma_memcpy = udma_prep_dma_memcpy; 546562306a36Sopenharmony_ci ud->ddev.directions |= BIT(DMA_MEM_TO_MEM); 546662306a36Sopenharmony_ci } 546762306a36Sopenharmony_ci 546862306a36Sopenharmony_ci ud->ddev.dev = dev; 546962306a36Sopenharmony_ci ud->dev = dev; 547062306a36Sopenharmony_ci ud->psil_base = ud->match_data->psil_base; 547162306a36Sopenharmony_ci 547262306a36Sopenharmony_ci INIT_LIST_HEAD(&ud->ddev.channels); 547362306a36Sopenharmony_ci INIT_LIST_HEAD(&ud->desc_to_purge); 547462306a36Sopenharmony_ci 547562306a36Sopenharmony_ci ch_count = setup_resources(ud); 547662306a36Sopenharmony_ci if (ch_count <= 0) 547762306a36Sopenharmony_ci return ch_count; 547862306a36Sopenharmony_ci 547962306a36Sopenharmony_ci spin_lock_init(&ud->lock); 548062306a36Sopenharmony_ci INIT_WORK(&ud->purge_work, udma_purge_desc_work); 548162306a36Sopenharmony_ci 548262306a36Sopenharmony_ci ud->desc_align = 64; 548362306a36Sopenharmony_ci if (ud->desc_align < dma_get_cache_alignment()) 548462306a36Sopenharmony_ci ud->desc_align = dma_get_cache_alignment(); 548562306a36Sopenharmony_ci 548662306a36Sopenharmony_ci ret = udma_setup_rx_flush(ud); 548762306a36Sopenharmony_ci if (ret) 548862306a36Sopenharmony_ci return ret; 548962306a36Sopenharmony_ci 549062306a36Sopenharmony_ci for (i = 0; i < ud->bchan_cnt; i++) { 549162306a36Sopenharmony_ci struct udma_bchan *bchan = &ud->bchans[i]; 549262306a36Sopenharmony_ci 549362306a36Sopenharmony_ci bchan->id = i; 549462306a36Sopenharmony_ci bchan->reg_rt = ud->mmrs[MMR_BCHANRT] + i * 0x1000; 549562306a36Sopenharmony_ci } 549662306a36Sopenharmony_ci 549762306a36Sopenharmony_ci for (i = 0; i < ud->tchan_cnt; i++) { 549862306a36Sopenharmony_ci struct udma_tchan *tchan = &ud->tchans[i]; 549962306a36Sopenharmony_ci 550062306a36Sopenharmony_ci tchan->id = i; 550162306a36Sopenharmony_ci tchan->reg_rt = ud->mmrs[MMR_TCHANRT] + i * 0x1000; 550262306a36Sopenharmony_ci } 550362306a36Sopenharmony_ci 550462306a36Sopenharmony_ci for (i = 0; i < ud->rchan_cnt; i++) { 550562306a36Sopenharmony_ci struct udma_rchan *rchan = &ud->rchans[i]; 550662306a36Sopenharmony_ci 550762306a36Sopenharmony_ci rchan->id = i; 550862306a36Sopenharmony_ci rchan->reg_rt = ud->mmrs[MMR_RCHANRT] + i * 0x1000; 550962306a36Sopenharmony_ci } 551062306a36Sopenharmony_ci 551162306a36Sopenharmony_ci for (i = 0; i < ud->rflow_cnt; i++) { 551262306a36Sopenharmony_ci struct udma_rflow *rflow = &ud->rflows[i]; 551362306a36Sopenharmony_ci 551462306a36Sopenharmony_ci rflow->id = i; 551562306a36Sopenharmony_ci } 551662306a36Sopenharmony_ci 551762306a36Sopenharmony_ci for (i = 0; i < ch_count; i++) { 551862306a36Sopenharmony_ci struct udma_chan *uc = &ud->channels[i]; 551962306a36Sopenharmony_ci 552062306a36Sopenharmony_ci uc->ud = ud; 552162306a36Sopenharmony_ci uc->vc.desc_free = udma_desc_free; 552262306a36Sopenharmony_ci uc->id = i; 552362306a36Sopenharmony_ci uc->bchan = NULL; 552462306a36Sopenharmony_ci uc->tchan = NULL; 552562306a36Sopenharmony_ci uc->rchan = NULL; 552662306a36Sopenharmony_ci uc->config.remote_thread_id = -1; 552762306a36Sopenharmony_ci uc->config.mapped_channel_id = -1; 552862306a36Sopenharmony_ci uc->config.default_flow_id = -1; 552962306a36Sopenharmony_ci uc->config.dir = DMA_MEM_TO_MEM; 553062306a36Sopenharmony_ci uc->name = devm_kasprintf(dev, GFP_KERNEL, "%s chan%d", 553162306a36Sopenharmony_ci dev_name(dev), i); 553262306a36Sopenharmony_ci 553362306a36Sopenharmony_ci vchan_init(&uc->vc, &ud->ddev); 553462306a36Sopenharmony_ci /* Use custom vchan completion handling */ 553562306a36Sopenharmony_ci tasklet_setup(&uc->vc.task, udma_vchan_complete); 553662306a36Sopenharmony_ci init_completion(&uc->teardown_completed); 553762306a36Sopenharmony_ci INIT_DELAYED_WORK(&uc->tx_drain.work, udma_check_tx_completion); 553862306a36Sopenharmony_ci } 553962306a36Sopenharmony_ci 554062306a36Sopenharmony_ci /* Configure the copy_align to the maximum burst size the device supports */ 554162306a36Sopenharmony_ci ud->ddev.copy_align = udma_get_copy_align(ud); 554262306a36Sopenharmony_ci 554362306a36Sopenharmony_ci ret = dma_async_device_register(&ud->ddev); 554462306a36Sopenharmony_ci if (ret) { 554562306a36Sopenharmony_ci dev_err(dev, "failed to register slave DMA engine: %d\n", ret); 554662306a36Sopenharmony_ci return ret; 554762306a36Sopenharmony_ci } 554862306a36Sopenharmony_ci 554962306a36Sopenharmony_ci platform_set_drvdata(pdev, ud); 555062306a36Sopenharmony_ci 555162306a36Sopenharmony_ci ret = of_dma_controller_register(dev->of_node, udma_of_xlate, ud); 555262306a36Sopenharmony_ci if (ret) { 555362306a36Sopenharmony_ci dev_err(dev, "failed to register of_dma controller\n"); 555462306a36Sopenharmony_ci dma_async_device_unregister(&ud->ddev); 555562306a36Sopenharmony_ci } 555662306a36Sopenharmony_ci 555762306a36Sopenharmony_ci return ret; 555862306a36Sopenharmony_ci} 555962306a36Sopenharmony_ci 556062306a36Sopenharmony_cistatic int __maybe_unused udma_pm_suspend(struct device *dev) 556162306a36Sopenharmony_ci{ 556262306a36Sopenharmony_ci struct udma_dev *ud = dev_get_drvdata(dev); 556362306a36Sopenharmony_ci struct dma_device *dma_dev = &ud->ddev; 556462306a36Sopenharmony_ci struct dma_chan *chan; 556562306a36Sopenharmony_ci struct udma_chan *uc; 556662306a36Sopenharmony_ci 556762306a36Sopenharmony_ci list_for_each_entry(chan, &dma_dev->channels, device_node) { 556862306a36Sopenharmony_ci if (chan->client_count) { 556962306a36Sopenharmony_ci uc = to_udma_chan(chan); 557062306a36Sopenharmony_ci /* backup the channel configuration */ 557162306a36Sopenharmony_ci memcpy(&uc->backup_config, &uc->config, 557262306a36Sopenharmony_ci sizeof(struct udma_chan_config)); 557362306a36Sopenharmony_ci dev_dbg(dev, "Suspending channel %s\n", 557462306a36Sopenharmony_ci dma_chan_name(chan)); 557562306a36Sopenharmony_ci ud->ddev.device_free_chan_resources(chan); 557662306a36Sopenharmony_ci } 557762306a36Sopenharmony_ci } 557862306a36Sopenharmony_ci 557962306a36Sopenharmony_ci return 0; 558062306a36Sopenharmony_ci} 558162306a36Sopenharmony_ci 558262306a36Sopenharmony_cistatic int __maybe_unused udma_pm_resume(struct device *dev) 558362306a36Sopenharmony_ci{ 558462306a36Sopenharmony_ci struct udma_dev *ud = dev_get_drvdata(dev); 558562306a36Sopenharmony_ci struct dma_device *dma_dev = &ud->ddev; 558662306a36Sopenharmony_ci struct dma_chan *chan; 558762306a36Sopenharmony_ci struct udma_chan *uc; 558862306a36Sopenharmony_ci int ret; 558962306a36Sopenharmony_ci 559062306a36Sopenharmony_ci list_for_each_entry(chan, &dma_dev->channels, device_node) { 559162306a36Sopenharmony_ci if (chan->client_count) { 559262306a36Sopenharmony_ci uc = to_udma_chan(chan); 559362306a36Sopenharmony_ci /* restore the channel configuration */ 559462306a36Sopenharmony_ci memcpy(&uc->config, &uc->backup_config, 559562306a36Sopenharmony_ci sizeof(struct udma_chan_config)); 559662306a36Sopenharmony_ci dev_dbg(dev, "Resuming channel %s\n", 559762306a36Sopenharmony_ci dma_chan_name(chan)); 559862306a36Sopenharmony_ci ret = ud->ddev.device_alloc_chan_resources(chan); 559962306a36Sopenharmony_ci if (ret) 560062306a36Sopenharmony_ci return ret; 560162306a36Sopenharmony_ci } 560262306a36Sopenharmony_ci } 560362306a36Sopenharmony_ci 560462306a36Sopenharmony_ci return 0; 560562306a36Sopenharmony_ci} 560662306a36Sopenharmony_ci 560762306a36Sopenharmony_cistatic const struct dev_pm_ops udma_pm_ops = { 560862306a36Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(udma_pm_suspend, udma_pm_resume) 560962306a36Sopenharmony_ci}; 561062306a36Sopenharmony_ci 561162306a36Sopenharmony_cistatic struct platform_driver udma_driver = { 561262306a36Sopenharmony_ci .driver = { 561362306a36Sopenharmony_ci .name = "ti-udma", 561462306a36Sopenharmony_ci .of_match_table = udma_of_match, 561562306a36Sopenharmony_ci .suppress_bind_attrs = true, 561662306a36Sopenharmony_ci .pm = &udma_pm_ops, 561762306a36Sopenharmony_ci }, 561862306a36Sopenharmony_ci .probe = udma_probe, 561962306a36Sopenharmony_ci}; 562062306a36Sopenharmony_ci 562162306a36Sopenharmony_cimodule_platform_driver(udma_driver); 562262306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 562362306a36Sopenharmony_ci 562462306a36Sopenharmony_ci/* Private interfaces to UDMA */ 562562306a36Sopenharmony_ci#include "k3-udma-private.c" 5626