162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Lightning Mountain centralized DMA controller driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2016 - 2020 Intel Corporation. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/bitfield.h> 962306a36Sopenharmony_ci#include <linux/clk.h> 1062306a36Sopenharmony_ci#include <linux/dma-mapping.h> 1162306a36Sopenharmony_ci#include <linux/dmapool.h> 1262306a36Sopenharmony_ci#include <linux/err.h> 1362306a36Sopenharmony_ci#include <linux/export.h> 1462306a36Sopenharmony_ci#include <linux/init.h> 1562306a36Sopenharmony_ci#include <linux/interrupt.h> 1662306a36Sopenharmony_ci#include <linux/iopoll.h> 1762306a36Sopenharmony_ci#include <linux/of_dma.h> 1862306a36Sopenharmony_ci#include <linux/of_irq.h> 1962306a36Sopenharmony_ci#include <linux/platform_device.h> 2062306a36Sopenharmony_ci#include <linux/reset.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include "../dmaengine.h" 2362306a36Sopenharmony_ci#include "../virt-dma.h" 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#define DRIVER_NAME "lgm-dma" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#define DMA_ID 0x0008 2862306a36Sopenharmony_ci#define DMA_ID_REV GENMASK(7, 0) 2962306a36Sopenharmony_ci#define DMA_ID_PNR GENMASK(19, 16) 3062306a36Sopenharmony_ci#define DMA_ID_CHNR GENMASK(26, 20) 3162306a36Sopenharmony_ci#define DMA_ID_DW_128B BIT(27) 3262306a36Sopenharmony_ci#define DMA_ID_AW_36B BIT(28) 3362306a36Sopenharmony_ci#define DMA_VER32 0x32 3462306a36Sopenharmony_ci#define DMA_VER31 0x31 3562306a36Sopenharmony_ci#define DMA_VER22 0x0A 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#define DMA_CTRL 0x0010 3862306a36Sopenharmony_ci#define DMA_CTRL_RST BIT(0) 3962306a36Sopenharmony_ci#define DMA_CTRL_DSRAM_PATH BIT(1) 4062306a36Sopenharmony_ci#define DMA_CTRL_DBURST_WR BIT(3) 4162306a36Sopenharmony_ci#define DMA_CTRL_VLD_DF_ACK BIT(4) 4262306a36Sopenharmony_ci#define DMA_CTRL_CH_FL BIT(6) 4362306a36Sopenharmony_ci#define DMA_CTRL_DS_FOD BIT(7) 4462306a36Sopenharmony_ci#define DMA_CTRL_DRB BIT(8) 4562306a36Sopenharmony_ci#define DMA_CTRL_ENBE BIT(9) 4662306a36Sopenharmony_ci#define DMA_CTRL_DESC_TMOUT_CNT_V31 GENMASK(27, 16) 4762306a36Sopenharmony_ci#define DMA_CTRL_DESC_TMOUT_EN_V31 BIT(30) 4862306a36Sopenharmony_ci#define DMA_CTRL_PKTARB BIT(31) 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci#define DMA_CPOLL 0x0014 5162306a36Sopenharmony_ci#define DMA_CPOLL_CNT GENMASK(15, 4) 5262306a36Sopenharmony_ci#define DMA_CPOLL_EN BIT(31) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define DMA_CS 0x0018 5562306a36Sopenharmony_ci#define DMA_CS_MASK GENMASK(5, 0) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define DMA_CCTRL 0x001C 5862306a36Sopenharmony_ci#define DMA_CCTRL_ON BIT(0) 5962306a36Sopenharmony_ci#define DMA_CCTRL_RST BIT(1) 6062306a36Sopenharmony_ci#define DMA_CCTRL_CH_POLL_EN BIT(2) 6162306a36Sopenharmony_ci#define DMA_CCTRL_CH_ABC BIT(3) /* Adaptive Burst Chop */ 6262306a36Sopenharmony_ci#define DMA_CDBA_MSB GENMASK(7, 4) 6362306a36Sopenharmony_ci#define DMA_CCTRL_DIR_TX BIT(8) 6462306a36Sopenharmony_ci#define DMA_CCTRL_CLASS GENMASK(11, 9) 6562306a36Sopenharmony_ci#define DMA_CCTRL_CLASSH GENMASK(19, 18) 6662306a36Sopenharmony_ci#define DMA_CCTRL_WR_NP_EN BIT(21) 6762306a36Sopenharmony_ci#define DMA_CCTRL_PDEN BIT(23) 6862306a36Sopenharmony_ci#define DMA_MAX_CLASS (SZ_32 - 1) 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci#define DMA_CDBA 0x0020 7162306a36Sopenharmony_ci#define DMA_CDLEN 0x0024 7262306a36Sopenharmony_ci#define DMA_CIS 0x0028 7362306a36Sopenharmony_ci#define DMA_CIE 0x002C 7462306a36Sopenharmony_ci#define DMA_CI_EOP BIT(1) 7562306a36Sopenharmony_ci#define DMA_CI_DUR BIT(2) 7662306a36Sopenharmony_ci#define DMA_CI_DESCPT BIT(3) 7762306a36Sopenharmony_ci#define DMA_CI_CHOFF BIT(4) 7862306a36Sopenharmony_ci#define DMA_CI_RDERR BIT(5) 7962306a36Sopenharmony_ci#define DMA_CI_ALL \ 8062306a36Sopenharmony_ci (DMA_CI_EOP | DMA_CI_DUR | DMA_CI_DESCPT | DMA_CI_CHOFF | DMA_CI_RDERR) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci#define DMA_PS 0x0040 8362306a36Sopenharmony_ci#define DMA_PCTRL 0x0044 8462306a36Sopenharmony_ci#define DMA_PCTRL_RXBL16 BIT(0) 8562306a36Sopenharmony_ci#define DMA_PCTRL_TXBL16 BIT(1) 8662306a36Sopenharmony_ci#define DMA_PCTRL_RXBL GENMASK(3, 2) 8762306a36Sopenharmony_ci#define DMA_PCTRL_RXBL_8 3 8862306a36Sopenharmony_ci#define DMA_PCTRL_TXBL GENMASK(5, 4) 8962306a36Sopenharmony_ci#define DMA_PCTRL_TXBL_8 3 9062306a36Sopenharmony_ci#define DMA_PCTRL_PDEN BIT(6) 9162306a36Sopenharmony_ci#define DMA_PCTRL_RXBL32 BIT(7) 9262306a36Sopenharmony_ci#define DMA_PCTRL_RXENDI GENMASK(9, 8) 9362306a36Sopenharmony_ci#define DMA_PCTRL_TXENDI GENMASK(11, 10) 9462306a36Sopenharmony_ci#define DMA_PCTRL_TXBL32 BIT(15) 9562306a36Sopenharmony_ci#define DMA_PCTRL_MEM_FLUSH BIT(16) 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci#define DMA_IRNEN1 0x00E8 9862306a36Sopenharmony_ci#define DMA_IRNCR1 0x00EC 9962306a36Sopenharmony_ci#define DMA_IRNEN 0x00F4 10062306a36Sopenharmony_ci#define DMA_IRNCR 0x00F8 10162306a36Sopenharmony_ci#define DMA_C_DP_TICK 0x100 10262306a36Sopenharmony_ci#define DMA_C_DP_TICK_TIKNARB GENMASK(15, 0) 10362306a36Sopenharmony_ci#define DMA_C_DP_TICK_TIKARB GENMASK(31, 16) 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci#define DMA_C_HDRM 0x110 10662306a36Sopenharmony_ci/* 10762306a36Sopenharmony_ci * If header mode is set in DMA descriptor, 10862306a36Sopenharmony_ci * If bit 30 is disabled, HDR_LEN must be configured according to channel 10962306a36Sopenharmony_ci * requirement. 11062306a36Sopenharmony_ci * If bit 30 is enabled(checksum with heade mode), HDR_LEN has no need to 11162306a36Sopenharmony_ci * be configured. It will enable check sum for switch 11262306a36Sopenharmony_ci * If header mode is not set in DMA descriptor, 11362306a36Sopenharmony_ci * This register setting doesn't matter 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci#define DMA_C_HDRM_HDR_SUM BIT(30) 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci#define DMA_C_BOFF 0x120 11862306a36Sopenharmony_ci#define DMA_C_BOFF_BOF_LEN GENMASK(7, 0) 11962306a36Sopenharmony_ci#define DMA_C_BOFF_EN BIT(31) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#define DMA_ORRC 0x190 12262306a36Sopenharmony_ci#define DMA_ORRC_ORRCNT GENMASK(8, 4) 12362306a36Sopenharmony_ci#define DMA_ORRC_EN BIT(31) 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci#define DMA_C_ENDIAN 0x200 12662306a36Sopenharmony_ci#define DMA_C_END_DATAENDI GENMASK(1, 0) 12762306a36Sopenharmony_ci#define DMA_C_END_DE_EN BIT(7) 12862306a36Sopenharmony_ci#define DMA_C_END_DESENDI GENMASK(9, 8) 12962306a36Sopenharmony_ci#define DMA_C_END_DES_EN BIT(16) 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci/* DMA controller capability */ 13262306a36Sopenharmony_ci#define DMA_ADDR_36BIT BIT(0) 13362306a36Sopenharmony_ci#define DMA_DATA_128BIT BIT(1) 13462306a36Sopenharmony_ci#define DMA_CHAN_FLOW_CTL BIT(2) 13562306a36Sopenharmony_ci#define DMA_DESC_FOD BIT(3) 13662306a36Sopenharmony_ci#define DMA_DESC_IN_SRAM BIT(4) 13762306a36Sopenharmony_ci#define DMA_EN_BYTE_EN BIT(5) 13862306a36Sopenharmony_ci#define DMA_DBURST_WR BIT(6) 13962306a36Sopenharmony_ci#define DMA_VALID_DESC_FETCH_ACK BIT(7) 14062306a36Sopenharmony_ci#define DMA_DFT_DRB BIT(8) 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci#define DMA_ORRC_MAX_CNT (SZ_32 - 1) 14362306a36Sopenharmony_ci#define DMA_DFT_POLL_CNT SZ_4 14462306a36Sopenharmony_ci#define DMA_DFT_BURST_V22 SZ_2 14562306a36Sopenharmony_ci#define DMA_BURSTL_8DW SZ_8 14662306a36Sopenharmony_ci#define DMA_BURSTL_16DW SZ_16 14762306a36Sopenharmony_ci#define DMA_BURSTL_32DW SZ_32 14862306a36Sopenharmony_ci#define DMA_DFT_BURST DMA_BURSTL_16DW 14962306a36Sopenharmony_ci#define DMA_MAX_DESC_NUM (SZ_8K - 1) 15062306a36Sopenharmony_ci#define DMA_CHAN_BOFF_MAX (SZ_256 - 1) 15162306a36Sopenharmony_ci#define DMA_DFT_ENDIAN 0 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci#define DMA_DFT_DESC_TCNT 50 15462306a36Sopenharmony_ci#define DMA_HDR_LEN_MAX (SZ_16K - 1) 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci/* DMA flags */ 15762306a36Sopenharmony_ci#define DMA_TX_CH BIT(0) 15862306a36Sopenharmony_ci#define DMA_RX_CH BIT(1) 15962306a36Sopenharmony_ci#define DEVICE_ALLOC_DESC BIT(2) 16062306a36Sopenharmony_ci#define CHAN_IN_USE BIT(3) 16162306a36Sopenharmony_ci#define DMA_HW_DESC BIT(4) 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci/* Descriptor fields */ 16462306a36Sopenharmony_ci#define DESC_DATA_LEN GENMASK(15, 0) 16562306a36Sopenharmony_ci#define DESC_BYTE_OFF GENMASK(25, 23) 16662306a36Sopenharmony_ci#define DESC_EOP BIT(28) 16762306a36Sopenharmony_ci#define DESC_SOP BIT(29) 16862306a36Sopenharmony_ci#define DESC_C BIT(30) 16962306a36Sopenharmony_ci#define DESC_OWN BIT(31) 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci#define DMA_CHAN_RST 1 17262306a36Sopenharmony_ci#define DMA_MAX_SIZE (BIT(16) - 1) 17362306a36Sopenharmony_ci#define MAX_LOWER_CHANS 32 17462306a36Sopenharmony_ci#define MASK_LOWER_CHANS GENMASK(4, 0) 17562306a36Sopenharmony_ci#define DMA_OWN 1 17662306a36Sopenharmony_ci#define HIGH_4_BITS GENMASK(3, 0) 17762306a36Sopenharmony_ci#define DMA_DFT_DESC_NUM 1 17862306a36Sopenharmony_ci#define DMA_PKT_DROP_DIS 0 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cienum ldma_chan_on_off { 18162306a36Sopenharmony_ci DMA_CH_OFF = 0, 18262306a36Sopenharmony_ci DMA_CH_ON = 1, 18362306a36Sopenharmony_ci}; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_cienum { 18662306a36Sopenharmony_ci DMA_TYPE_TX = 0, 18762306a36Sopenharmony_ci DMA_TYPE_RX, 18862306a36Sopenharmony_ci DMA_TYPE_MCPY, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistruct ldma_dev; 19262306a36Sopenharmony_cistruct ldma_port; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_cistruct ldma_chan { 19562306a36Sopenharmony_ci struct virt_dma_chan vchan; 19662306a36Sopenharmony_ci struct ldma_port *port; /* back pointer */ 19762306a36Sopenharmony_ci char name[8]; /* Channel name */ 19862306a36Sopenharmony_ci int nr; /* Channel id in hardware */ 19962306a36Sopenharmony_ci u32 flags; /* central way or channel based way */ 20062306a36Sopenharmony_ci enum ldma_chan_on_off onoff; 20162306a36Sopenharmony_ci dma_addr_t desc_phys; 20262306a36Sopenharmony_ci void *desc_base; /* Virtual address */ 20362306a36Sopenharmony_ci u32 desc_cnt; /* Number of descriptors */ 20462306a36Sopenharmony_ci int rst; 20562306a36Sopenharmony_ci u32 hdrm_len; 20662306a36Sopenharmony_ci bool hdrm_csum; 20762306a36Sopenharmony_ci u32 boff_len; 20862306a36Sopenharmony_ci u32 data_endian; 20962306a36Sopenharmony_ci u32 desc_endian; 21062306a36Sopenharmony_ci bool pden; 21162306a36Sopenharmony_ci bool desc_rx_np; 21262306a36Sopenharmony_ci bool data_endian_en; 21362306a36Sopenharmony_ci bool desc_endian_en; 21462306a36Sopenharmony_ci bool abc_en; 21562306a36Sopenharmony_ci bool desc_init; 21662306a36Sopenharmony_ci struct dma_pool *desc_pool; /* Descriptors pool */ 21762306a36Sopenharmony_ci u32 desc_num; 21862306a36Sopenharmony_ci struct dw2_desc_sw *ds; 21962306a36Sopenharmony_ci struct work_struct work; 22062306a36Sopenharmony_ci struct dma_slave_config config; 22162306a36Sopenharmony_ci}; 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistruct ldma_port { 22462306a36Sopenharmony_ci struct ldma_dev *ldev; /* back pointer */ 22562306a36Sopenharmony_ci u32 portid; 22662306a36Sopenharmony_ci u32 rxbl; 22762306a36Sopenharmony_ci u32 txbl; 22862306a36Sopenharmony_ci u32 rxendi; 22962306a36Sopenharmony_ci u32 txendi; 23062306a36Sopenharmony_ci u32 pkt_drop; 23162306a36Sopenharmony_ci}; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci/* Instance specific data */ 23462306a36Sopenharmony_cistruct ldma_inst_data { 23562306a36Sopenharmony_ci bool desc_in_sram; 23662306a36Sopenharmony_ci bool chan_fc; 23762306a36Sopenharmony_ci bool desc_fod; /* Fetch On Demand */ 23862306a36Sopenharmony_ci bool valid_desc_fetch_ack; 23962306a36Sopenharmony_ci u32 orrc; /* Outstanding read count */ 24062306a36Sopenharmony_ci const char *name; 24162306a36Sopenharmony_ci u32 type; 24262306a36Sopenharmony_ci}; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistruct ldma_dev { 24562306a36Sopenharmony_ci struct device *dev; 24662306a36Sopenharmony_ci void __iomem *base; 24762306a36Sopenharmony_ci struct reset_control *rst; 24862306a36Sopenharmony_ci struct clk *core_clk; 24962306a36Sopenharmony_ci struct dma_device dma_dev; 25062306a36Sopenharmony_ci u32 ver; 25162306a36Sopenharmony_ci int irq; 25262306a36Sopenharmony_ci struct ldma_port *ports; 25362306a36Sopenharmony_ci struct ldma_chan *chans; /* channel list on this DMA or port */ 25462306a36Sopenharmony_ci spinlock_t dev_lock; /* Controller register exclusive */ 25562306a36Sopenharmony_ci u32 chan_nrs; 25662306a36Sopenharmony_ci u32 port_nrs; 25762306a36Sopenharmony_ci u32 channels_mask; 25862306a36Sopenharmony_ci u32 flags; 25962306a36Sopenharmony_ci u32 pollcnt; 26062306a36Sopenharmony_ci const struct ldma_inst_data *inst; 26162306a36Sopenharmony_ci struct workqueue_struct *wq; 26262306a36Sopenharmony_ci}; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistruct dw2_desc { 26562306a36Sopenharmony_ci u32 field; 26662306a36Sopenharmony_ci u32 addr; 26762306a36Sopenharmony_ci} __packed __aligned(8); 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistruct dw2_desc_sw { 27062306a36Sopenharmony_ci struct virt_dma_desc vdesc; 27162306a36Sopenharmony_ci struct ldma_chan *chan; 27262306a36Sopenharmony_ci dma_addr_t desc_phys; 27362306a36Sopenharmony_ci size_t desc_cnt; 27462306a36Sopenharmony_ci size_t size; 27562306a36Sopenharmony_ci struct dw2_desc *desc_hw; 27662306a36Sopenharmony_ci}; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic inline void 27962306a36Sopenharmony_cildma_update_bits(struct ldma_dev *d, u32 mask, u32 val, u32 ofs) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci u32 old_val, new_val; 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci old_val = readl(d->base + ofs); 28462306a36Sopenharmony_ci new_val = (old_val & ~mask) | (val & mask); 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci if (new_val != old_val) 28762306a36Sopenharmony_ci writel(new_val, d->base + ofs); 28862306a36Sopenharmony_ci} 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_cistatic inline struct ldma_chan *to_ldma_chan(struct dma_chan *chan) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci return container_of(chan, struct ldma_chan, vchan.chan); 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_cistatic inline struct ldma_dev *to_ldma_dev(struct dma_device *dma_dev) 29662306a36Sopenharmony_ci{ 29762306a36Sopenharmony_ci return container_of(dma_dev, struct ldma_dev, dma_dev); 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic inline struct dw2_desc_sw *to_lgm_dma_desc(struct virt_dma_desc *vdesc) 30162306a36Sopenharmony_ci{ 30262306a36Sopenharmony_ci return container_of(vdesc, struct dw2_desc_sw, vdesc); 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_cistatic inline bool ldma_chan_tx(struct ldma_chan *c) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci return !!(c->flags & DMA_TX_CH); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cistatic inline bool ldma_chan_is_hw_desc(struct ldma_chan *c) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci return !!(c->flags & DMA_HW_DESC); 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic void ldma_dev_reset(struct ldma_dev *d) 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci unsigned long flags; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 32162306a36Sopenharmony_ci ldma_update_bits(d, DMA_CTRL_RST, DMA_CTRL_RST, DMA_CTRL); 32262306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_cistatic void ldma_dev_pkt_arb_cfg(struct ldma_dev *d, bool enable) 32662306a36Sopenharmony_ci{ 32762306a36Sopenharmony_ci unsigned long flags; 32862306a36Sopenharmony_ci u32 mask = DMA_CTRL_PKTARB; 32962306a36Sopenharmony_ci u32 val = enable ? DMA_CTRL_PKTARB : 0; 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 33262306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 33362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_cistatic void ldma_dev_sram_desc_cfg(struct ldma_dev *d, bool enable) 33762306a36Sopenharmony_ci{ 33862306a36Sopenharmony_ci unsigned long flags; 33962306a36Sopenharmony_ci u32 mask = DMA_CTRL_DSRAM_PATH; 34062306a36Sopenharmony_ci u32 val = enable ? DMA_CTRL_DSRAM_PATH : 0; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 34362306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 34462306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic void ldma_dev_chan_flow_ctl_cfg(struct ldma_dev *d, bool enable) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci unsigned long flags; 35062306a36Sopenharmony_ci u32 mask, val; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (d->inst->type != DMA_TYPE_TX) 35362306a36Sopenharmony_ci return; 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_ci mask = DMA_CTRL_CH_FL; 35662306a36Sopenharmony_ci val = enable ? DMA_CTRL_CH_FL : 0; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 35962306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 36062306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic void ldma_dev_global_polling_enable(struct ldma_dev *d) 36462306a36Sopenharmony_ci{ 36562306a36Sopenharmony_ci unsigned long flags; 36662306a36Sopenharmony_ci u32 mask = DMA_CPOLL_EN | DMA_CPOLL_CNT; 36762306a36Sopenharmony_ci u32 val = DMA_CPOLL_EN; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci val |= FIELD_PREP(DMA_CPOLL_CNT, d->pollcnt); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 37262306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CPOLL); 37362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 37462306a36Sopenharmony_ci} 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_cistatic void ldma_dev_desc_fetch_on_demand_cfg(struct ldma_dev *d, bool enable) 37762306a36Sopenharmony_ci{ 37862306a36Sopenharmony_ci unsigned long flags; 37962306a36Sopenharmony_ci u32 mask, val; 38062306a36Sopenharmony_ci 38162306a36Sopenharmony_ci if (d->inst->type == DMA_TYPE_MCPY) 38262306a36Sopenharmony_ci return; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci mask = DMA_CTRL_DS_FOD; 38562306a36Sopenharmony_ci val = enable ? DMA_CTRL_DS_FOD : 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 38862306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 38962306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_cistatic void ldma_dev_byte_enable_cfg(struct ldma_dev *d, bool enable) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci unsigned long flags; 39562306a36Sopenharmony_ci u32 mask = DMA_CTRL_ENBE; 39662306a36Sopenharmony_ci u32 val = enable ? DMA_CTRL_ENBE : 0; 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 39962306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 40062306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_cistatic void ldma_dev_orrc_cfg(struct ldma_dev *d) 40462306a36Sopenharmony_ci{ 40562306a36Sopenharmony_ci unsigned long flags; 40662306a36Sopenharmony_ci u32 val = 0; 40762306a36Sopenharmony_ci u32 mask; 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (d->inst->type == DMA_TYPE_RX) 41062306a36Sopenharmony_ci return; 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci mask = DMA_ORRC_EN | DMA_ORRC_ORRCNT; 41362306a36Sopenharmony_ci if (d->inst->orrc > 0 && d->inst->orrc <= DMA_ORRC_MAX_CNT) 41462306a36Sopenharmony_ci val = DMA_ORRC_EN | FIELD_PREP(DMA_ORRC_ORRCNT, d->inst->orrc); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 41762306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_ORRC); 41862306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 41962306a36Sopenharmony_ci} 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_cistatic void ldma_dev_df_tout_cfg(struct ldma_dev *d, bool enable, int tcnt) 42262306a36Sopenharmony_ci{ 42362306a36Sopenharmony_ci u32 mask = DMA_CTRL_DESC_TMOUT_CNT_V31; 42462306a36Sopenharmony_ci unsigned long flags; 42562306a36Sopenharmony_ci u32 val; 42662306a36Sopenharmony_ci 42762306a36Sopenharmony_ci if (enable) 42862306a36Sopenharmony_ci val = DMA_CTRL_DESC_TMOUT_EN_V31 | FIELD_PREP(DMA_CTRL_DESC_TMOUT_CNT_V31, tcnt); 42962306a36Sopenharmony_ci else 43062306a36Sopenharmony_ci val = 0; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 43362306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 43462306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic void ldma_dev_dburst_wr_cfg(struct ldma_dev *d, bool enable) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci unsigned long flags; 44062306a36Sopenharmony_ci u32 mask, val; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (d->inst->type != DMA_TYPE_RX && d->inst->type != DMA_TYPE_MCPY) 44362306a36Sopenharmony_ci return; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci mask = DMA_CTRL_DBURST_WR; 44662306a36Sopenharmony_ci val = enable ? DMA_CTRL_DBURST_WR : 0; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 44962306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 45062306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 45162306a36Sopenharmony_ci} 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_cistatic void ldma_dev_vld_fetch_ack_cfg(struct ldma_dev *d, bool enable) 45462306a36Sopenharmony_ci{ 45562306a36Sopenharmony_ci unsigned long flags; 45662306a36Sopenharmony_ci u32 mask, val; 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (d->inst->type != DMA_TYPE_TX) 45962306a36Sopenharmony_ci return; 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci mask = DMA_CTRL_VLD_DF_ACK; 46262306a36Sopenharmony_ci val = enable ? DMA_CTRL_VLD_DF_ACK : 0; 46362306a36Sopenharmony_ci 46462306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 46562306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 46662306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 46762306a36Sopenharmony_ci} 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_cistatic void ldma_dev_drb_cfg(struct ldma_dev *d, int enable) 47062306a36Sopenharmony_ci{ 47162306a36Sopenharmony_ci unsigned long flags; 47262306a36Sopenharmony_ci u32 mask = DMA_CTRL_DRB; 47362306a36Sopenharmony_ci u32 val = enable ? DMA_CTRL_DRB : 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 47662306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CTRL); 47762306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_cistatic int ldma_dev_cfg(struct ldma_dev *d) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci bool enable; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci ldma_dev_pkt_arb_cfg(d, true); 48562306a36Sopenharmony_ci ldma_dev_global_polling_enable(d); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci enable = !!(d->flags & DMA_DFT_DRB); 48862306a36Sopenharmony_ci ldma_dev_drb_cfg(d, enable); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci enable = !!(d->flags & DMA_EN_BYTE_EN); 49162306a36Sopenharmony_ci ldma_dev_byte_enable_cfg(d, enable); 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci enable = !!(d->flags & DMA_CHAN_FLOW_CTL); 49462306a36Sopenharmony_ci ldma_dev_chan_flow_ctl_cfg(d, enable); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci enable = !!(d->flags & DMA_DESC_FOD); 49762306a36Sopenharmony_ci ldma_dev_desc_fetch_on_demand_cfg(d, enable); 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci enable = !!(d->flags & DMA_DESC_IN_SRAM); 50062306a36Sopenharmony_ci ldma_dev_sram_desc_cfg(d, enable); 50162306a36Sopenharmony_ci 50262306a36Sopenharmony_ci enable = !!(d->flags & DMA_DBURST_WR); 50362306a36Sopenharmony_ci ldma_dev_dburst_wr_cfg(d, enable); 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci enable = !!(d->flags & DMA_VALID_DESC_FETCH_ACK); 50662306a36Sopenharmony_ci ldma_dev_vld_fetch_ack_cfg(d, enable); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ci if (d->ver > DMA_VER22) { 50962306a36Sopenharmony_ci ldma_dev_orrc_cfg(d); 51062306a36Sopenharmony_ci ldma_dev_df_tout_cfg(d, true, DMA_DFT_DESC_TCNT); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci dev_dbg(d->dev, "%s Controller 0x%08x configuration done\n", 51462306a36Sopenharmony_ci d->inst->name, readl(d->base + DMA_CTRL)); 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci return 0; 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_cistatic int ldma_chan_cctrl_cfg(struct ldma_chan *c, u32 val) 52062306a36Sopenharmony_ci{ 52162306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 52262306a36Sopenharmony_ci u32 class_low, class_high; 52362306a36Sopenharmony_ci unsigned long flags; 52462306a36Sopenharmony_ci u32 reg; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 52762306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 52862306a36Sopenharmony_ci reg = readl(d->base + DMA_CCTRL); 52962306a36Sopenharmony_ci /* Read from hardware */ 53062306a36Sopenharmony_ci if (reg & DMA_CCTRL_DIR_TX) 53162306a36Sopenharmony_ci c->flags |= DMA_TX_CH; 53262306a36Sopenharmony_ci else 53362306a36Sopenharmony_ci c->flags |= DMA_RX_CH; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Keep the class value unchanged */ 53662306a36Sopenharmony_ci class_low = FIELD_GET(DMA_CCTRL_CLASS, reg); 53762306a36Sopenharmony_ci class_high = FIELD_GET(DMA_CCTRL_CLASSH, reg); 53862306a36Sopenharmony_ci val &= ~DMA_CCTRL_CLASS; 53962306a36Sopenharmony_ci val |= FIELD_PREP(DMA_CCTRL_CLASS, class_low); 54062306a36Sopenharmony_ci val &= ~DMA_CCTRL_CLASSH; 54162306a36Sopenharmony_ci val |= FIELD_PREP(DMA_CCTRL_CLASSH, class_high); 54262306a36Sopenharmony_ci writel(val, d->base + DMA_CCTRL); 54362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void ldma_chan_irq_init(struct ldma_chan *c) 54962306a36Sopenharmony_ci{ 55062306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 55162306a36Sopenharmony_ci unsigned long flags; 55262306a36Sopenharmony_ci u32 enofs, crofs; 55362306a36Sopenharmony_ci u32 cn_bit; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci if (c->nr < MAX_LOWER_CHANS) { 55662306a36Sopenharmony_ci enofs = DMA_IRNEN; 55762306a36Sopenharmony_ci crofs = DMA_IRNCR; 55862306a36Sopenharmony_ci } else { 55962306a36Sopenharmony_ci enofs = DMA_IRNEN1; 56062306a36Sopenharmony_ci crofs = DMA_IRNCR1; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci cn_bit = BIT(c->nr & MASK_LOWER_CHANS); 56462306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 56562306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci /* Clear all interrupts and disabled it */ 56862306a36Sopenharmony_ci writel(0, d->base + DMA_CIE); 56962306a36Sopenharmony_ci writel(DMA_CI_ALL, d->base + DMA_CIS); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ldma_update_bits(d, cn_bit, 0, enofs); 57262306a36Sopenharmony_ci writel(cn_bit, d->base + crofs); 57362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 57462306a36Sopenharmony_ci} 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_cistatic void ldma_chan_set_class(struct ldma_chan *c, u32 val) 57762306a36Sopenharmony_ci{ 57862306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 57962306a36Sopenharmony_ci u32 class_val; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (d->inst->type == DMA_TYPE_MCPY || val > DMA_MAX_CLASS) 58262306a36Sopenharmony_ci return; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci /* 3 bits low */ 58562306a36Sopenharmony_ci class_val = FIELD_PREP(DMA_CCTRL_CLASS, val & 0x7); 58662306a36Sopenharmony_ci /* 2 bits high */ 58762306a36Sopenharmony_ci class_val |= FIELD_PREP(DMA_CCTRL_CLASSH, (val >> 3) & 0x3); 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 59062306a36Sopenharmony_ci ldma_update_bits(d, DMA_CCTRL_CLASS | DMA_CCTRL_CLASSH, class_val, 59162306a36Sopenharmony_ci DMA_CCTRL); 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic int ldma_chan_on(struct ldma_chan *c) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 59762306a36Sopenharmony_ci unsigned long flags; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci /* If descriptors not configured, not allow to turn on channel */ 60062306a36Sopenharmony_ci if (WARN_ON(!c->desc_init)) 60162306a36Sopenharmony_ci return -EINVAL; 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 60462306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 60562306a36Sopenharmony_ci ldma_update_bits(d, DMA_CCTRL_ON, DMA_CCTRL_ON, DMA_CCTRL); 60662306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci c->onoff = DMA_CH_ON; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return 0; 61162306a36Sopenharmony_ci} 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_cistatic int ldma_chan_off(struct ldma_chan *c) 61462306a36Sopenharmony_ci{ 61562306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 61662306a36Sopenharmony_ci unsigned long flags; 61762306a36Sopenharmony_ci u32 val; 61862306a36Sopenharmony_ci int ret; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 62162306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 62262306a36Sopenharmony_ci ldma_update_bits(d, DMA_CCTRL_ON, 0, DMA_CCTRL); 62362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(d->base + DMA_CCTRL, val, 62662306a36Sopenharmony_ci !(val & DMA_CCTRL_ON), 0, 10000); 62762306a36Sopenharmony_ci if (ret) 62862306a36Sopenharmony_ci return ret; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci c->onoff = DMA_CH_OFF; 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci return 0; 63362306a36Sopenharmony_ci} 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_cistatic void ldma_chan_desc_hw_cfg(struct ldma_chan *c, dma_addr_t desc_base, 63662306a36Sopenharmony_ci int desc_num) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 63962306a36Sopenharmony_ci unsigned long flags; 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 64262306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 64362306a36Sopenharmony_ci writel(lower_32_bits(desc_base), d->base + DMA_CDBA); 64462306a36Sopenharmony_ci 64562306a36Sopenharmony_ci /* Higher 4 bits of 36 bit addressing */ 64662306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT)) { 64762306a36Sopenharmony_ci u32 hi = upper_32_bits(desc_base) & HIGH_4_BITS; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci ldma_update_bits(d, DMA_CDBA_MSB, 65062306a36Sopenharmony_ci FIELD_PREP(DMA_CDBA_MSB, hi), DMA_CCTRL); 65162306a36Sopenharmony_ci } 65262306a36Sopenharmony_ci writel(desc_num, d->base + DMA_CDLEN); 65362306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci c->desc_init = true; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 65962306a36Sopenharmony_cildma_chan_desc_cfg(struct dma_chan *chan, dma_addr_t desc_base, int desc_num) 66062306a36Sopenharmony_ci{ 66162306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 66262306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 66362306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx; 66462306a36Sopenharmony_ci struct dw2_desc_sw *ds; 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci if (!desc_num) { 66762306a36Sopenharmony_ci dev_err(d->dev, "Channel %d must allocate descriptor first\n", 66862306a36Sopenharmony_ci c->nr); 66962306a36Sopenharmony_ci return NULL; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci if (desc_num > DMA_MAX_DESC_NUM) { 67362306a36Sopenharmony_ci dev_err(d->dev, "Channel %d descriptor number out of range %d\n", 67462306a36Sopenharmony_ci c->nr, desc_num); 67562306a36Sopenharmony_ci return NULL; 67662306a36Sopenharmony_ci } 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci ldma_chan_desc_hw_cfg(c, desc_base, desc_num); 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci c->flags |= DMA_HW_DESC; 68162306a36Sopenharmony_ci c->desc_cnt = desc_num; 68262306a36Sopenharmony_ci c->desc_phys = desc_base; 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci ds = kzalloc(sizeof(*ds), GFP_NOWAIT); 68562306a36Sopenharmony_ci if (!ds) 68662306a36Sopenharmony_ci return NULL; 68762306a36Sopenharmony_ci 68862306a36Sopenharmony_ci tx = &ds->vdesc.tx; 68962306a36Sopenharmony_ci dma_async_tx_descriptor_init(tx, chan); 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return tx; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int ldma_chan_reset(struct ldma_chan *c) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 69762306a36Sopenharmony_ci unsigned long flags; 69862306a36Sopenharmony_ci u32 val; 69962306a36Sopenharmony_ci int ret; 70062306a36Sopenharmony_ci 70162306a36Sopenharmony_ci ret = ldma_chan_off(c); 70262306a36Sopenharmony_ci if (ret) 70362306a36Sopenharmony_ci return ret; 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 70662306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 70762306a36Sopenharmony_ci ldma_update_bits(d, DMA_CCTRL_RST, DMA_CCTRL_RST, DMA_CCTRL); 70862306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 70962306a36Sopenharmony_ci 71062306a36Sopenharmony_ci ret = readl_poll_timeout_atomic(d->base + DMA_CCTRL, val, 71162306a36Sopenharmony_ci !(val & DMA_CCTRL_RST), 0, 10000); 71262306a36Sopenharmony_ci if (ret) 71362306a36Sopenharmony_ci return ret; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci c->rst = 1; 71662306a36Sopenharmony_ci c->desc_init = false; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return 0; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic void ldma_chan_byte_offset_cfg(struct ldma_chan *c, u32 boff_len) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 72462306a36Sopenharmony_ci u32 mask = DMA_C_BOFF_EN | DMA_C_BOFF_BOF_LEN; 72562306a36Sopenharmony_ci u32 val; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (boff_len > 0 && boff_len <= DMA_CHAN_BOFF_MAX) 72862306a36Sopenharmony_ci val = FIELD_PREP(DMA_C_BOFF_BOF_LEN, boff_len) | DMA_C_BOFF_EN; 72962306a36Sopenharmony_ci else 73062306a36Sopenharmony_ci val = 0; 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 73362306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_C_BOFF); 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic void ldma_chan_data_endian_cfg(struct ldma_chan *c, bool enable, 73762306a36Sopenharmony_ci u32 endian_type) 73862306a36Sopenharmony_ci{ 73962306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 74062306a36Sopenharmony_ci u32 mask = DMA_C_END_DE_EN | DMA_C_END_DATAENDI; 74162306a36Sopenharmony_ci u32 val; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (enable) 74462306a36Sopenharmony_ci val = DMA_C_END_DE_EN | FIELD_PREP(DMA_C_END_DATAENDI, endian_type); 74562306a36Sopenharmony_ci else 74662306a36Sopenharmony_ci val = 0; 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 74962306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_C_ENDIAN); 75062306a36Sopenharmony_ci} 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_cistatic void ldma_chan_desc_endian_cfg(struct ldma_chan *c, bool enable, 75362306a36Sopenharmony_ci u32 endian_type) 75462306a36Sopenharmony_ci{ 75562306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 75662306a36Sopenharmony_ci u32 mask = DMA_C_END_DES_EN | DMA_C_END_DESENDI; 75762306a36Sopenharmony_ci u32 val; 75862306a36Sopenharmony_ci 75962306a36Sopenharmony_ci if (enable) 76062306a36Sopenharmony_ci val = DMA_C_END_DES_EN | FIELD_PREP(DMA_C_END_DESENDI, endian_type); 76162306a36Sopenharmony_ci else 76262306a36Sopenharmony_ci val = 0; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 76562306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_C_ENDIAN); 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic void ldma_chan_hdr_mode_cfg(struct ldma_chan *c, u32 hdr_len, bool csum) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 77162306a36Sopenharmony_ci u32 mask, val; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci /* NB, csum disabled, hdr length must be provided */ 77462306a36Sopenharmony_ci if (!csum && (!hdr_len || hdr_len > DMA_HDR_LEN_MAX)) 77562306a36Sopenharmony_ci return; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci mask = DMA_C_HDRM_HDR_SUM; 77862306a36Sopenharmony_ci val = DMA_C_HDRM_HDR_SUM; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci if (!csum && hdr_len) 78162306a36Sopenharmony_ci val = hdr_len; 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 78462306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_C_HDRM); 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_cistatic void ldma_chan_rxwr_np_cfg(struct ldma_chan *c, bool enable) 78862306a36Sopenharmony_ci{ 78962306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 79062306a36Sopenharmony_ci u32 mask, val; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci /* Only valid for RX channel */ 79362306a36Sopenharmony_ci if (ldma_chan_tx(c)) 79462306a36Sopenharmony_ci return; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci mask = DMA_CCTRL_WR_NP_EN; 79762306a36Sopenharmony_ci val = enable ? DMA_CCTRL_WR_NP_EN : 0; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 80062306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CCTRL); 80162306a36Sopenharmony_ci} 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_cistatic void ldma_chan_abc_cfg(struct ldma_chan *c, bool enable) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 80662306a36Sopenharmony_ci u32 mask, val; 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_ci if (d->ver < DMA_VER32 || ldma_chan_tx(c)) 80962306a36Sopenharmony_ci return; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci mask = DMA_CCTRL_CH_ABC; 81262306a36Sopenharmony_ci val = enable ? DMA_CCTRL_CH_ABC : 0; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci ldma_update_bits(d, DMA_CS_MASK, c->nr, DMA_CS); 81562306a36Sopenharmony_ci ldma_update_bits(d, mask, val, DMA_CCTRL); 81662306a36Sopenharmony_ci} 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_cistatic int ldma_port_cfg(struct ldma_port *p) 81962306a36Sopenharmony_ci{ 82062306a36Sopenharmony_ci unsigned long flags; 82162306a36Sopenharmony_ci struct ldma_dev *d; 82262306a36Sopenharmony_ci u32 reg; 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci d = p->ldev; 82562306a36Sopenharmony_ci reg = FIELD_PREP(DMA_PCTRL_TXENDI, p->txendi); 82662306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_RXENDI, p->rxendi); 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci if (d->ver == DMA_VER22) { 82962306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_TXBL, p->txbl); 83062306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_RXBL, p->rxbl); 83162306a36Sopenharmony_ci } else { 83262306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_PDEN, p->pkt_drop); 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_ci if (p->txbl == DMA_BURSTL_32DW) 83562306a36Sopenharmony_ci reg |= DMA_PCTRL_TXBL32; 83662306a36Sopenharmony_ci else if (p->txbl == DMA_BURSTL_16DW) 83762306a36Sopenharmony_ci reg |= DMA_PCTRL_TXBL16; 83862306a36Sopenharmony_ci else 83962306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_TXBL, DMA_PCTRL_TXBL_8); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (p->rxbl == DMA_BURSTL_32DW) 84262306a36Sopenharmony_ci reg |= DMA_PCTRL_RXBL32; 84362306a36Sopenharmony_ci else if (p->rxbl == DMA_BURSTL_16DW) 84462306a36Sopenharmony_ci reg |= DMA_PCTRL_RXBL16; 84562306a36Sopenharmony_ci else 84662306a36Sopenharmony_ci reg |= FIELD_PREP(DMA_PCTRL_RXBL, DMA_PCTRL_RXBL_8); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 85062306a36Sopenharmony_ci writel(p->portid, d->base + DMA_PS); 85162306a36Sopenharmony_ci writel(reg, d->base + DMA_PCTRL); 85262306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci reg = readl(d->base + DMA_PCTRL); /* read back */ 85562306a36Sopenharmony_ci dev_dbg(d->dev, "Port Control 0x%08x configuration done\n", reg); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return 0; 85862306a36Sopenharmony_ci} 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_cistatic int ldma_chan_cfg(struct ldma_chan *c) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 86362306a36Sopenharmony_ci unsigned long flags; 86462306a36Sopenharmony_ci u32 reg; 86562306a36Sopenharmony_ci 86662306a36Sopenharmony_ci reg = c->pden ? DMA_CCTRL_PDEN : 0; 86762306a36Sopenharmony_ci reg |= c->onoff ? DMA_CCTRL_ON : 0; 86862306a36Sopenharmony_ci reg |= c->rst ? DMA_CCTRL_RST : 0; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci ldma_chan_cctrl_cfg(c, reg); 87162306a36Sopenharmony_ci ldma_chan_irq_init(c); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (d->ver <= DMA_VER22) 87462306a36Sopenharmony_ci return 0; 87562306a36Sopenharmony_ci 87662306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 87762306a36Sopenharmony_ci ldma_chan_set_class(c, c->nr); 87862306a36Sopenharmony_ci ldma_chan_byte_offset_cfg(c, c->boff_len); 87962306a36Sopenharmony_ci ldma_chan_data_endian_cfg(c, c->data_endian_en, c->data_endian); 88062306a36Sopenharmony_ci ldma_chan_desc_endian_cfg(c, c->desc_endian_en, c->desc_endian); 88162306a36Sopenharmony_ci ldma_chan_hdr_mode_cfg(c, c->hdrm_len, c->hdrm_csum); 88262306a36Sopenharmony_ci ldma_chan_rxwr_np_cfg(c, c->desc_rx_np); 88362306a36Sopenharmony_ci ldma_chan_abc_cfg(c, c->abc_en); 88462306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci if (ldma_chan_is_hw_desc(c)) 88762306a36Sopenharmony_ci ldma_chan_desc_hw_cfg(c, c->desc_phys, c->desc_cnt); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci return 0; 89062306a36Sopenharmony_ci} 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_cistatic void ldma_dev_init(struct ldma_dev *d) 89362306a36Sopenharmony_ci{ 89462306a36Sopenharmony_ci unsigned long ch_mask = (unsigned long)d->channels_mask; 89562306a36Sopenharmony_ci struct ldma_port *p; 89662306a36Sopenharmony_ci struct ldma_chan *c; 89762306a36Sopenharmony_ci int i; 89862306a36Sopenharmony_ci u32 j; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci spin_lock_init(&d->dev_lock); 90162306a36Sopenharmony_ci ldma_dev_reset(d); 90262306a36Sopenharmony_ci ldma_dev_cfg(d); 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci /* DMA port initialization */ 90562306a36Sopenharmony_ci for (i = 0; i < d->port_nrs; i++) { 90662306a36Sopenharmony_ci p = &d->ports[i]; 90762306a36Sopenharmony_ci ldma_port_cfg(p); 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci /* DMA channel initialization */ 91162306a36Sopenharmony_ci for_each_set_bit(j, &ch_mask, d->chan_nrs) { 91262306a36Sopenharmony_ci c = &d->chans[j]; 91362306a36Sopenharmony_ci ldma_chan_cfg(c); 91462306a36Sopenharmony_ci } 91562306a36Sopenharmony_ci} 91662306a36Sopenharmony_ci 91762306a36Sopenharmony_cistatic int ldma_parse_dt(struct ldma_dev *d) 91862306a36Sopenharmony_ci{ 91962306a36Sopenharmony_ci struct fwnode_handle *fwnode = dev_fwnode(d->dev); 92062306a36Sopenharmony_ci struct ldma_port *p; 92162306a36Sopenharmony_ci int i; 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci if (fwnode_property_read_bool(fwnode, "intel,dma-byte-en")) 92462306a36Sopenharmony_ci d->flags |= DMA_EN_BYTE_EN; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci if (fwnode_property_read_bool(fwnode, "intel,dma-dburst-wr")) 92762306a36Sopenharmony_ci d->flags |= DMA_DBURST_WR; 92862306a36Sopenharmony_ci 92962306a36Sopenharmony_ci if (fwnode_property_read_bool(fwnode, "intel,dma-drb")) 93062306a36Sopenharmony_ci d->flags |= DMA_DFT_DRB; 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci if (fwnode_property_read_u32(fwnode, "intel,dma-poll-cnt", 93362306a36Sopenharmony_ci &d->pollcnt)) 93462306a36Sopenharmony_ci d->pollcnt = DMA_DFT_POLL_CNT; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci if (d->inst->chan_fc) 93762306a36Sopenharmony_ci d->flags |= DMA_CHAN_FLOW_CTL; 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci if (d->inst->desc_fod) 94062306a36Sopenharmony_ci d->flags |= DMA_DESC_FOD; 94162306a36Sopenharmony_ci 94262306a36Sopenharmony_ci if (d->inst->desc_in_sram) 94362306a36Sopenharmony_ci d->flags |= DMA_DESC_IN_SRAM; 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (d->inst->valid_desc_fetch_ack) 94662306a36Sopenharmony_ci d->flags |= DMA_VALID_DESC_FETCH_ACK; 94762306a36Sopenharmony_ci 94862306a36Sopenharmony_ci if (d->ver > DMA_VER22) { 94962306a36Sopenharmony_ci if (!d->port_nrs) 95062306a36Sopenharmony_ci return -EINVAL; 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci for (i = 0; i < d->port_nrs; i++) { 95362306a36Sopenharmony_ci p = &d->ports[i]; 95462306a36Sopenharmony_ci p->rxendi = DMA_DFT_ENDIAN; 95562306a36Sopenharmony_ci p->txendi = DMA_DFT_ENDIAN; 95662306a36Sopenharmony_ci p->rxbl = DMA_DFT_BURST; 95762306a36Sopenharmony_ci p->txbl = DMA_DFT_BURST; 95862306a36Sopenharmony_ci p->pkt_drop = DMA_PKT_DROP_DIS; 95962306a36Sopenharmony_ci } 96062306a36Sopenharmony_ci } 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci return 0; 96362306a36Sopenharmony_ci} 96462306a36Sopenharmony_ci 96562306a36Sopenharmony_cistatic void dma_free_desc_resource(struct virt_dma_desc *vdesc) 96662306a36Sopenharmony_ci{ 96762306a36Sopenharmony_ci struct dw2_desc_sw *ds = to_lgm_dma_desc(vdesc); 96862306a36Sopenharmony_ci struct ldma_chan *c = ds->chan; 96962306a36Sopenharmony_ci 97062306a36Sopenharmony_ci dma_pool_free(c->desc_pool, ds->desc_hw, ds->desc_phys); 97162306a36Sopenharmony_ci kfree(ds); 97262306a36Sopenharmony_ci} 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_cistatic struct dw2_desc_sw * 97562306a36Sopenharmony_cidma_alloc_desc_resource(int num, struct ldma_chan *c) 97662306a36Sopenharmony_ci{ 97762306a36Sopenharmony_ci struct device *dev = c->vchan.chan.device->dev; 97862306a36Sopenharmony_ci struct dw2_desc_sw *ds; 97962306a36Sopenharmony_ci 98062306a36Sopenharmony_ci if (num > c->desc_num) { 98162306a36Sopenharmony_ci dev_err(dev, "sg num %d exceed max %d\n", num, c->desc_num); 98262306a36Sopenharmony_ci return NULL; 98362306a36Sopenharmony_ci } 98462306a36Sopenharmony_ci 98562306a36Sopenharmony_ci ds = kzalloc(sizeof(*ds), GFP_NOWAIT); 98662306a36Sopenharmony_ci if (!ds) 98762306a36Sopenharmony_ci return NULL; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci ds->chan = c; 99062306a36Sopenharmony_ci ds->desc_hw = dma_pool_zalloc(c->desc_pool, GFP_ATOMIC, 99162306a36Sopenharmony_ci &ds->desc_phys); 99262306a36Sopenharmony_ci if (!ds->desc_hw) { 99362306a36Sopenharmony_ci dev_dbg(dev, "out of memory for link descriptor\n"); 99462306a36Sopenharmony_ci kfree(ds); 99562306a36Sopenharmony_ci return NULL; 99662306a36Sopenharmony_ci } 99762306a36Sopenharmony_ci ds->desc_cnt = num; 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_ci return ds; 100062306a36Sopenharmony_ci} 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_cistatic void ldma_chan_irq_en(struct ldma_chan *c) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 100562306a36Sopenharmony_ci unsigned long flags; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_ci spin_lock_irqsave(&d->dev_lock, flags); 100862306a36Sopenharmony_ci writel(c->nr, d->base + DMA_CS); 100962306a36Sopenharmony_ci writel(DMA_CI_EOP, d->base + DMA_CIE); 101062306a36Sopenharmony_ci writel(BIT(c->nr), d->base + DMA_IRNEN); 101162306a36Sopenharmony_ci spin_unlock_irqrestore(&d->dev_lock, flags); 101262306a36Sopenharmony_ci} 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_cistatic void ldma_issue_pending(struct dma_chan *chan) 101562306a36Sopenharmony_ci{ 101662306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 101762306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 101862306a36Sopenharmony_ci unsigned long flags; 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (d->ver == DMA_VER22) { 102162306a36Sopenharmony_ci spin_lock_irqsave(&c->vchan.lock, flags); 102262306a36Sopenharmony_ci if (vchan_issue_pending(&c->vchan)) { 102362306a36Sopenharmony_ci struct virt_dma_desc *vdesc; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* Get the next descriptor */ 102662306a36Sopenharmony_ci vdesc = vchan_next_desc(&c->vchan); 102762306a36Sopenharmony_ci if (!vdesc) { 102862306a36Sopenharmony_ci c->ds = NULL; 102962306a36Sopenharmony_ci spin_unlock_irqrestore(&c->vchan.lock, flags); 103062306a36Sopenharmony_ci return; 103162306a36Sopenharmony_ci } 103262306a36Sopenharmony_ci list_del(&vdesc->node); 103362306a36Sopenharmony_ci c->ds = to_lgm_dma_desc(vdesc); 103462306a36Sopenharmony_ci ldma_chan_desc_hw_cfg(c, c->ds->desc_phys, c->ds->desc_cnt); 103562306a36Sopenharmony_ci ldma_chan_irq_en(c); 103662306a36Sopenharmony_ci } 103762306a36Sopenharmony_ci spin_unlock_irqrestore(&c->vchan.lock, flags); 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci ldma_chan_on(c); 104062306a36Sopenharmony_ci} 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_cistatic void ldma_synchronize(struct dma_chan *chan) 104362306a36Sopenharmony_ci{ 104462306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci /* 104762306a36Sopenharmony_ci * clear any pending work if any. In that 104862306a36Sopenharmony_ci * case the resource needs to be free here. 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_ci cancel_work_sync(&c->work); 105162306a36Sopenharmony_ci vchan_synchronize(&c->vchan); 105262306a36Sopenharmony_ci if (c->ds) 105362306a36Sopenharmony_ci dma_free_desc_resource(&c->ds->vdesc); 105462306a36Sopenharmony_ci} 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_cistatic int ldma_terminate_all(struct dma_chan *chan) 105762306a36Sopenharmony_ci{ 105862306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 105962306a36Sopenharmony_ci unsigned long flags; 106062306a36Sopenharmony_ci LIST_HEAD(head); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci spin_lock_irqsave(&c->vchan.lock, flags); 106362306a36Sopenharmony_ci vchan_get_all_descriptors(&c->vchan, &head); 106462306a36Sopenharmony_ci spin_unlock_irqrestore(&c->vchan.lock, flags); 106562306a36Sopenharmony_ci vchan_dma_desc_free_list(&c->vchan, &head); 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci return ldma_chan_reset(c); 106862306a36Sopenharmony_ci} 106962306a36Sopenharmony_ci 107062306a36Sopenharmony_cistatic int ldma_resume_chan(struct dma_chan *chan) 107162306a36Sopenharmony_ci{ 107262306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci ldma_chan_on(c); 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci return 0; 107762306a36Sopenharmony_ci} 107862306a36Sopenharmony_ci 107962306a36Sopenharmony_cistatic int ldma_pause_chan(struct dma_chan *chan) 108062306a36Sopenharmony_ci{ 108162306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci return ldma_chan_off(c); 108462306a36Sopenharmony_ci} 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_cistatic enum dma_status 108762306a36Sopenharmony_cildma_tx_status(struct dma_chan *chan, dma_cookie_t cookie, 108862306a36Sopenharmony_ci struct dma_tx_state *txstate) 108962306a36Sopenharmony_ci{ 109062306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 109162306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 109262306a36Sopenharmony_ci enum dma_status status = DMA_COMPLETE; 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_ci if (d->ver == DMA_VER22) 109562306a36Sopenharmony_ci status = dma_cookie_status(chan, cookie, txstate); 109662306a36Sopenharmony_ci 109762306a36Sopenharmony_ci return status; 109862306a36Sopenharmony_ci} 109962306a36Sopenharmony_ci 110062306a36Sopenharmony_cistatic void dma_chan_irq(int irq, void *data) 110162306a36Sopenharmony_ci{ 110262306a36Sopenharmony_ci struct ldma_chan *c = data; 110362306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 110462306a36Sopenharmony_ci u32 stat; 110562306a36Sopenharmony_ci 110662306a36Sopenharmony_ci /* Disable channel interrupts */ 110762306a36Sopenharmony_ci writel(c->nr, d->base + DMA_CS); 110862306a36Sopenharmony_ci stat = readl(d->base + DMA_CIS); 110962306a36Sopenharmony_ci if (!stat) 111062306a36Sopenharmony_ci return; 111162306a36Sopenharmony_ci 111262306a36Sopenharmony_ci writel(readl(d->base + DMA_CIE) & ~DMA_CI_ALL, d->base + DMA_CIE); 111362306a36Sopenharmony_ci writel(stat, d->base + DMA_CIS); 111462306a36Sopenharmony_ci queue_work(d->wq, &c->work); 111562306a36Sopenharmony_ci} 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_cistatic irqreturn_t dma_interrupt(int irq, void *dev_id) 111862306a36Sopenharmony_ci{ 111962306a36Sopenharmony_ci struct ldma_dev *d = dev_id; 112062306a36Sopenharmony_ci struct ldma_chan *c; 112162306a36Sopenharmony_ci unsigned long irncr; 112262306a36Sopenharmony_ci u32 cid; 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci irncr = readl(d->base + DMA_IRNCR); 112562306a36Sopenharmony_ci if (!irncr) { 112662306a36Sopenharmony_ci dev_err(d->dev, "dummy interrupt\n"); 112762306a36Sopenharmony_ci return IRQ_NONE; 112862306a36Sopenharmony_ci } 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci for_each_set_bit(cid, &irncr, d->chan_nrs) { 113162306a36Sopenharmony_ci /* Mask */ 113262306a36Sopenharmony_ci writel(readl(d->base + DMA_IRNEN) & ~BIT(cid), d->base + DMA_IRNEN); 113362306a36Sopenharmony_ci /* Ack */ 113462306a36Sopenharmony_ci writel(readl(d->base + DMA_IRNCR) | BIT(cid), d->base + DMA_IRNCR); 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_ci c = &d->chans[cid]; 113762306a36Sopenharmony_ci dma_chan_irq(irq, c); 113862306a36Sopenharmony_ci } 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_ci return IRQ_HANDLED; 114162306a36Sopenharmony_ci} 114262306a36Sopenharmony_ci 114362306a36Sopenharmony_cistatic void prep_slave_burst_len(struct ldma_chan *c) 114462306a36Sopenharmony_ci{ 114562306a36Sopenharmony_ci struct ldma_port *p = c->port; 114662306a36Sopenharmony_ci struct dma_slave_config *cfg = &c->config; 114762306a36Sopenharmony_ci 114862306a36Sopenharmony_ci if (cfg->dst_maxburst) 114962306a36Sopenharmony_ci cfg->src_maxburst = cfg->dst_maxburst; 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_ci /* TX and RX has the same burst length */ 115262306a36Sopenharmony_ci p->txbl = ilog2(cfg->src_maxburst); 115362306a36Sopenharmony_ci p->rxbl = p->txbl; 115462306a36Sopenharmony_ci} 115562306a36Sopenharmony_ci 115662306a36Sopenharmony_cistatic struct dma_async_tx_descriptor * 115762306a36Sopenharmony_cildma_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl, 115862306a36Sopenharmony_ci unsigned int sglen, enum dma_transfer_direction dir, 115962306a36Sopenharmony_ci unsigned long flags, void *context) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 116262306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 116362306a36Sopenharmony_ci size_t len, avail, total = 0; 116462306a36Sopenharmony_ci struct dw2_desc *hw_ds; 116562306a36Sopenharmony_ci struct dw2_desc_sw *ds; 116662306a36Sopenharmony_ci struct scatterlist *sg; 116762306a36Sopenharmony_ci int num = sglen, i; 116862306a36Sopenharmony_ci dma_addr_t addr; 116962306a36Sopenharmony_ci 117062306a36Sopenharmony_ci if (!sgl) 117162306a36Sopenharmony_ci return NULL; 117262306a36Sopenharmony_ci 117362306a36Sopenharmony_ci if (d->ver > DMA_VER22) 117462306a36Sopenharmony_ci return ldma_chan_desc_cfg(chan, sgl->dma_address, sglen); 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_ci for_each_sg(sgl, sg, sglen, i) { 117762306a36Sopenharmony_ci avail = sg_dma_len(sg); 117862306a36Sopenharmony_ci if (avail > DMA_MAX_SIZE) 117962306a36Sopenharmony_ci num += DIV_ROUND_UP(avail, DMA_MAX_SIZE) - 1; 118062306a36Sopenharmony_ci } 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci ds = dma_alloc_desc_resource(num, c); 118362306a36Sopenharmony_ci if (!ds) 118462306a36Sopenharmony_ci return NULL; 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci c->ds = ds; 118762306a36Sopenharmony_ci 118862306a36Sopenharmony_ci num = 0; 118962306a36Sopenharmony_ci /* sop and eop has to be handled nicely */ 119062306a36Sopenharmony_ci for_each_sg(sgl, sg, sglen, i) { 119162306a36Sopenharmony_ci addr = sg_dma_address(sg); 119262306a36Sopenharmony_ci avail = sg_dma_len(sg); 119362306a36Sopenharmony_ci total += avail; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci do { 119662306a36Sopenharmony_ci len = min_t(size_t, avail, DMA_MAX_SIZE); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci hw_ds = &ds->desc_hw[num]; 119962306a36Sopenharmony_ci switch (sglen) { 120062306a36Sopenharmony_ci case 1: 120162306a36Sopenharmony_ci hw_ds->field &= ~DESC_SOP; 120262306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_SOP, 1); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci hw_ds->field &= ~DESC_EOP; 120562306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_EOP, 1); 120662306a36Sopenharmony_ci break; 120762306a36Sopenharmony_ci default: 120862306a36Sopenharmony_ci if (num == 0) { 120962306a36Sopenharmony_ci hw_ds->field &= ~DESC_SOP; 121062306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_SOP, 1); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci hw_ds->field &= ~DESC_EOP; 121362306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_EOP, 0); 121462306a36Sopenharmony_ci } else if (num == (sglen - 1)) { 121562306a36Sopenharmony_ci hw_ds->field &= ~DESC_SOP; 121662306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_SOP, 0); 121762306a36Sopenharmony_ci hw_ds->field &= ~DESC_EOP; 121862306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_EOP, 1); 121962306a36Sopenharmony_ci } else { 122062306a36Sopenharmony_ci hw_ds->field &= ~DESC_SOP; 122162306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_SOP, 0); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci hw_ds->field &= ~DESC_EOP; 122462306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_EOP, 0); 122562306a36Sopenharmony_ci } 122662306a36Sopenharmony_ci break; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci /* Only 32 bit address supported */ 122962306a36Sopenharmony_ci hw_ds->addr = (u32)addr; 123062306a36Sopenharmony_ci 123162306a36Sopenharmony_ci hw_ds->field &= ~DESC_DATA_LEN; 123262306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_DATA_LEN, len); 123362306a36Sopenharmony_ci 123462306a36Sopenharmony_ci hw_ds->field &= ~DESC_C; 123562306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_C, 0); 123662306a36Sopenharmony_ci 123762306a36Sopenharmony_ci hw_ds->field &= ~DESC_BYTE_OFF; 123862306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_BYTE_OFF, addr & 0x3); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci /* Ensure data ready before ownership change */ 124162306a36Sopenharmony_ci wmb(); 124262306a36Sopenharmony_ci hw_ds->field &= ~DESC_OWN; 124362306a36Sopenharmony_ci hw_ds->field |= FIELD_PREP(DESC_OWN, DMA_OWN); 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_ci /* Ensure ownership changed before moving forward */ 124662306a36Sopenharmony_ci wmb(); 124762306a36Sopenharmony_ci num++; 124862306a36Sopenharmony_ci addr += len; 124962306a36Sopenharmony_ci avail -= len; 125062306a36Sopenharmony_ci } while (avail); 125162306a36Sopenharmony_ci } 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ds->size = total; 125462306a36Sopenharmony_ci prep_slave_burst_len(c); 125562306a36Sopenharmony_ci 125662306a36Sopenharmony_ci return vchan_tx_prep(&c->vchan, &ds->vdesc, DMA_CTRL_ACK); 125762306a36Sopenharmony_ci} 125862306a36Sopenharmony_ci 125962306a36Sopenharmony_cistatic int 126062306a36Sopenharmony_cildma_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg) 126162306a36Sopenharmony_ci{ 126262306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci memcpy(&c->config, cfg, sizeof(c->config)); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci return 0; 126762306a36Sopenharmony_ci} 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_cistatic int ldma_alloc_chan_resources(struct dma_chan *chan) 127062306a36Sopenharmony_ci{ 127162306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 127262306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 127362306a36Sopenharmony_ci struct device *dev = c->vchan.chan.device->dev; 127462306a36Sopenharmony_ci size_t desc_sz; 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci if (d->ver > DMA_VER22) { 127762306a36Sopenharmony_ci c->flags |= CHAN_IN_USE; 127862306a36Sopenharmony_ci return 0; 127962306a36Sopenharmony_ci } 128062306a36Sopenharmony_ci 128162306a36Sopenharmony_ci if (c->desc_pool) 128262306a36Sopenharmony_ci return c->desc_num; 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_ci desc_sz = c->desc_num * sizeof(struct dw2_desc); 128562306a36Sopenharmony_ci c->desc_pool = dma_pool_create(c->name, dev, desc_sz, 128662306a36Sopenharmony_ci __alignof__(struct dw2_desc), 0); 128762306a36Sopenharmony_ci 128862306a36Sopenharmony_ci if (!c->desc_pool) { 128962306a36Sopenharmony_ci dev_err(dev, "unable to allocate descriptor pool\n"); 129062306a36Sopenharmony_ci return -ENOMEM; 129162306a36Sopenharmony_ci } 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci return c->desc_num; 129462306a36Sopenharmony_ci} 129562306a36Sopenharmony_ci 129662306a36Sopenharmony_cistatic void ldma_free_chan_resources(struct dma_chan *chan) 129762306a36Sopenharmony_ci{ 129862306a36Sopenharmony_ci struct ldma_chan *c = to_ldma_chan(chan); 129962306a36Sopenharmony_ci struct ldma_dev *d = to_ldma_dev(c->vchan.chan.device); 130062306a36Sopenharmony_ci 130162306a36Sopenharmony_ci if (d->ver == DMA_VER22) { 130262306a36Sopenharmony_ci dma_pool_destroy(c->desc_pool); 130362306a36Sopenharmony_ci c->desc_pool = NULL; 130462306a36Sopenharmony_ci vchan_free_chan_resources(to_virt_chan(chan)); 130562306a36Sopenharmony_ci ldma_chan_reset(c); 130662306a36Sopenharmony_ci } else { 130762306a36Sopenharmony_ci c->flags &= ~CHAN_IN_USE; 130862306a36Sopenharmony_ci } 130962306a36Sopenharmony_ci} 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_cistatic void dma_work(struct work_struct *work) 131262306a36Sopenharmony_ci{ 131362306a36Sopenharmony_ci struct ldma_chan *c = container_of(work, struct ldma_chan, work); 131462306a36Sopenharmony_ci struct dma_async_tx_descriptor *tx = &c->ds->vdesc.tx; 131562306a36Sopenharmony_ci struct virt_dma_chan *vc = &c->vchan; 131662306a36Sopenharmony_ci struct dmaengine_desc_callback cb; 131762306a36Sopenharmony_ci struct virt_dma_desc *vd, *_vd; 131862306a36Sopenharmony_ci unsigned long flags; 131962306a36Sopenharmony_ci LIST_HEAD(head); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci spin_lock_irqsave(&c->vchan.lock, flags); 132262306a36Sopenharmony_ci list_splice_tail_init(&vc->desc_completed, &head); 132362306a36Sopenharmony_ci spin_unlock_irqrestore(&c->vchan.lock, flags); 132462306a36Sopenharmony_ci dmaengine_desc_get_callback(tx, &cb); 132562306a36Sopenharmony_ci dma_cookie_complete(tx); 132662306a36Sopenharmony_ci dmaengine_desc_callback_invoke(&cb, NULL); 132762306a36Sopenharmony_ci 132862306a36Sopenharmony_ci list_for_each_entry_safe(vd, _vd, &head, node) { 132962306a36Sopenharmony_ci dmaengine_desc_get_callback(tx, &cb); 133062306a36Sopenharmony_ci dma_cookie_complete(tx); 133162306a36Sopenharmony_ci list_del(&vd->node); 133262306a36Sopenharmony_ci dmaengine_desc_callback_invoke(&cb, NULL); 133362306a36Sopenharmony_ci 133462306a36Sopenharmony_ci vchan_vdesc_fini(vd); 133562306a36Sopenharmony_ci } 133662306a36Sopenharmony_ci c->ds = NULL; 133762306a36Sopenharmony_ci} 133862306a36Sopenharmony_ci 133962306a36Sopenharmony_cistatic void 134062306a36Sopenharmony_ciupdate_burst_len_v22(struct ldma_chan *c, struct ldma_port *p, u32 burst) 134162306a36Sopenharmony_ci{ 134262306a36Sopenharmony_ci if (ldma_chan_tx(c)) 134362306a36Sopenharmony_ci p->txbl = ilog2(burst); 134462306a36Sopenharmony_ci else 134562306a36Sopenharmony_ci p->rxbl = ilog2(burst); 134662306a36Sopenharmony_ci} 134762306a36Sopenharmony_ci 134862306a36Sopenharmony_cistatic void 134962306a36Sopenharmony_ciupdate_burst_len_v3X(struct ldma_chan *c, struct ldma_port *p, u32 burst) 135062306a36Sopenharmony_ci{ 135162306a36Sopenharmony_ci if (ldma_chan_tx(c)) 135262306a36Sopenharmony_ci p->txbl = burst; 135362306a36Sopenharmony_ci else 135462306a36Sopenharmony_ci p->rxbl = burst; 135562306a36Sopenharmony_ci} 135662306a36Sopenharmony_ci 135762306a36Sopenharmony_cistatic int 135862306a36Sopenharmony_ciupdate_client_configs(struct of_dma *ofdma, struct of_phandle_args *spec) 135962306a36Sopenharmony_ci{ 136062306a36Sopenharmony_ci struct ldma_dev *d = ofdma->of_dma_data; 136162306a36Sopenharmony_ci u32 chan_id = spec->args[0]; 136262306a36Sopenharmony_ci u32 port_id = spec->args[1]; 136362306a36Sopenharmony_ci u32 burst = spec->args[2]; 136462306a36Sopenharmony_ci struct ldma_port *p; 136562306a36Sopenharmony_ci struct ldma_chan *c; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci if (chan_id >= d->chan_nrs || port_id >= d->port_nrs) 136862306a36Sopenharmony_ci return 0; 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci p = &d->ports[port_id]; 137162306a36Sopenharmony_ci c = &d->chans[chan_id]; 137262306a36Sopenharmony_ci c->port = p; 137362306a36Sopenharmony_ci 137462306a36Sopenharmony_ci if (d->ver == DMA_VER22) 137562306a36Sopenharmony_ci update_burst_len_v22(c, p, burst); 137662306a36Sopenharmony_ci else 137762306a36Sopenharmony_ci update_burst_len_v3X(c, p, burst); 137862306a36Sopenharmony_ci 137962306a36Sopenharmony_ci ldma_port_cfg(p); 138062306a36Sopenharmony_ci 138162306a36Sopenharmony_ci return 1; 138262306a36Sopenharmony_ci} 138362306a36Sopenharmony_ci 138462306a36Sopenharmony_cistatic struct dma_chan *ldma_xlate(struct of_phandle_args *spec, 138562306a36Sopenharmony_ci struct of_dma *ofdma) 138662306a36Sopenharmony_ci{ 138762306a36Sopenharmony_ci struct ldma_dev *d = ofdma->of_dma_data; 138862306a36Sopenharmony_ci u32 chan_id = spec->args[0]; 138962306a36Sopenharmony_ci int ret; 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci if (!spec->args_count) 139262306a36Sopenharmony_ci return NULL; 139362306a36Sopenharmony_ci 139462306a36Sopenharmony_ci /* if args_count is 1 driver use default settings */ 139562306a36Sopenharmony_ci if (spec->args_count > 1) { 139662306a36Sopenharmony_ci ret = update_client_configs(ofdma, spec); 139762306a36Sopenharmony_ci if (!ret) 139862306a36Sopenharmony_ci return NULL; 139962306a36Sopenharmony_ci } 140062306a36Sopenharmony_ci 140162306a36Sopenharmony_ci return dma_get_slave_channel(&d->chans[chan_id].vchan.chan); 140262306a36Sopenharmony_ci} 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_cistatic void ldma_dma_init_v22(int i, struct ldma_dev *d) 140562306a36Sopenharmony_ci{ 140662306a36Sopenharmony_ci struct ldma_chan *c; 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_ci c = &d->chans[i]; 140962306a36Sopenharmony_ci c->nr = i; /* Real channel number */ 141062306a36Sopenharmony_ci c->rst = DMA_CHAN_RST; 141162306a36Sopenharmony_ci c->desc_num = DMA_DFT_DESC_NUM; 141262306a36Sopenharmony_ci snprintf(c->name, sizeof(c->name), "chan%d", c->nr); 141362306a36Sopenharmony_ci INIT_WORK(&c->work, dma_work); 141462306a36Sopenharmony_ci c->vchan.desc_free = dma_free_desc_resource; 141562306a36Sopenharmony_ci vchan_init(&c->vchan, &d->dma_dev); 141662306a36Sopenharmony_ci} 141762306a36Sopenharmony_ci 141862306a36Sopenharmony_cistatic void ldma_dma_init_v3X(int i, struct ldma_dev *d) 141962306a36Sopenharmony_ci{ 142062306a36Sopenharmony_ci struct ldma_chan *c; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci c = &d->chans[i]; 142362306a36Sopenharmony_ci c->data_endian = DMA_DFT_ENDIAN; 142462306a36Sopenharmony_ci c->desc_endian = DMA_DFT_ENDIAN; 142562306a36Sopenharmony_ci c->data_endian_en = false; 142662306a36Sopenharmony_ci c->desc_endian_en = false; 142762306a36Sopenharmony_ci c->desc_rx_np = false; 142862306a36Sopenharmony_ci c->flags |= DEVICE_ALLOC_DESC; 142962306a36Sopenharmony_ci c->onoff = DMA_CH_OFF; 143062306a36Sopenharmony_ci c->rst = DMA_CHAN_RST; 143162306a36Sopenharmony_ci c->abc_en = true; 143262306a36Sopenharmony_ci c->hdrm_csum = false; 143362306a36Sopenharmony_ci c->boff_len = 0; 143462306a36Sopenharmony_ci c->nr = i; 143562306a36Sopenharmony_ci c->vchan.desc_free = dma_free_desc_resource; 143662306a36Sopenharmony_ci vchan_init(&c->vchan, &d->dma_dev); 143762306a36Sopenharmony_ci} 143862306a36Sopenharmony_ci 143962306a36Sopenharmony_cistatic int ldma_init_v22(struct ldma_dev *d, struct platform_device *pdev) 144062306a36Sopenharmony_ci{ 144162306a36Sopenharmony_ci int ret; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci ret = device_property_read_u32(d->dev, "dma-channels", &d->chan_nrs); 144462306a36Sopenharmony_ci if (ret < 0) { 144562306a36Sopenharmony_ci dev_err(d->dev, "unable to read dma-channels property\n"); 144662306a36Sopenharmony_ci return ret; 144762306a36Sopenharmony_ci } 144862306a36Sopenharmony_ci 144962306a36Sopenharmony_ci d->irq = platform_get_irq(pdev, 0); 145062306a36Sopenharmony_ci if (d->irq < 0) 145162306a36Sopenharmony_ci return d->irq; 145262306a36Sopenharmony_ci 145362306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, d->irq, dma_interrupt, 0, 145462306a36Sopenharmony_ci DRIVER_NAME, d); 145562306a36Sopenharmony_ci if (ret) 145662306a36Sopenharmony_ci return ret; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci d->wq = alloc_ordered_workqueue("dma_wq", WQ_MEM_RECLAIM | 145962306a36Sopenharmony_ci WQ_HIGHPRI); 146062306a36Sopenharmony_ci if (!d->wq) 146162306a36Sopenharmony_ci return -ENOMEM; 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci return 0; 146462306a36Sopenharmony_ci} 146562306a36Sopenharmony_ci 146662306a36Sopenharmony_cistatic void ldma_clk_disable(void *data) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct ldma_dev *d = data; 146962306a36Sopenharmony_ci 147062306a36Sopenharmony_ci clk_disable_unprepare(d->core_clk); 147162306a36Sopenharmony_ci reset_control_assert(d->rst); 147262306a36Sopenharmony_ci} 147362306a36Sopenharmony_ci 147462306a36Sopenharmony_cistatic const struct ldma_inst_data dma0 = { 147562306a36Sopenharmony_ci .name = "dma0", 147662306a36Sopenharmony_ci .chan_fc = false, 147762306a36Sopenharmony_ci .desc_fod = false, 147862306a36Sopenharmony_ci .desc_in_sram = false, 147962306a36Sopenharmony_ci .valid_desc_fetch_ack = false, 148062306a36Sopenharmony_ci}; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_cistatic const struct ldma_inst_data dma2tx = { 148362306a36Sopenharmony_ci .name = "dma2tx", 148462306a36Sopenharmony_ci .type = DMA_TYPE_TX, 148562306a36Sopenharmony_ci .orrc = 16, 148662306a36Sopenharmony_ci .chan_fc = true, 148762306a36Sopenharmony_ci .desc_fod = true, 148862306a36Sopenharmony_ci .desc_in_sram = true, 148962306a36Sopenharmony_ci .valid_desc_fetch_ack = true, 149062306a36Sopenharmony_ci}; 149162306a36Sopenharmony_ci 149262306a36Sopenharmony_cistatic const struct ldma_inst_data dma1rx = { 149362306a36Sopenharmony_ci .name = "dma1rx", 149462306a36Sopenharmony_ci .type = DMA_TYPE_RX, 149562306a36Sopenharmony_ci .orrc = 16, 149662306a36Sopenharmony_ci .chan_fc = false, 149762306a36Sopenharmony_ci .desc_fod = true, 149862306a36Sopenharmony_ci .desc_in_sram = true, 149962306a36Sopenharmony_ci .valid_desc_fetch_ack = false, 150062306a36Sopenharmony_ci}; 150162306a36Sopenharmony_ci 150262306a36Sopenharmony_cistatic const struct ldma_inst_data dma1tx = { 150362306a36Sopenharmony_ci .name = "dma1tx", 150462306a36Sopenharmony_ci .type = DMA_TYPE_TX, 150562306a36Sopenharmony_ci .orrc = 16, 150662306a36Sopenharmony_ci .chan_fc = true, 150762306a36Sopenharmony_ci .desc_fod = true, 150862306a36Sopenharmony_ci .desc_in_sram = true, 150962306a36Sopenharmony_ci .valid_desc_fetch_ack = true, 151062306a36Sopenharmony_ci}; 151162306a36Sopenharmony_ci 151262306a36Sopenharmony_cistatic const struct ldma_inst_data dma0tx = { 151362306a36Sopenharmony_ci .name = "dma0tx", 151462306a36Sopenharmony_ci .type = DMA_TYPE_TX, 151562306a36Sopenharmony_ci .orrc = 16, 151662306a36Sopenharmony_ci .chan_fc = true, 151762306a36Sopenharmony_ci .desc_fod = true, 151862306a36Sopenharmony_ci .desc_in_sram = true, 151962306a36Sopenharmony_ci .valid_desc_fetch_ack = true, 152062306a36Sopenharmony_ci}; 152162306a36Sopenharmony_ci 152262306a36Sopenharmony_cistatic const struct ldma_inst_data dma3 = { 152362306a36Sopenharmony_ci .name = "dma3", 152462306a36Sopenharmony_ci .type = DMA_TYPE_MCPY, 152562306a36Sopenharmony_ci .orrc = 16, 152662306a36Sopenharmony_ci .chan_fc = false, 152762306a36Sopenharmony_ci .desc_fod = false, 152862306a36Sopenharmony_ci .desc_in_sram = true, 152962306a36Sopenharmony_ci .valid_desc_fetch_ack = false, 153062306a36Sopenharmony_ci}; 153162306a36Sopenharmony_ci 153262306a36Sopenharmony_cistatic const struct ldma_inst_data toe_dma30 = { 153362306a36Sopenharmony_ci .name = "toe_dma30", 153462306a36Sopenharmony_ci .type = DMA_TYPE_MCPY, 153562306a36Sopenharmony_ci .orrc = 16, 153662306a36Sopenharmony_ci .chan_fc = false, 153762306a36Sopenharmony_ci .desc_fod = false, 153862306a36Sopenharmony_ci .desc_in_sram = true, 153962306a36Sopenharmony_ci .valid_desc_fetch_ack = true, 154062306a36Sopenharmony_ci}; 154162306a36Sopenharmony_ci 154262306a36Sopenharmony_cistatic const struct ldma_inst_data toe_dma31 = { 154362306a36Sopenharmony_ci .name = "toe_dma31", 154462306a36Sopenharmony_ci .type = DMA_TYPE_MCPY, 154562306a36Sopenharmony_ci .orrc = 16, 154662306a36Sopenharmony_ci .chan_fc = false, 154762306a36Sopenharmony_ci .desc_fod = false, 154862306a36Sopenharmony_ci .desc_in_sram = true, 154962306a36Sopenharmony_ci .valid_desc_fetch_ack = true, 155062306a36Sopenharmony_ci}; 155162306a36Sopenharmony_ci 155262306a36Sopenharmony_cistatic const struct of_device_id intel_ldma_match[] = { 155362306a36Sopenharmony_ci { .compatible = "intel,lgm-cdma", .data = &dma0}, 155462306a36Sopenharmony_ci { .compatible = "intel,lgm-dma2tx", .data = &dma2tx}, 155562306a36Sopenharmony_ci { .compatible = "intel,lgm-dma1rx", .data = &dma1rx}, 155662306a36Sopenharmony_ci { .compatible = "intel,lgm-dma1tx", .data = &dma1tx}, 155762306a36Sopenharmony_ci { .compatible = "intel,lgm-dma0tx", .data = &dma0tx}, 155862306a36Sopenharmony_ci { .compatible = "intel,lgm-dma3", .data = &dma3}, 155962306a36Sopenharmony_ci { .compatible = "intel,lgm-toe-dma30", .data = &toe_dma30}, 156062306a36Sopenharmony_ci { .compatible = "intel,lgm-toe-dma31", .data = &toe_dma31}, 156162306a36Sopenharmony_ci {} 156262306a36Sopenharmony_ci}; 156362306a36Sopenharmony_ci 156462306a36Sopenharmony_cistatic int intel_ldma_probe(struct platform_device *pdev) 156562306a36Sopenharmony_ci{ 156662306a36Sopenharmony_ci struct device *dev = &pdev->dev; 156762306a36Sopenharmony_ci struct dma_device *dma_dev; 156862306a36Sopenharmony_ci unsigned long ch_mask; 156962306a36Sopenharmony_ci struct ldma_chan *c; 157062306a36Sopenharmony_ci struct ldma_port *p; 157162306a36Sopenharmony_ci struct ldma_dev *d; 157262306a36Sopenharmony_ci u32 id, bitn = 32, j; 157362306a36Sopenharmony_ci int i, ret; 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_ci d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); 157662306a36Sopenharmony_ci if (!d) 157762306a36Sopenharmony_ci return -ENOMEM; 157862306a36Sopenharmony_ci 157962306a36Sopenharmony_ci /* Link controller to platform device */ 158062306a36Sopenharmony_ci d->dev = &pdev->dev; 158162306a36Sopenharmony_ci 158262306a36Sopenharmony_ci d->inst = device_get_match_data(dev); 158362306a36Sopenharmony_ci if (!d->inst) { 158462306a36Sopenharmony_ci dev_err(dev, "No device match found\n"); 158562306a36Sopenharmony_ci return -ENODEV; 158662306a36Sopenharmony_ci } 158762306a36Sopenharmony_ci 158862306a36Sopenharmony_ci d->base = devm_platform_ioremap_resource(pdev, 0); 158962306a36Sopenharmony_ci if (IS_ERR(d->base)) 159062306a36Sopenharmony_ci return PTR_ERR(d->base); 159162306a36Sopenharmony_ci 159262306a36Sopenharmony_ci /* Power up and reset the dma engine, some DMAs always on?? */ 159362306a36Sopenharmony_ci d->core_clk = devm_clk_get_optional(dev, NULL); 159462306a36Sopenharmony_ci if (IS_ERR(d->core_clk)) 159562306a36Sopenharmony_ci return PTR_ERR(d->core_clk); 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci d->rst = devm_reset_control_get_optional(dev, NULL); 159862306a36Sopenharmony_ci if (IS_ERR(d->rst)) 159962306a36Sopenharmony_ci return PTR_ERR(d->rst); 160062306a36Sopenharmony_ci 160162306a36Sopenharmony_ci clk_prepare_enable(d->core_clk); 160262306a36Sopenharmony_ci reset_control_deassert(d->rst); 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci ret = devm_add_action_or_reset(dev, ldma_clk_disable, d); 160562306a36Sopenharmony_ci if (ret) { 160662306a36Sopenharmony_ci dev_err(dev, "Failed to devm_add_action_or_reset, %d\n", ret); 160762306a36Sopenharmony_ci return ret; 160862306a36Sopenharmony_ci } 160962306a36Sopenharmony_ci 161062306a36Sopenharmony_ci id = readl(d->base + DMA_ID); 161162306a36Sopenharmony_ci d->chan_nrs = FIELD_GET(DMA_ID_CHNR, id); 161262306a36Sopenharmony_ci d->port_nrs = FIELD_GET(DMA_ID_PNR, id); 161362306a36Sopenharmony_ci d->ver = FIELD_GET(DMA_ID_REV, id); 161462306a36Sopenharmony_ci 161562306a36Sopenharmony_ci if (id & DMA_ID_AW_36B) 161662306a36Sopenharmony_ci d->flags |= DMA_ADDR_36BIT; 161762306a36Sopenharmony_ci 161862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_64BIT) && (id & DMA_ID_AW_36B)) 161962306a36Sopenharmony_ci bitn = 36; 162062306a36Sopenharmony_ci 162162306a36Sopenharmony_ci if (id & DMA_ID_DW_128B) 162262306a36Sopenharmony_ci d->flags |= DMA_DATA_128BIT; 162362306a36Sopenharmony_ci 162462306a36Sopenharmony_ci ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(bitn)); 162562306a36Sopenharmony_ci if (ret) { 162662306a36Sopenharmony_ci dev_err(dev, "No usable DMA configuration\n"); 162762306a36Sopenharmony_ci return ret; 162862306a36Sopenharmony_ci } 162962306a36Sopenharmony_ci 163062306a36Sopenharmony_ci if (d->ver == DMA_VER22) { 163162306a36Sopenharmony_ci ret = ldma_init_v22(d, pdev); 163262306a36Sopenharmony_ci if (ret) 163362306a36Sopenharmony_ci return ret; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci ret = device_property_read_u32(dev, "dma-channel-mask", &d->channels_mask); 163762306a36Sopenharmony_ci if (ret < 0) 163862306a36Sopenharmony_ci d->channels_mask = GENMASK(d->chan_nrs - 1, 0); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci dma_dev = &d->dma_dev; 164162306a36Sopenharmony_ci 164262306a36Sopenharmony_ci dma_cap_zero(dma_dev->cap_mask); 164362306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, dma_dev->cap_mask); 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci /* Channel initializations */ 164662306a36Sopenharmony_ci INIT_LIST_HEAD(&dma_dev->channels); 164762306a36Sopenharmony_ci 164862306a36Sopenharmony_ci /* Port Initializations */ 164962306a36Sopenharmony_ci d->ports = devm_kcalloc(dev, d->port_nrs, sizeof(*p), GFP_KERNEL); 165062306a36Sopenharmony_ci if (!d->ports) 165162306a36Sopenharmony_ci return -ENOMEM; 165262306a36Sopenharmony_ci 165362306a36Sopenharmony_ci /* Channels Initializations */ 165462306a36Sopenharmony_ci d->chans = devm_kcalloc(d->dev, d->chan_nrs, sizeof(*c), GFP_KERNEL); 165562306a36Sopenharmony_ci if (!d->chans) 165662306a36Sopenharmony_ci return -ENOMEM; 165762306a36Sopenharmony_ci 165862306a36Sopenharmony_ci for (i = 0; i < d->port_nrs; i++) { 165962306a36Sopenharmony_ci p = &d->ports[i]; 166062306a36Sopenharmony_ci p->portid = i; 166162306a36Sopenharmony_ci p->ldev = d; 166262306a36Sopenharmony_ci } 166362306a36Sopenharmony_ci 166462306a36Sopenharmony_ci dma_dev->dev = &pdev->dev; 166562306a36Sopenharmony_ci 166662306a36Sopenharmony_ci ch_mask = (unsigned long)d->channels_mask; 166762306a36Sopenharmony_ci for_each_set_bit(j, &ch_mask, d->chan_nrs) { 166862306a36Sopenharmony_ci if (d->ver == DMA_VER22) 166962306a36Sopenharmony_ci ldma_dma_init_v22(j, d); 167062306a36Sopenharmony_ci else 167162306a36Sopenharmony_ci ldma_dma_init_v3X(j, d); 167262306a36Sopenharmony_ci } 167362306a36Sopenharmony_ci 167462306a36Sopenharmony_ci ret = ldma_parse_dt(d); 167562306a36Sopenharmony_ci if (ret) 167662306a36Sopenharmony_ci return ret; 167762306a36Sopenharmony_ci 167862306a36Sopenharmony_ci dma_dev->device_alloc_chan_resources = ldma_alloc_chan_resources; 167962306a36Sopenharmony_ci dma_dev->device_free_chan_resources = ldma_free_chan_resources; 168062306a36Sopenharmony_ci dma_dev->device_terminate_all = ldma_terminate_all; 168162306a36Sopenharmony_ci dma_dev->device_issue_pending = ldma_issue_pending; 168262306a36Sopenharmony_ci dma_dev->device_tx_status = ldma_tx_status; 168362306a36Sopenharmony_ci dma_dev->device_resume = ldma_resume_chan; 168462306a36Sopenharmony_ci dma_dev->device_pause = ldma_pause_chan; 168562306a36Sopenharmony_ci dma_dev->device_prep_slave_sg = ldma_prep_slave_sg; 168662306a36Sopenharmony_ci 168762306a36Sopenharmony_ci if (d->ver == DMA_VER22) { 168862306a36Sopenharmony_ci dma_dev->device_config = ldma_slave_config; 168962306a36Sopenharmony_ci dma_dev->device_synchronize = ldma_synchronize; 169062306a36Sopenharmony_ci dma_dev->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 169162306a36Sopenharmony_ci dma_dev->dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES); 169262306a36Sopenharmony_ci dma_dev->directions = BIT(DMA_MEM_TO_DEV) | 169362306a36Sopenharmony_ci BIT(DMA_DEV_TO_MEM); 169462306a36Sopenharmony_ci dma_dev->residue_granularity = 169562306a36Sopenharmony_ci DMA_RESIDUE_GRANULARITY_DESCRIPTOR; 169662306a36Sopenharmony_ci } 169762306a36Sopenharmony_ci 169862306a36Sopenharmony_ci platform_set_drvdata(pdev, d); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci ldma_dev_init(d); 170162306a36Sopenharmony_ci 170262306a36Sopenharmony_ci ret = dma_async_device_register(dma_dev); 170362306a36Sopenharmony_ci if (ret) { 170462306a36Sopenharmony_ci dev_err(dev, "Failed to register slave DMA engine device\n"); 170562306a36Sopenharmony_ci return ret; 170662306a36Sopenharmony_ci } 170762306a36Sopenharmony_ci 170862306a36Sopenharmony_ci ret = of_dma_controller_register(pdev->dev.of_node, ldma_xlate, d); 170962306a36Sopenharmony_ci if (ret) { 171062306a36Sopenharmony_ci dev_err(dev, "Failed to register of DMA controller\n"); 171162306a36Sopenharmony_ci dma_async_device_unregister(dma_dev); 171262306a36Sopenharmony_ci return ret; 171362306a36Sopenharmony_ci } 171462306a36Sopenharmony_ci 171562306a36Sopenharmony_ci dev_info(dev, "Init done - rev: %x, ports: %d channels: %d\n", d->ver, 171662306a36Sopenharmony_ci d->port_nrs, d->chan_nrs); 171762306a36Sopenharmony_ci 171862306a36Sopenharmony_ci return 0; 171962306a36Sopenharmony_ci} 172062306a36Sopenharmony_ci 172162306a36Sopenharmony_cistatic struct platform_driver intel_ldma_driver = { 172262306a36Sopenharmony_ci .probe = intel_ldma_probe, 172362306a36Sopenharmony_ci .driver = { 172462306a36Sopenharmony_ci .name = DRIVER_NAME, 172562306a36Sopenharmony_ci .of_match_table = intel_ldma_match, 172662306a36Sopenharmony_ci }, 172762306a36Sopenharmony_ci}; 172862306a36Sopenharmony_ci 172962306a36Sopenharmony_ci/* 173062306a36Sopenharmony_ci * Perform this driver as device_initcall to make sure initialization happens 173162306a36Sopenharmony_ci * before its DMA clients of some are platform specific and also to provide 173262306a36Sopenharmony_ci * registered DMA channels and DMA capabilities to clients before their 173362306a36Sopenharmony_ci * initialization. 173462306a36Sopenharmony_ci */ 173562306a36Sopenharmony_cibuiltin_platform_driver(intel_ldma_driver); 1736