162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci#include <linux/delay.h> 362306a36Sopenharmony_ci#include <linux/dmaengine.h> 462306a36Sopenharmony_ci#include <linux/dma-mapping.h> 562306a36Sopenharmony_ci#include <linux/platform_device.h> 662306a36Sopenharmony_ci#include <linux/module.h> 762306a36Sopenharmony_ci#include <linux/of.h> 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/of_dma.h> 1062306a36Sopenharmony_ci#include <linux/of_irq.h> 1162306a36Sopenharmony_ci#include <linux/dmapool.h> 1262306a36Sopenharmony_ci#include <linux/interrupt.h> 1362306a36Sopenharmony_ci#include <linux/of_address.h> 1462306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1562306a36Sopenharmony_ci#include "../dmaengine.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#define DESC_TYPE 27 1862306a36Sopenharmony_ci#define DESC_TYPE_HOST 0x10 1962306a36Sopenharmony_ci#define DESC_TYPE_TEARD 0x13 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#define TD_DESC_IS_RX (1 << 16) 2262306a36Sopenharmony_ci#define TD_DESC_DMA_NUM 10 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define DESC_LENGTH_BITS_NUM 21 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define DESC_TYPE_USB (5 << 26) 2762306a36Sopenharmony_ci#define DESC_PD_COMPLETE (1 << 31) 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci/* DMA engine */ 3062306a36Sopenharmony_ci#define DMA_TDFDQ 4 3162306a36Sopenharmony_ci#define DMA_TXGCR(x) (0x800 + (x) * 0x20) 3262306a36Sopenharmony_ci#define DMA_RXGCR(x) (0x808 + (x) * 0x20) 3362306a36Sopenharmony_ci#define RXHPCRA0 4 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci#define GCR_CHAN_ENABLE (1 << 31) 3662306a36Sopenharmony_ci#define GCR_TEARDOWN (1 << 30) 3762306a36Sopenharmony_ci#define GCR_STARV_RETRY (1 << 24) 3862306a36Sopenharmony_ci#define GCR_DESC_TYPE_HOST (1 << 14) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* DMA scheduler */ 4162306a36Sopenharmony_ci#define DMA_SCHED_CTRL 0 4262306a36Sopenharmony_ci#define DMA_SCHED_CTRL_EN (1 << 31) 4362306a36Sopenharmony_ci#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800) 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci#define SCHED_ENTRY0_CHAN(x) ((x) << 0) 4662306a36Sopenharmony_ci#define SCHED_ENTRY0_IS_RX (1 << 7) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define SCHED_ENTRY1_CHAN(x) ((x) << 8) 4962306a36Sopenharmony_ci#define SCHED_ENTRY1_IS_RX (1 << 15) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define SCHED_ENTRY2_CHAN(x) ((x) << 16) 5262306a36Sopenharmony_ci#define SCHED_ENTRY2_IS_RX (1 << 23) 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci#define SCHED_ENTRY3_CHAN(x) ((x) << 24) 5562306a36Sopenharmony_ci#define SCHED_ENTRY3_IS_RX (1 << 31) 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci/* Queue manager */ 5862306a36Sopenharmony_ci/* 4 KiB of memory for descriptors, 2 for each endpoint */ 5962306a36Sopenharmony_ci#define ALLOC_DECS_NUM 128 6062306a36Sopenharmony_ci#define DESCS_AREAS 1 6162306a36Sopenharmony_ci#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS) 6262306a36Sopenharmony_ci#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci#define QMGR_LRAM0_BASE 0x80 6562306a36Sopenharmony_ci#define QMGR_LRAM_SIZE 0x84 6662306a36Sopenharmony_ci#define QMGR_LRAM1_BASE 0x88 6762306a36Sopenharmony_ci#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10) 6862306a36Sopenharmony_ci#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10) 6962306a36Sopenharmony_ci#define QMGR_MEMCTRL_IDX_SH 16 7062306a36Sopenharmony_ci#define QMGR_MEMCTRL_DESC_SH 8 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci#define QMGR_PEND(x) (0x90 + (x) * 4) 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci#define QMGR_PENDING_SLOT_Q(x) (x / 32) 7562306a36Sopenharmony_ci#define QMGR_PENDING_BIT_Q(x) (x % 32) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10) 7862306a36Sopenharmony_ci#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10) 7962306a36Sopenharmony_ci#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) 8062306a36Sopenharmony_ci#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci/* Packet Descriptor */ 8362306a36Sopenharmony_ci#define PD2_ZERO_LENGTH (1 << 19) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cistruct cppi41_channel { 8662306a36Sopenharmony_ci struct dma_chan chan; 8762306a36Sopenharmony_ci struct dma_async_tx_descriptor txd; 8862306a36Sopenharmony_ci struct cppi41_dd *cdd; 8962306a36Sopenharmony_ci struct cppi41_desc *desc; 9062306a36Sopenharmony_ci dma_addr_t desc_phys; 9162306a36Sopenharmony_ci void __iomem *gcr_reg; 9262306a36Sopenharmony_ci int is_tx; 9362306a36Sopenharmony_ci u32 residue; 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci unsigned int q_num; 9662306a36Sopenharmony_ci unsigned int q_comp_num; 9762306a36Sopenharmony_ci unsigned int port_num; 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci unsigned td_retry; 10062306a36Sopenharmony_ci unsigned td_queued:1; 10162306a36Sopenharmony_ci unsigned td_seen:1; 10262306a36Sopenharmony_ci unsigned td_desc_seen:1; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci struct list_head node; /* Node for pending list */ 10562306a36Sopenharmony_ci}; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_cistruct cppi41_desc { 10862306a36Sopenharmony_ci u32 pd0; 10962306a36Sopenharmony_ci u32 pd1; 11062306a36Sopenharmony_ci u32 pd2; 11162306a36Sopenharmony_ci u32 pd3; 11262306a36Sopenharmony_ci u32 pd4; 11362306a36Sopenharmony_ci u32 pd5; 11462306a36Sopenharmony_ci u32 pd6; 11562306a36Sopenharmony_ci u32 pd7; 11662306a36Sopenharmony_ci} __aligned(32); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistruct chan_queues { 11962306a36Sopenharmony_ci u16 submit; 12062306a36Sopenharmony_ci u16 complete; 12162306a36Sopenharmony_ci}; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_cistruct cppi41_dd { 12462306a36Sopenharmony_ci struct dma_device ddev; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci void *qmgr_scratch; 12762306a36Sopenharmony_ci dma_addr_t scratch_phys; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci struct cppi41_desc *cd; 13062306a36Sopenharmony_ci dma_addr_t descs_phys; 13162306a36Sopenharmony_ci u32 first_td_desc; 13262306a36Sopenharmony_ci struct cppi41_channel *chan_busy[ALLOC_DECS_NUM]; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci void __iomem *ctrl_mem; 13562306a36Sopenharmony_ci void __iomem *sched_mem; 13662306a36Sopenharmony_ci void __iomem *qmgr_mem; 13762306a36Sopenharmony_ci unsigned int irq; 13862306a36Sopenharmony_ci const struct chan_queues *queues_rx; 13962306a36Sopenharmony_ci const struct chan_queues *queues_tx; 14062306a36Sopenharmony_ci struct chan_queues td_queue; 14162306a36Sopenharmony_ci u16 first_completion_queue; 14262306a36Sopenharmony_ci u16 qmgr_num_pend; 14362306a36Sopenharmony_ci u32 n_chans; 14462306a36Sopenharmony_ci u8 platform; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci struct list_head pending; /* Pending queued transfers */ 14762306a36Sopenharmony_ci spinlock_t lock; /* Lock for pending list */ 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* context for suspend/resume */ 15062306a36Sopenharmony_ci unsigned int dma_tdfdq; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci bool is_suspended; 15362306a36Sopenharmony_ci}; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic struct chan_queues am335x_usb_queues_tx[] = { 15662306a36Sopenharmony_ci /* USB0 ENDP 1 */ 15762306a36Sopenharmony_ci [ 0] = { .submit = 32, .complete = 93}, 15862306a36Sopenharmony_ci [ 1] = { .submit = 34, .complete = 94}, 15962306a36Sopenharmony_ci [ 2] = { .submit = 36, .complete = 95}, 16062306a36Sopenharmony_ci [ 3] = { .submit = 38, .complete = 96}, 16162306a36Sopenharmony_ci [ 4] = { .submit = 40, .complete = 97}, 16262306a36Sopenharmony_ci [ 5] = { .submit = 42, .complete = 98}, 16362306a36Sopenharmony_ci [ 6] = { .submit = 44, .complete = 99}, 16462306a36Sopenharmony_ci [ 7] = { .submit = 46, .complete = 100}, 16562306a36Sopenharmony_ci [ 8] = { .submit = 48, .complete = 101}, 16662306a36Sopenharmony_ci [ 9] = { .submit = 50, .complete = 102}, 16762306a36Sopenharmony_ci [10] = { .submit = 52, .complete = 103}, 16862306a36Sopenharmony_ci [11] = { .submit = 54, .complete = 104}, 16962306a36Sopenharmony_ci [12] = { .submit = 56, .complete = 105}, 17062306a36Sopenharmony_ci [13] = { .submit = 58, .complete = 106}, 17162306a36Sopenharmony_ci [14] = { .submit = 60, .complete = 107}, 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* USB1 ENDP1 */ 17462306a36Sopenharmony_ci [15] = { .submit = 62, .complete = 125}, 17562306a36Sopenharmony_ci [16] = { .submit = 64, .complete = 126}, 17662306a36Sopenharmony_ci [17] = { .submit = 66, .complete = 127}, 17762306a36Sopenharmony_ci [18] = { .submit = 68, .complete = 128}, 17862306a36Sopenharmony_ci [19] = { .submit = 70, .complete = 129}, 17962306a36Sopenharmony_ci [20] = { .submit = 72, .complete = 130}, 18062306a36Sopenharmony_ci [21] = { .submit = 74, .complete = 131}, 18162306a36Sopenharmony_ci [22] = { .submit = 76, .complete = 132}, 18262306a36Sopenharmony_ci [23] = { .submit = 78, .complete = 133}, 18362306a36Sopenharmony_ci [24] = { .submit = 80, .complete = 134}, 18462306a36Sopenharmony_ci [25] = { .submit = 82, .complete = 135}, 18562306a36Sopenharmony_ci [26] = { .submit = 84, .complete = 136}, 18662306a36Sopenharmony_ci [27] = { .submit = 86, .complete = 137}, 18762306a36Sopenharmony_ci [28] = { .submit = 88, .complete = 138}, 18862306a36Sopenharmony_ci [29] = { .submit = 90, .complete = 139}, 18962306a36Sopenharmony_ci}; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic const struct chan_queues am335x_usb_queues_rx[] = { 19262306a36Sopenharmony_ci /* USB0 ENDP 1 */ 19362306a36Sopenharmony_ci [ 0] = { .submit = 1, .complete = 109}, 19462306a36Sopenharmony_ci [ 1] = { .submit = 2, .complete = 110}, 19562306a36Sopenharmony_ci [ 2] = { .submit = 3, .complete = 111}, 19662306a36Sopenharmony_ci [ 3] = { .submit = 4, .complete = 112}, 19762306a36Sopenharmony_ci [ 4] = { .submit = 5, .complete = 113}, 19862306a36Sopenharmony_ci [ 5] = { .submit = 6, .complete = 114}, 19962306a36Sopenharmony_ci [ 6] = { .submit = 7, .complete = 115}, 20062306a36Sopenharmony_ci [ 7] = { .submit = 8, .complete = 116}, 20162306a36Sopenharmony_ci [ 8] = { .submit = 9, .complete = 117}, 20262306a36Sopenharmony_ci [ 9] = { .submit = 10, .complete = 118}, 20362306a36Sopenharmony_ci [10] = { .submit = 11, .complete = 119}, 20462306a36Sopenharmony_ci [11] = { .submit = 12, .complete = 120}, 20562306a36Sopenharmony_ci [12] = { .submit = 13, .complete = 121}, 20662306a36Sopenharmony_ci [13] = { .submit = 14, .complete = 122}, 20762306a36Sopenharmony_ci [14] = { .submit = 15, .complete = 123}, 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* USB1 ENDP 1 */ 21062306a36Sopenharmony_ci [15] = { .submit = 16, .complete = 141}, 21162306a36Sopenharmony_ci [16] = { .submit = 17, .complete = 142}, 21262306a36Sopenharmony_ci [17] = { .submit = 18, .complete = 143}, 21362306a36Sopenharmony_ci [18] = { .submit = 19, .complete = 144}, 21462306a36Sopenharmony_ci [19] = { .submit = 20, .complete = 145}, 21562306a36Sopenharmony_ci [20] = { .submit = 21, .complete = 146}, 21662306a36Sopenharmony_ci [21] = { .submit = 22, .complete = 147}, 21762306a36Sopenharmony_ci [22] = { .submit = 23, .complete = 148}, 21862306a36Sopenharmony_ci [23] = { .submit = 24, .complete = 149}, 21962306a36Sopenharmony_ci [24] = { .submit = 25, .complete = 150}, 22062306a36Sopenharmony_ci [25] = { .submit = 26, .complete = 151}, 22162306a36Sopenharmony_ci [26] = { .submit = 27, .complete = 152}, 22262306a36Sopenharmony_ci [27] = { .submit = 28, .complete = 153}, 22362306a36Sopenharmony_ci [28] = { .submit = 29, .complete = 154}, 22462306a36Sopenharmony_ci [29] = { .submit = 30, .complete = 155}, 22562306a36Sopenharmony_ci}; 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_tx[] = { 22862306a36Sopenharmony_ci [0] = { .submit = 16, .complete = 24}, 22962306a36Sopenharmony_ci [1] = { .submit = 18, .complete = 24}, 23062306a36Sopenharmony_ci [2] = { .submit = 20, .complete = 24}, 23162306a36Sopenharmony_ci [3] = { .submit = 22, .complete = 24}, 23262306a36Sopenharmony_ci}; 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_rx[] = { 23562306a36Sopenharmony_ci [0] = { .submit = 1, .complete = 26}, 23662306a36Sopenharmony_ci [1] = { .submit = 3, .complete = 26}, 23762306a36Sopenharmony_ci [2] = { .submit = 5, .complete = 26}, 23862306a36Sopenharmony_ci [3] = { .submit = 7, .complete = 26}, 23962306a36Sopenharmony_ci}; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistruct cppi_glue_infos { 24262306a36Sopenharmony_ci const struct chan_queues *queues_rx; 24362306a36Sopenharmony_ci const struct chan_queues *queues_tx; 24462306a36Sopenharmony_ci struct chan_queues td_queue; 24562306a36Sopenharmony_ci u16 first_completion_queue; 24662306a36Sopenharmony_ci u16 qmgr_num_pend; 24762306a36Sopenharmony_ci}; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_cistatic struct cppi41_channel *to_cpp41_chan(struct dma_chan *c) 25062306a36Sopenharmony_ci{ 25162306a36Sopenharmony_ci return container_of(c, struct cppi41_channel, chan); 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_cistatic struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) 25562306a36Sopenharmony_ci{ 25662306a36Sopenharmony_ci struct cppi41_channel *c; 25762306a36Sopenharmony_ci u32 descs_size; 25862306a36Sopenharmony_ci u32 desc_num; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM; 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci if (!((desc >= cdd->descs_phys) && 26362306a36Sopenharmony_ci (desc < (cdd->descs_phys + descs_size)))) { 26462306a36Sopenharmony_ci return NULL; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc); 26862306a36Sopenharmony_ci BUG_ON(desc_num >= ALLOC_DECS_NUM); 26962306a36Sopenharmony_ci c = cdd->chan_busy[desc_num]; 27062306a36Sopenharmony_ci cdd->chan_busy[desc_num] = NULL; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci /* Usecount for chan_busy[], paired with push_desc_queue() */ 27362306a36Sopenharmony_ci pm_runtime_put(cdd->ddev.dev); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci return c; 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_cistatic void cppi_writel(u32 val, void *__iomem *mem) 27962306a36Sopenharmony_ci{ 28062306a36Sopenharmony_ci __raw_writel(val, mem); 28162306a36Sopenharmony_ci} 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_cistatic u32 cppi_readl(void *__iomem *mem) 28462306a36Sopenharmony_ci{ 28562306a36Sopenharmony_ci return __raw_readl(mem); 28662306a36Sopenharmony_ci} 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_cistatic u32 pd_trans_len(u32 val) 28962306a36Sopenharmony_ci{ 29062306a36Sopenharmony_ci return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1); 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_cistatic u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num) 29462306a36Sopenharmony_ci{ 29562306a36Sopenharmony_ci u32 desc; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num)); 29862306a36Sopenharmony_ci desc &= ~0x1f; 29962306a36Sopenharmony_ci return desc; 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cistatic irqreturn_t cppi41_irq(int irq, void *data) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci struct cppi41_dd *cdd = data; 30562306a36Sopenharmony_ci u16 first_completion_queue = cdd->first_completion_queue; 30662306a36Sopenharmony_ci u16 qmgr_num_pend = cdd->qmgr_num_pend; 30762306a36Sopenharmony_ci struct cppi41_channel *c; 30862306a36Sopenharmony_ci int i; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci for (i = QMGR_PENDING_SLOT_Q(first_completion_queue); i < qmgr_num_pend; 31162306a36Sopenharmony_ci i++) { 31262306a36Sopenharmony_ci u32 val; 31362306a36Sopenharmony_ci u32 q_num; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i)); 31662306a36Sopenharmony_ci if (i == QMGR_PENDING_SLOT_Q(first_completion_queue) && val) { 31762306a36Sopenharmony_ci u32 mask; 31862306a36Sopenharmony_ci /* set corresponding bit for completion Q 93 */ 31962306a36Sopenharmony_ci mask = 1 << QMGR_PENDING_BIT_Q(first_completion_queue); 32062306a36Sopenharmony_ci /* not set all bits for queues less than Q 93 */ 32162306a36Sopenharmony_ci mask--; 32262306a36Sopenharmony_ci /* now invert and keep only Q 93+ set */ 32362306a36Sopenharmony_ci val &= ~mask; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci if (val) 32762306a36Sopenharmony_ci __iormb(); 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci while (val) { 33062306a36Sopenharmony_ci u32 desc, len; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci /* 33362306a36Sopenharmony_ci * This should never trigger, see the comments in 33462306a36Sopenharmony_ci * push_desc_queue() 33562306a36Sopenharmony_ci */ 33662306a36Sopenharmony_ci WARN_ON(cdd->is_suspended); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci q_num = __fls(val); 33962306a36Sopenharmony_ci val &= ~(1 << q_num); 34062306a36Sopenharmony_ci q_num += 32 * i; 34162306a36Sopenharmony_ci desc = cppi41_pop_desc(cdd, q_num); 34262306a36Sopenharmony_ci c = desc_to_chan(cdd, desc); 34362306a36Sopenharmony_ci if (WARN_ON(!c)) { 34462306a36Sopenharmony_ci pr_err("%s() q %d desc %08x\n", __func__, 34562306a36Sopenharmony_ci q_num, desc); 34662306a36Sopenharmony_ci continue; 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci if (c->desc->pd2 & PD2_ZERO_LENGTH) 35062306a36Sopenharmony_ci len = 0; 35162306a36Sopenharmony_ci else 35262306a36Sopenharmony_ci len = pd_trans_len(c->desc->pd0); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci c->residue = pd_trans_len(c->desc->pd6) - len; 35562306a36Sopenharmony_ci dma_cookie_complete(&c->txd); 35662306a36Sopenharmony_ci dmaengine_desc_get_callback_invoke(&c->txd, NULL); 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci return IRQ_HANDLED; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci dma_cookie_t cookie; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci cookie = dma_cookie_assign(tx); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci return cookie; 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_cistatic int cppi41_dma_alloc_chan_resources(struct dma_chan *chan) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 37462306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 37562306a36Sopenharmony_ci int error; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci error = pm_runtime_get_sync(cdd->ddev.dev); 37862306a36Sopenharmony_ci if (error < 0) { 37962306a36Sopenharmony_ci dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n", 38062306a36Sopenharmony_ci __func__, error); 38162306a36Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci return error; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci dma_cookie_init(chan); 38762306a36Sopenharmony_ci dma_async_tx_descriptor_init(&c->txd, chan); 38862306a36Sopenharmony_ci c->txd.tx_submit = cppi41_tx_submit; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (!c->is_tx) 39162306a36Sopenharmony_ci cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 39462306a36Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci return 0; 39762306a36Sopenharmony_ci} 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_cistatic void cppi41_dma_free_chan_resources(struct dma_chan *chan) 40062306a36Sopenharmony_ci{ 40162306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 40262306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 40362306a36Sopenharmony_ci int error; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci error = pm_runtime_get_sync(cdd->ddev.dev); 40662306a36Sopenharmony_ci if (error < 0) { 40762306a36Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci return; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci WARN_ON(!list_empty(&cdd->pending)); 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 41562306a36Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 41662306a36Sopenharmony_ci} 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_cistatic enum dma_status cppi41_dma_tx_status(struct dma_chan *chan, 41962306a36Sopenharmony_ci dma_cookie_t cookie, struct dma_tx_state *txstate) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 42262306a36Sopenharmony_ci enum dma_status ret; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci dma_set_residue(txstate, c->residue); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci return ret; 42962306a36Sopenharmony_ci} 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_cistatic void push_desc_queue(struct cppi41_channel *c) 43262306a36Sopenharmony_ci{ 43362306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 43462306a36Sopenharmony_ci u32 desc_num; 43562306a36Sopenharmony_ci u32 desc_phys; 43662306a36Sopenharmony_ci u32 reg; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci c->residue = 0; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci reg = GCR_CHAN_ENABLE; 44162306a36Sopenharmony_ci if (!c->is_tx) { 44262306a36Sopenharmony_ci reg |= GCR_STARV_RETRY; 44362306a36Sopenharmony_ci reg |= GCR_DESC_TYPE_HOST; 44462306a36Sopenharmony_ci reg |= c->q_comp_num; 44562306a36Sopenharmony_ci } 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci cppi_writel(reg, c->gcr_reg); 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci /* 45062306a36Sopenharmony_ci * We don't use writel() but __raw_writel() so we have to make sure 45162306a36Sopenharmony_ci * that the DMA descriptor in coherent memory made to the main memory 45262306a36Sopenharmony_ci * before starting the dma engine. 45362306a36Sopenharmony_ci */ 45462306a36Sopenharmony_ci __iowmb(); 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci /* 45762306a36Sopenharmony_ci * DMA transfers can take at least 200ms to complete with USB mass 45862306a36Sopenharmony_ci * storage connected. To prevent autosuspend timeouts, we must use 45962306a36Sopenharmony_ci * pm_runtime_get/put() when chan_busy[] is modified. This will get 46062306a36Sopenharmony_ci * cleared in desc_to_chan() or cppi41_stop_chan() depending on the 46162306a36Sopenharmony_ci * outcome of the transfer. 46262306a36Sopenharmony_ci */ 46362306a36Sopenharmony_ci pm_runtime_get(cdd->ddev.dev); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci desc_phys = lower_32_bits(c->desc_phys); 46662306a36Sopenharmony_ci desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); 46762306a36Sopenharmony_ci WARN_ON(cdd->chan_busy[desc_num]); 46862306a36Sopenharmony_ci cdd->chan_busy[desc_num] = c; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci reg = (sizeof(struct cppi41_desc) - 24) / 4; 47162306a36Sopenharmony_ci reg |= desc_phys; 47262306a36Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Caller must hold cdd->lock to prevent push_desc_queue() 47762306a36Sopenharmony_ci * getting called out of order. We have both cppi41_dma_issue_pending() 47862306a36Sopenharmony_ci * and cppi41_runtime_resume() call this function. 47962306a36Sopenharmony_ci */ 48062306a36Sopenharmony_cistatic void cppi41_run_queue(struct cppi41_dd *cdd) 48162306a36Sopenharmony_ci{ 48262306a36Sopenharmony_ci struct cppi41_channel *c, *_c; 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci list_for_each_entry_safe(c, _c, &cdd->pending, node) { 48562306a36Sopenharmony_ci push_desc_queue(c); 48662306a36Sopenharmony_ci list_del(&c->node); 48762306a36Sopenharmony_ci } 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_cistatic void cppi41_dma_issue_pending(struct dma_chan *chan) 49162306a36Sopenharmony_ci{ 49262306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 49362306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 49462306a36Sopenharmony_ci unsigned long flags; 49562306a36Sopenharmony_ci int error; 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci error = pm_runtime_get(cdd->ddev.dev); 49862306a36Sopenharmony_ci if ((error != -EINPROGRESS) && error < 0) { 49962306a36Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 50062306a36Sopenharmony_ci dev_err(cdd->ddev.dev, "Failed to pm_runtime_get: %i\n", 50162306a36Sopenharmony_ci error); 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci return; 50462306a36Sopenharmony_ci } 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 50762306a36Sopenharmony_ci list_add_tail(&c->node, &cdd->pending); 50862306a36Sopenharmony_ci if (!cdd->is_suspended) 50962306a36Sopenharmony_ci cppi41_run_queue(cdd); 51062306a36Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 51362306a36Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_cistatic u32 get_host_pd0(u32 length) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci u32 reg; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci reg = DESC_TYPE_HOST << DESC_TYPE; 52162306a36Sopenharmony_ci reg |= length; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci return reg; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic u32 get_host_pd1(struct cppi41_channel *c) 52762306a36Sopenharmony_ci{ 52862306a36Sopenharmony_ci u32 reg; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci reg = 0; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci return reg; 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic u32 get_host_pd2(struct cppi41_channel *c) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci u32 reg; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci reg = DESC_TYPE_USB; 54062306a36Sopenharmony_ci reg |= c->q_comp_num; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci return reg; 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_cistatic u32 get_host_pd3(u32 length) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci u32 reg; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci /* PD3 = packet size */ 55062306a36Sopenharmony_ci reg = length; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci return reg; 55362306a36Sopenharmony_ci} 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_cistatic u32 get_host_pd6(u32 length) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci u32 reg; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci /* PD6 buffer size */ 56062306a36Sopenharmony_ci reg = DESC_PD_COMPLETE; 56162306a36Sopenharmony_ci reg |= length; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return reg; 56462306a36Sopenharmony_ci} 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_cistatic u32 get_host_pd4_or_7(u32 addr) 56762306a36Sopenharmony_ci{ 56862306a36Sopenharmony_ci u32 reg; 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci reg = addr; 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci return reg; 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_cistatic u32 get_host_pd5(void) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci u32 reg; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci reg = 0; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return reg; 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg( 58562306a36Sopenharmony_ci struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len, 58662306a36Sopenharmony_ci enum dma_transfer_direction dir, unsigned long tx_flags, void *context) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 58962306a36Sopenharmony_ci struct dma_async_tx_descriptor *txd = NULL; 59062306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 59162306a36Sopenharmony_ci struct cppi41_desc *d; 59262306a36Sopenharmony_ci struct scatterlist *sg; 59362306a36Sopenharmony_ci unsigned int i; 59462306a36Sopenharmony_ci int error; 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci error = pm_runtime_get(cdd->ddev.dev); 59762306a36Sopenharmony_ci if (error < 0) { 59862306a36Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci return NULL; 60162306a36Sopenharmony_ci } 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci if (cdd->is_suspended) 60462306a36Sopenharmony_ci goto err_out_not_ready; 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_ci d = c->desc; 60762306a36Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 60862306a36Sopenharmony_ci u32 addr; 60962306a36Sopenharmony_ci u32 len; 61062306a36Sopenharmony_ci 61162306a36Sopenharmony_ci /* We need to use more than one desc once musb supports sg */ 61262306a36Sopenharmony_ci addr = lower_32_bits(sg_dma_address(sg)); 61362306a36Sopenharmony_ci len = sg_dma_len(sg); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci d->pd0 = get_host_pd0(len); 61662306a36Sopenharmony_ci d->pd1 = get_host_pd1(c); 61762306a36Sopenharmony_ci d->pd2 = get_host_pd2(c); 61862306a36Sopenharmony_ci d->pd3 = get_host_pd3(len); 61962306a36Sopenharmony_ci d->pd4 = get_host_pd4_or_7(addr); 62062306a36Sopenharmony_ci d->pd5 = get_host_pd5(); 62162306a36Sopenharmony_ci d->pd6 = get_host_pd6(len); 62262306a36Sopenharmony_ci d->pd7 = get_host_pd4_or_7(addr); 62362306a36Sopenharmony_ci 62462306a36Sopenharmony_ci d++; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci txd = &c->txd; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_cierr_out_not_ready: 63062306a36Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 63162306a36Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci return txd; 63462306a36Sopenharmony_ci} 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_cistatic void cppi41_compute_td_desc(struct cppi41_desc *d) 63762306a36Sopenharmony_ci{ 63862306a36Sopenharmony_ci d->pd0 = DESC_TYPE_TEARD << DESC_TYPE; 63962306a36Sopenharmony_ci} 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_cistatic int cppi41_tear_down_chan(struct cppi41_channel *c) 64262306a36Sopenharmony_ci{ 64362306a36Sopenharmony_ci struct dmaengine_result abort_result; 64462306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 64562306a36Sopenharmony_ci struct cppi41_desc *td; 64662306a36Sopenharmony_ci u32 reg; 64762306a36Sopenharmony_ci u32 desc_phys; 64862306a36Sopenharmony_ci u32 td_desc_phys; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci td = cdd->cd; 65162306a36Sopenharmony_ci td += cdd->first_td_desc; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci td_desc_phys = cdd->descs_phys; 65462306a36Sopenharmony_ci td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci if (!c->td_queued) { 65762306a36Sopenharmony_ci cppi41_compute_td_desc(td); 65862306a36Sopenharmony_ci __iowmb(); 65962306a36Sopenharmony_ci 66062306a36Sopenharmony_ci reg = (sizeof(struct cppi41_desc) - 24) / 4; 66162306a36Sopenharmony_ci reg |= td_desc_phys; 66262306a36Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + 66362306a36Sopenharmony_ci QMGR_QUEUE_D(cdd->td_queue.submit)); 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci reg = GCR_CHAN_ENABLE; 66662306a36Sopenharmony_ci if (!c->is_tx) { 66762306a36Sopenharmony_ci reg |= GCR_STARV_RETRY; 66862306a36Sopenharmony_ci reg |= GCR_DESC_TYPE_HOST; 66962306a36Sopenharmony_ci reg |= cdd->td_queue.complete; 67062306a36Sopenharmony_ci } 67162306a36Sopenharmony_ci reg |= GCR_TEARDOWN; 67262306a36Sopenharmony_ci cppi_writel(reg, c->gcr_reg); 67362306a36Sopenharmony_ci c->td_queued = 1; 67462306a36Sopenharmony_ci c->td_retry = 500; 67562306a36Sopenharmony_ci } 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (!c->td_seen || !c->td_desc_seen) { 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, cdd->td_queue.complete); 68062306a36Sopenharmony_ci if (!desc_phys && c->is_tx) 68162306a36Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci if (desc_phys == c->desc_phys) { 68462306a36Sopenharmony_ci c->td_desc_seen = 1; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci } else if (desc_phys == td_desc_phys) { 68762306a36Sopenharmony_ci u32 pd0; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci __iormb(); 69062306a36Sopenharmony_ci pd0 = td->pd0; 69162306a36Sopenharmony_ci WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD); 69262306a36Sopenharmony_ci WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX)); 69362306a36Sopenharmony_ci WARN_ON((pd0 & 0x1f) != c->port_num); 69462306a36Sopenharmony_ci c->td_seen = 1; 69562306a36Sopenharmony_ci } else if (desc_phys) { 69662306a36Sopenharmony_ci WARN_ON_ONCE(1); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } 69962306a36Sopenharmony_ci c->td_retry--; 70062306a36Sopenharmony_ci /* 70162306a36Sopenharmony_ci * If the TX descriptor / channel is in use, the caller needs to poke 70262306a36Sopenharmony_ci * his TD bit multiple times. After that he hardware releases the 70362306a36Sopenharmony_ci * transfer descriptor followed by TD descriptor. Waiting seems not to 70462306a36Sopenharmony_ci * cause any difference. 70562306a36Sopenharmony_ci * RX seems to be thrown out right away. However once the TearDown 70662306a36Sopenharmony_ci * descriptor gets through we are done. If we have seen the transfer 70762306a36Sopenharmony_ci * descriptor before the TD we fetch it from enqueue, it has to be 70862306a36Sopenharmony_ci * there waiting for us. 70962306a36Sopenharmony_ci */ 71062306a36Sopenharmony_ci if (!c->td_seen && c->td_retry) { 71162306a36Sopenharmony_ci udelay(1); 71262306a36Sopenharmony_ci return -EAGAIN; 71362306a36Sopenharmony_ci } 71462306a36Sopenharmony_ci WARN_ON(!c->td_retry); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_ci if (!c->td_desc_seen) { 71762306a36Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_num); 71862306a36Sopenharmony_ci if (!desc_phys) 71962306a36Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); 72062306a36Sopenharmony_ci WARN_ON(!desc_phys); 72162306a36Sopenharmony_ci } 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci c->td_queued = 0; 72462306a36Sopenharmony_ci c->td_seen = 0; 72562306a36Sopenharmony_ci c->td_desc_seen = 0; 72662306a36Sopenharmony_ci cppi_writel(0, c->gcr_reg); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* Invoke the callback to do the necessary clean-up */ 72962306a36Sopenharmony_ci abort_result.result = DMA_TRANS_ABORTED; 73062306a36Sopenharmony_ci dma_cookie_complete(&c->txd); 73162306a36Sopenharmony_ci dmaengine_desc_get_callback_invoke(&c->txd, &abort_result); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci return 0; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_cistatic int cppi41_stop_chan(struct dma_chan *chan) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 73962306a36Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 74062306a36Sopenharmony_ci u32 desc_num; 74162306a36Sopenharmony_ci u32 desc_phys; 74262306a36Sopenharmony_ci int ret; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci desc_phys = lower_32_bits(c->desc_phys); 74562306a36Sopenharmony_ci desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); 74662306a36Sopenharmony_ci if (!cdd->chan_busy[desc_num]) { 74762306a36Sopenharmony_ci struct cppi41_channel *cc, *_ct; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci /* 75062306a36Sopenharmony_ci * channels might still be in the pending list if 75162306a36Sopenharmony_ci * cppi41_dma_issue_pending() is called after 75262306a36Sopenharmony_ci * cppi41_runtime_suspend() is called 75362306a36Sopenharmony_ci */ 75462306a36Sopenharmony_ci list_for_each_entry_safe(cc, _ct, &cdd->pending, node) { 75562306a36Sopenharmony_ci if (cc != c) 75662306a36Sopenharmony_ci continue; 75762306a36Sopenharmony_ci list_del(&cc->node); 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci } 76062306a36Sopenharmony_ci return 0; 76162306a36Sopenharmony_ci } 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci ret = cppi41_tear_down_chan(c); 76462306a36Sopenharmony_ci if (ret) 76562306a36Sopenharmony_ci return ret; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci WARN_ON(!cdd->chan_busy[desc_num]); 76862306a36Sopenharmony_ci cdd->chan_busy[desc_num] = NULL; 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci /* Usecount for chan_busy[], paired with push_desc_queue() */ 77162306a36Sopenharmony_ci pm_runtime_put(cdd->ddev.dev); 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci return 0; 77462306a36Sopenharmony_ci} 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_cistatic int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci struct cppi41_channel *cchan, *chans; 77962306a36Sopenharmony_ci int i; 78062306a36Sopenharmony_ci u32 n_chans = cdd->n_chans; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* 78362306a36Sopenharmony_ci * The channels can only be used as TX or as RX. So we add twice 78462306a36Sopenharmony_ci * that much dma channels because USB can only do RX or TX. 78562306a36Sopenharmony_ci */ 78662306a36Sopenharmony_ci n_chans *= 2; 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci chans = devm_kcalloc(dev, n_chans, sizeof(*chans), GFP_KERNEL); 78962306a36Sopenharmony_ci if (!chans) 79062306a36Sopenharmony_ci return -ENOMEM; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci for (i = 0; i < n_chans; i++) { 79362306a36Sopenharmony_ci cchan = &chans[i]; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci cchan->cdd = cdd; 79662306a36Sopenharmony_ci if (i & 1) { 79762306a36Sopenharmony_ci cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1); 79862306a36Sopenharmony_ci cchan->is_tx = 1; 79962306a36Sopenharmony_ci } else { 80062306a36Sopenharmony_ci cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1); 80162306a36Sopenharmony_ci cchan->is_tx = 0; 80262306a36Sopenharmony_ci } 80362306a36Sopenharmony_ci cchan->port_num = i >> 1; 80462306a36Sopenharmony_ci cchan->desc = &cdd->cd[i]; 80562306a36Sopenharmony_ci cchan->desc_phys = cdd->descs_phys; 80662306a36Sopenharmony_ci cchan->desc_phys += i * sizeof(struct cppi41_desc); 80762306a36Sopenharmony_ci cchan->chan.device = &cdd->ddev; 80862306a36Sopenharmony_ci list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels); 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci cdd->first_td_desc = n_chans; 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci return 0; 81362306a36Sopenharmony_ci} 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_cistatic void purge_descs(struct device *dev, struct cppi41_dd *cdd) 81662306a36Sopenharmony_ci{ 81762306a36Sopenharmony_ci unsigned int mem_decs; 81862306a36Sopenharmony_ci int i; 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc); 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) { 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i)); 82562306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i)); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci dma_free_coherent(dev, mem_decs, cdd->cd, 82862306a36Sopenharmony_ci cdd->descs_phys); 82962306a36Sopenharmony_ci } 83062306a36Sopenharmony_ci} 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_cistatic void disable_sched(struct cppi41_dd *cdd) 83362306a36Sopenharmony_ci{ 83462306a36Sopenharmony_ci cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); 83562306a36Sopenharmony_ci} 83662306a36Sopenharmony_ci 83762306a36Sopenharmony_cistatic void deinit_cppi41(struct device *dev, struct cppi41_dd *cdd) 83862306a36Sopenharmony_ci{ 83962306a36Sopenharmony_ci disable_sched(cdd); 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci purge_descs(dev, cdd); 84262306a36Sopenharmony_ci 84362306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); 84462306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); 84562306a36Sopenharmony_ci dma_free_coherent(dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch, 84662306a36Sopenharmony_ci cdd->scratch_phys); 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic int init_descs(struct device *dev, struct cppi41_dd *cdd) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci unsigned int desc_size; 85262306a36Sopenharmony_ci unsigned int mem_decs; 85362306a36Sopenharmony_ci int i; 85462306a36Sopenharmony_ci u32 reg; 85562306a36Sopenharmony_ci u32 idx; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cppi41_desc) & 85862306a36Sopenharmony_ci (sizeof(struct cppi41_desc) - 1)); 85962306a36Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32); 86062306a36Sopenharmony_ci BUILD_BUG_ON(ALLOC_DECS_NUM < 32); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci desc_size = sizeof(struct cppi41_desc); 86362306a36Sopenharmony_ci mem_decs = ALLOC_DECS_NUM * desc_size; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_ci idx = 0; 86662306a36Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) { 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci reg = idx << QMGR_MEMCTRL_IDX_SH; 86962306a36Sopenharmony_ci reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH; 87062306a36Sopenharmony_ci reg |= ilog2(ALLOC_DECS_NUM) - 5; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_ci BUILD_BUG_ON(DESCS_AREAS != 1); 87362306a36Sopenharmony_ci cdd->cd = dma_alloc_coherent(dev, mem_decs, 87462306a36Sopenharmony_ci &cdd->descs_phys, GFP_KERNEL); 87562306a36Sopenharmony_ci if (!cdd->cd) 87662306a36Sopenharmony_ci return -ENOMEM; 87762306a36Sopenharmony_ci 87862306a36Sopenharmony_ci cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); 87962306a36Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i)); 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci idx += ALLOC_DECS_NUM; 88262306a36Sopenharmony_ci } 88362306a36Sopenharmony_ci return 0; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic void init_sched(struct cppi41_dd *cdd) 88762306a36Sopenharmony_ci{ 88862306a36Sopenharmony_ci unsigned ch; 88962306a36Sopenharmony_ci unsigned word; 89062306a36Sopenharmony_ci u32 reg; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci word = 0; 89362306a36Sopenharmony_ci cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); 89462306a36Sopenharmony_ci for (ch = 0; ch < cdd->n_chans; ch += 2) { 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci reg = SCHED_ENTRY0_CHAN(ch); 89762306a36Sopenharmony_ci reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci reg |= SCHED_ENTRY2_CHAN(ch + 1); 90062306a36Sopenharmony_ci reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX; 90162306a36Sopenharmony_ci cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word)); 90262306a36Sopenharmony_ci word++; 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci reg = cdd->n_chans * 2 - 1; 90562306a36Sopenharmony_ci reg |= DMA_SCHED_CTRL_EN; 90662306a36Sopenharmony_ci cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL); 90762306a36Sopenharmony_ci} 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_cistatic int init_cppi41(struct device *dev, struct cppi41_dd *cdd) 91062306a36Sopenharmony_ci{ 91162306a36Sopenharmony_ci int ret; 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1)); 91462306a36Sopenharmony_ci cdd->qmgr_scratch = dma_alloc_coherent(dev, QMGR_SCRATCH_SIZE, 91562306a36Sopenharmony_ci &cdd->scratch_phys, GFP_KERNEL); 91662306a36Sopenharmony_ci if (!cdd->qmgr_scratch) 91762306a36Sopenharmony_ci return -ENOMEM; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); 92062306a36Sopenharmony_ci cppi_writel(TOTAL_DESCS_NUM, cdd->qmgr_mem + QMGR_LRAM_SIZE); 92162306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); 92262306a36Sopenharmony_ci 92362306a36Sopenharmony_ci ret = init_descs(dev, cdd); 92462306a36Sopenharmony_ci if (ret) 92562306a36Sopenharmony_ci goto err_td; 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ); 92862306a36Sopenharmony_ci init_sched(cdd); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci return 0; 93162306a36Sopenharmony_cierr_td: 93262306a36Sopenharmony_ci deinit_cppi41(dev, cdd); 93362306a36Sopenharmony_ci return ret; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_cistatic struct platform_driver cpp41_dma_driver; 93762306a36Sopenharmony_ci/* 93862306a36Sopenharmony_ci * The param format is: 93962306a36Sopenharmony_ci * X Y 94062306a36Sopenharmony_ci * X: Port 94162306a36Sopenharmony_ci * Y: 0 = RX else TX 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ci#define INFO_PORT 0 94462306a36Sopenharmony_ci#define INFO_IS_TX 1 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_cistatic bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) 94762306a36Sopenharmony_ci{ 94862306a36Sopenharmony_ci struct cppi41_channel *cchan; 94962306a36Sopenharmony_ci struct cppi41_dd *cdd; 95062306a36Sopenharmony_ci const struct chan_queues *queues; 95162306a36Sopenharmony_ci u32 *num = param; 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ci if (chan->device->dev->driver != &cpp41_dma_driver.driver) 95462306a36Sopenharmony_ci return false; 95562306a36Sopenharmony_ci 95662306a36Sopenharmony_ci cchan = to_cpp41_chan(chan); 95762306a36Sopenharmony_ci 95862306a36Sopenharmony_ci if (cchan->port_num != num[INFO_PORT]) 95962306a36Sopenharmony_ci return false; 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci if (cchan->is_tx && !num[INFO_IS_TX]) 96262306a36Sopenharmony_ci return false; 96362306a36Sopenharmony_ci cdd = cchan->cdd; 96462306a36Sopenharmony_ci if (cchan->is_tx) 96562306a36Sopenharmony_ci queues = cdd->queues_tx; 96662306a36Sopenharmony_ci else 96762306a36Sopenharmony_ci queues = cdd->queues_rx; 96862306a36Sopenharmony_ci 96962306a36Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) != 97062306a36Sopenharmony_ci ARRAY_SIZE(am335x_usb_queues_tx)); 97162306a36Sopenharmony_ci if (WARN_ON(cchan->port_num >= ARRAY_SIZE(am335x_usb_queues_rx))) 97262306a36Sopenharmony_ci return false; 97362306a36Sopenharmony_ci 97462306a36Sopenharmony_ci cchan->q_num = queues[cchan->port_num].submit; 97562306a36Sopenharmony_ci cchan->q_comp_num = queues[cchan->port_num].complete; 97662306a36Sopenharmony_ci return true; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic struct of_dma_filter_info cpp41_dma_info = { 98062306a36Sopenharmony_ci .filter_fn = cpp41_dma_filter_fn, 98162306a36Sopenharmony_ci}; 98262306a36Sopenharmony_ci 98362306a36Sopenharmony_cistatic struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec, 98462306a36Sopenharmony_ci struct of_dma *ofdma) 98562306a36Sopenharmony_ci{ 98662306a36Sopenharmony_ci int count = dma_spec->args_count; 98762306a36Sopenharmony_ci struct of_dma_filter_info *info = ofdma->of_dma_data; 98862306a36Sopenharmony_ci 98962306a36Sopenharmony_ci if (!info || !info->filter_fn) 99062306a36Sopenharmony_ci return NULL; 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (count != 2) 99362306a36Sopenharmony_ci return NULL; 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci return dma_request_channel(info->dma_cap, info->filter_fn, 99662306a36Sopenharmony_ci &dma_spec->args[0]); 99762306a36Sopenharmony_ci} 99862306a36Sopenharmony_ci 99962306a36Sopenharmony_cistatic const struct cppi_glue_infos am335x_usb_infos = { 100062306a36Sopenharmony_ci .queues_rx = am335x_usb_queues_rx, 100162306a36Sopenharmony_ci .queues_tx = am335x_usb_queues_tx, 100262306a36Sopenharmony_ci .td_queue = { .submit = 31, .complete = 0 }, 100362306a36Sopenharmony_ci .first_completion_queue = 93, 100462306a36Sopenharmony_ci .qmgr_num_pend = 5, 100562306a36Sopenharmony_ci}; 100662306a36Sopenharmony_ci 100762306a36Sopenharmony_cistatic const struct cppi_glue_infos da8xx_usb_infos = { 100862306a36Sopenharmony_ci .queues_rx = da8xx_usb_queues_rx, 100962306a36Sopenharmony_ci .queues_tx = da8xx_usb_queues_tx, 101062306a36Sopenharmony_ci .td_queue = { .submit = 31, .complete = 0 }, 101162306a36Sopenharmony_ci .first_completion_queue = 24, 101262306a36Sopenharmony_ci .qmgr_num_pend = 2, 101362306a36Sopenharmony_ci}; 101462306a36Sopenharmony_ci 101562306a36Sopenharmony_cistatic const struct of_device_id cppi41_dma_ids[] = { 101662306a36Sopenharmony_ci { .compatible = "ti,am3359-cppi41", .data = &am335x_usb_infos}, 101762306a36Sopenharmony_ci { .compatible = "ti,da830-cppi41", .data = &da8xx_usb_infos}, 101862306a36Sopenharmony_ci {}, 101962306a36Sopenharmony_ci}; 102062306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, cppi41_dma_ids); 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_cistatic const struct cppi_glue_infos *get_glue_info(struct device *dev) 102362306a36Sopenharmony_ci{ 102462306a36Sopenharmony_ci const struct of_device_id *of_id; 102562306a36Sopenharmony_ci 102662306a36Sopenharmony_ci of_id = of_match_node(cppi41_dma_ids, dev->of_node); 102762306a36Sopenharmony_ci if (!of_id) 102862306a36Sopenharmony_ci return NULL; 102962306a36Sopenharmony_ci return of_id->data; 103062306a36Sopenharmony_ci} 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci#define CPPI41_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ 103362306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ 103462306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ 103562306a36Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_cistatic int cppi41_dma_probe(struct platform_device *pdev) 103862306a36Sopenharmony_ci{ 103962306a36Sopenharmony_ci struct cppi41_dd *cdd; 104062306a36Sopenharmony_ci struct device *dev = &pdev->dev; 104162306a36Sopenharmony_ci const struct cppi_glue_infos *glue_info; 104262306a36Sopenharmony_ci int index; 104362306a36Sopenharmony_ci int irq; 104462306a36Sopenharmony_ci int ret; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci glue_info = get_glue_info(dev); 104762306a36Sopenharmony_ci if (!glue_info) 104862306a36Sopenharmony_ci return -EINVAL; 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_ci cdd = devm_kzalloc(&pdev->dev, sizeof(*cdd), GFP_KERNEL); 105162306a36Sopenharmony_ci if (!cdd) 105262306a36Sopenharmony_ci return -ENOMEM; 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask); 105562306a36Sopenharmony_ci cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources; 105662306a36Sopenharmony_ci cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources; 105762306a36Sopenharmony_ci cdd->ddev.device_tx_status = cppi41_dma_tx_status; 105862306a36Sopenharmony_ci cdd->ddev.device_issue_pending = cppi41_dma_issue_pending; 105962306a36Sopenharmony_ci cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg; 106062306a36Sopenharmony_ci cdd->ddev.device_terminate_all = cppi41_stop_chan; 106162306a36Sopenharmony_ci cdd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 106262306a36Sopenharmony_ci cdd->ddev.src_addr_widths = CPPI41_DMA_BUSWIDTHS; 106362306a36Sopenharmony_ci cdd->ddev.dst_addr_widths = CPPI41_DMA_BUSWIDTHS; 106462306a36Sopenharmony_ci cdd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 106562306a36Sopenharmony_ci cdd->ddev.dev = dev; 106662306a36Sopenharmony_ci INIT_LIST_HEAD(&cdd->ddev.channels); 106762306a36Sopenharmony_ci cpp41_dma_info.dma_cap = cdd->ddev.cap_mask; 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ci index = of_property_match_string(dev->of_node, 107062306a36Sopenharmony_ci "reg-names", "controller"); 107162306a36Sopenharmony_ci if (index < 0) 107262306a36Sopenharmony_ci return index; 107362306a36Sopenharmony_ci 107462306a36Sopenharmony_ci cdd->ctrl_mem = devm_platform_ioremap_resource(pdev, index); 107562306a36Sopenharmony_ci if (IS_ERR(cdd->ctrl_mem)) 107662306a36Sopenharmony_ci return PTR_ERR(cdd->ctrl_mem); 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci cdd->sched_mem = devm_platform_ioremap_resource(pdev, index + 1); 107962306a36Sopenharmony_ci if (IS_ERR(cdd->sched_mem)) 108062306a36Sopenharmony_ci return PTR_ERR(cdd->sched_mem); 108162306a36Sopenharmony_ci 108262306a36Sopenharmony_ci cdd->qmgr_mem = devm_platform_ioremap_resource(pdev, index + 2); 108362306a36Sopenharmony_ci if (IS_ERR(cdd->qmgr_mem)) 108462306a36Sopenharmony_ci return PTR_ERR(cdd->qmgr_mem); 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci spin_lock_init(&cdd->lock); 108762306a36Sopenharmony_ci INIT_LIST_HEAD(&cdd->pending); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci platform_set_drvdata(pdev, cdd); 109062306a36Sopenharmony_ci 109162306a36Sopenharmony_ci pm_runtime_enable(dev); 109262306a36Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 100); 109362306a36Sopenharmony_ci pm_runtime_use_autosuspend(dev); 109462306a36Sopenharmony_ci ret = pm_runtime_get_sync(dev); 109562306a36Sopenharmony_ci if (ret < 0) 109662306a36Sopenharmony_ci goto err_get_sync; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci cdd->queues_rx = glue_info->queues_rx; 109962306a36Sopenharmony_ci cdd->queues_tx = glue_info->queues_tx; 110062306a36Sopenharmony_ci cdd->td_queue = glue_info->td_queue; 110162306a36Sopenharmony_ci cdd->qmgr_num_pend = glue_info->qmgr_num_pend; 110262306a36Sopenharmony_ci cdd->first_completion_queue = glue_info->first_completion_queue; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci /* Parse new and deprecated dma-channels properties */ 110562306a36Sopenharmony_ci ret = of_property_read_u32(dev->of_node, 110662306a36Sopenharmony_ci "dma-channels", &cdd->n_chans); 110762306a36Sopenharmony_ci if (ret) 110862306a36Sopenharmony_ci ret = of_property_read_u32(dev->of_node, 110962306a36Sopenharmony_ci "#dma-channels", &cdd->n_chans); 111062306a36Sopenharmony_ci if (ret) 111162306a36Sopenharmony_ci goto err_get_n_chans; 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci ret = init_cppi41(dev, cdd); 111462306a36Sopenharmony_ci if (ret) 111562306a36Sopenharmony_ci goto err_init_cppi; 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = cppi41_add_chans(dev, cdd); 111862306a36Sopenharmony_ci if (ret) 111962306a36Sopenharmony_ci goto err_chans; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci irq = irq_of_parse_and_map(dev->of_node, 0); 112262306a36Sopenharmony_ci if (!irq) { 112362306a36Sopenharmony_ci ret = -EINVAL; 112462306a36Sopenharmony_ci goto err_chans; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, cppi41_irq, IRQF_SHARED, 112862306a36Sopenharmony_ci dev_name(dev), cdd); 112962306a36Sopenharmony_ci if (ret) 113062306a36Sopenharmony_ci goto err_chans; 113162306a36Sopenharmony_ci cdd->irq = irq; 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci ret = dma_async_device_register(&cdd->ddev); 113462306a36Sopenharmony_ci if (ret) 113562306a36Sopenharmony_ci goto err_chans; 113662306a36Sopenharmony_ci 113762306a36Sopenharmony_ci ret = of_dma_controller_register(dev->of_node, 113862306a36Sopenharmony_ci cppi41_dma_xlate, &cpp41_dma_info); 113962306a36Sopenharmony_ci if (ret) 114062306a36Sopenharmony_ci goto err_of; 114162306a36Sopenharmony_ci 114262306a36Sopenharmony_ci pm_runtime_mark_last_busy(dev); 114362306a36Sopenharmony_ci pm_runtime_put_autosuspend(dev); 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_ci return 0; 114662306a36Sopenharmony_cierr_of: 114762306a36Sopenharmony_ci dma_async_device_unregister(&cdd->ddev); 114862306a36Sopenharmony_cierr_chans: 114962306a36Sopenharmony_ci deinit_cppi41(dev, cdd); 115062306a36Sopenharmony_cierr_init_cppi: 115162306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 115262306a36Sopenharmony_cierr_get_n_chans: 115362306a36Sopenharmony_cierr_get_sync: 115462306a36Sopenharmony_ci pm_runtime_put_sync(dev); 115562306a36Sopenharmony_ci pm_runtime_disable(dev); 115662306a36Sopenharmony_ci return ret; 115762306a36Sopenharmony_ci} 115862306a36Sopenharmony_ci 115962306a36Sopenharmony_cistatic int cppi41_dma_remove(struct platform_device *pdev) 116062306a36Sopenharmony_ci{ 116162306a36Sopenharmony_ci struct cppi41_dd *cdd = platform_get_drvdata(pdev); 116262306a36Sopenharmony_ci int error; 116362306a36Sopenharmony_ci 116462306a36Sopenharmony_ci error = pm_runtime_get_sync(&pdev->dev); 116562306a36Sopenharmony_ci if (error < 0) 116662306a36Sopenharmony_ci dev_err(&pdev->dev, "%s could not pm_runtime_get: %i\n", 116762306a36Sopenharmony_ci __func__, error); 116862306a36Sopenharmony_ci of_dma_controller_free(pdev->dev.of_node); 116962306a36Sopenharmony_ci dma_async_device_unregister(&cdd->ddev); 117062306a36Sopenharmony_ci 117162306a36Sopenharmony_ci devm_free_irq(&pdev->dev, cdd->irq, cdd); 117262306a36Sopenharmony_ci deinit_cppi41(&pdev->dev, cdd); 117362306a36Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 117462306a36Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 117562306a36Sopenharmony_ci pm_runtime_disable(&pdev->dev); 117662306a36Sopenharmony_ci return 0; 117762306a36Sopenharmony_ci} 117862306a36Sopenharmony_ci 117962306a36Sopenharmony_cistatic int __maybe_unused cppi41_suspend(struct device *dev) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci cdd->dma_tdfdq = cppi_readl(cdd->ctrl_mem + DMA_TDFDQ); 118462306a36Sopenharmony_ci disable_sched(cdd); 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci return 0; 118762306a36Sopenharmony_ci} 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_cistatic int __maybe_unused cppi41_resume(struct device *dev) 119062306a36Sopenharmony_ci{ 119162306a36Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 119262306a36Sopenharmony_ci struct cppi41_channel *c; 119362306a36Sopenharmony_ci int i; 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) 119662306a36Sopenharmony_ci cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); 119762306a36Sopenharmony_ci 119862306a36Sopenharmony_ci list_for_each_entry(c, &cdd->ddev.channels, chan.device_node) 119962306a36Sopenharmony_ci if (!c->is_tx) 120062306a36Sopenharmony_ci cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); 120162306a36Sopenharmony_ci 120262306a36Sopenharmony_ci init_sched(cdd); 120362306a36Sopenharmony_ci 120462306a36Sopenharmony_ci cppi_writel(cdd->dma_tdfdq, cdd->ctrl_mem + DMA_TDFDQ); 120562306a36Sopenharmony_ci cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); 120662306a36Sopenharmony_ci cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); 120762306a36Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci return 0; 121062306a36Sopenharmony_ci} 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_cistatic int __maybe_unused cppi41_runtime_suspend(struct device *dev) 121362306a36Sopenharmony_ci{ 121462306a36Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 121562306a36Sopenharmony_ci unsigned long flags; 121662306a36Sopenharmony_ci 121762306a36Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 121862306a36Sopenharmony_ci cdd->is_suspended = true; 121962306a36Sopenharmony_ci WARN_ON(!list_empty(&cdd->pending)); 122062306a36Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 122162306a36Sopenharmony_ci 122262306a36Sopenharmony_ci return 0; 122362306a36Sopenharmony_ci} 122462306a36Sopenharmony_ci 122562306a36Sopenharmony_cistatic int __maybe_unused cppi41_runtime_resume(struct device *dev) 122662306a36Sopenharmony_ci{ 122762306a36Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 122862306a36Sopenharmony_ci unsigned long flags; 122962306a36Sopenharmony_ci 123062306a36Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 123162306a36Sopenharmony_ci cdd->is_suspended = false; 123262306a36Sopenharmony_ci cppi41_run_queue(cdd); 123362306a36Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci return 0; 123662306a36Sopenharmony_ci} 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_cistatic const struct dev_pm_ops cppi41_pm_ops = { 123962306a36Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(cppi41_suspend, cppi41_resume) 124062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(cppi41_runtime_suspend, 124162306a36Sopenharmony_ci cppi41_runtime_resume, 124262306a36Sopenharmony_ci NULL) 124362306a36Sopenharmony_ci}; 124462306a36Sopenharmony_ci 124562306a36Sopenharmony_cistatic struct platform_driver cpp41_dma_driver = { 124662306a36Sopenharmony_ci .probe = cppi41_dma_probe, 124762306a36Sopenharmony_ci .remove = cppi41_dma_remove, 124862306a36Sopenharmony_ci .driver = { 124962306a36Sopenharmony_ci .name = "cppi41-dma-engine", 125062306a36Sopenharmony_ci .pm = &cppi41_pm_ops, 125162306a36Sopenharmony_ci .of_match_table = of_match_ptr(cppi41_dma_ids), 125262306a36Sopenharmony_ci }, 125362306a36Sopenharmony_ci}; 125462306a36Sopenharmony_ci 125562306a36Sopenharmony_cimodule_platform_driver(cpp41_dma_driver); 125662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 125762306a36Sopenharmony_ciMODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); 1258