18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci#include <linux/delay.h> 38c2ecf20Sopenharmony_ci#include <linux/dmaengine.h> 48c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 58c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 68c2ecf20Sopenharmony_ci#include <linux/module.h> 78c2ecf20Sopenharmony_ci#include <linux/of.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/of_dma.h> 108c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 118c2ecf20Sopenharmony_ci#include <linux/dmapool.h> 128c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 138c2ecf20Sopenharmony_ci#include <linux/of_address.h> 148c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 158c2ecf20Sopenharmony_ci#include "../dmaengine.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#define DESC_TYPE 27 188c2ecf20Sopenharmony_ci#define DESC_TYPE_HOST 0x10 198c2ecf20Sopenharmony_ci#define DESC_TYPE_TEARD 0x13 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define TD_DESC_IS_RX (1 << 16) 228c2ecf20Sopenharmony_ci#define TD_DESC_DMA_NUM 10 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define DESC_LENGTH_BITS_NUM 21 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#define DESC_TYPE_USB (5 << 26) 278c2ecf20Sopenharmony_ci#define DESC_PD_COMPLETE (1 << 31) 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci/* DMA engine */ 308c2ecf20Sopenharmony_ci#define DMA_TDFDQ 4 318c2ecf20Sopenharmony_ci#define DMA_TXGCR(x) (0x800 + (x) * 0x20) 328c2ecf20Sopenharmony_ci#define DMA_RXGCR(x) (0x808 + (x) * 0x20) 338c2ecf20Sopenharmony_ci#define RXHPCRA0 4 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci#define GCR_CHAN_ENABLE (1 << 31) 368c2ecf20Sopenharmony_ci#define GCR_TEARDOWN (1 << 30) 378c2ecf20Sopenharmony_ci#define GCR_STARV_RETRY (1 << 24) 388c2ecf20Sopenharmony_ci#define GCR_DESC_TYPE_HOST (1 << 14) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* DMA scheduler */ 418c2ecf20Sopenharmony_ci#define DMA_SCHED_CTRL 0 428c2ecf20Sopenharmony_ci#define DMA_SCHED_CTRL_EN (1 << 31) 438c2ecf20Sopenharmony_ci#define DMA_SCHED_WORD(x) ((x) * 4 + 0x800) 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci#define SCHED_ENTRY0_CHAN(x) ((x) << 0) 468c2ecf20Sopenharmony_ci#define SCHED_ENTRY0_IS_RX (1 << 7) 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define SCHED_ENTRY1_CHAN(x) ((x) << 8) 498c2ecf20Sopenharmony_ci#define SCHED_ENTRY1_IS_RX (1 << 15) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define SCHED_ENTRY2_CHAN(x) ((x) << 16) 528c2ecf20Sopenharmony_ci#define SCHED_ENTRY2_IS_RX (1 << 23) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci#define SCHED_ENTRY3_CHAN(x) ((x) << 24) 558c2ecf20Sopenharmony_ci#define SCHED_ENTRY3_IS_RX (1 << 31) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* Queue manager */ 588c2ecf20Sopenharmony_ci/* 4 KiB of memory for descriptors, 2 for each endpoint */ 598c2ecf20Sopenharmony_ci#define ALLOC_DECS_NUM 128 608c2ecf20Sopenharmony_ci#define DESCS_AREAS 1 618c2ecf20Sopenharmony_ci#define TOTAL_DESCS_NUM (ALLOC_DECS_NUM * DESCS_AREAS) 628c2ecf20Sopenharmony_ci#define QMGR_SCRATCH_SIZE (TOTAL_DESCS_NUM * 4) 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci#define QMGR_LRAM0_BASE 0x80 658c2ecf20Sopenharmony_ci#define QMGR_LRAM_SIZE 0x84 668c2ecf20Sopenharmony_ci#define QMGR_LRAM1_BASE 0x88 678c2ecf20Sopenharmony_ci#define QMGR_MEMBASE(x) (0x1000 + (x) * 0x10) 688c2ecf20Sopenharmony_ci#define QMGR_MEMCTRL(x) (0x1004 + (x) * 0x10) 698c2ecf20Sopenharmony_ci#define QMGR_MEMCTRL_IDX_SH 16 708c2ecf20Sopenharmony_ci#define QMGR_MEMCTRL_DESC_SH 8 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define QMGR_PEND(x) (0x90 + (x) * 4) 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define QMGR_PENDING_SLOT_Q(x) (x / 32) 758c2ecf20Sopenharmony_ci#define QMGR_PENDING_BIT_Q(x) (x % 32) 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci#define QMGR_QUEUE_A(n) (0x2000 + (n) * 0x10) 788c2ecf20Sopenharmony_ci#define QMGR_QUEUE_B(n) (0x2004 + (n) * 0x10) 798c2ecf20Sopenharmony_ci#define QMGR_QUEUE_C(n) (0x2008 + (n) * 0x10) 808c2ecf20Sopenharmony_ci#define QMGR_QUEUE_D(n) (0x200c + (n) * 0x10) 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* Packet Descriptor */ 838c2ecf20Sopenharmony_ci#define PD2_ZERO_LENGTH (1 << 19) 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct cppi41_channel { 868c2ecf20Sopenharmony_ci struct dma_chan chan; 878c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor txd; 888c2ecf20Sopenharmony_ci struct cppi41_dd *cdd; 898c2ecf20Sopenharmony_ci struct cppi41_desc *desc; 908c2ecf20Sopenharmony_ci dma_addr_t desc_phys; 918c2ecf20Sopenharmony_ci void __iomem *gcr_reg; 928c2ecf20Sopenharmony_ci int is_tx; 938c2ecf20Sopenharmony_ci u32 residue; 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci unsigned int q_num; 968c2ecf20Sopenharmony_ci unsigned int q_comp_num; 978c2ecf20Sopenharmony_ci unsigned int port_num; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci unsigned td_retry; 1008c2ecf20Sopenharmony_ci unsigned td_queued:1; 1018c2ecf20Sopenharmony_ci unsigned td_seen:1; 1028c2ecf20Sopenharmony_ci unsigned td_desc_seen:1; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci struct list_head node; /* Node for pending list */ 1058c2ecf20Sopenharmony_ci}; 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistruct cppi41_desc { 1088c2ecf20Sopenharmony_ci u32 pd0; 1098c2ecf20Sopenharmony_ci u32 pd1; 1108c2ecf20Sopenharmony_ci u32 pd2; 1118c2ecf20Sopenharmony_ci u32 pd3; 1128c2ecf20Sopenharmony_ci u32 pd4; 1138c2ecf20Sopenharmony_ci u32 pd5; 1148c2ecf20Sopenharmony_ci u32 pd6; 1158c2ecf20Sopenharmony_ci u32 pd7; 1168c2ecf20Sopenharmony_ci} __aligned(32); 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistruct chan_queues { 1198c2ecf20Sopenharmony_ci u16 submit; 1208c2ecf20Sopenharmony_ci u16 complete; 1218c2ecf20Sopenharmony_ci}; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_cistruct cppi41_dd { 1248c2ecf20Sopenharmony_ci struct dma_device ddev; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci void *qmgr_scratch; 1278c2ecf20Sopenharmony_ci dma_addr_t scratch_phys; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci struct cppi41_desc *cd; 1308c2ecf20Sopenharmony_ci dma_addr_t descs_phys; 1318c2ecf20Sopenharmony_ci u32 first_td_desc; 1328c2ecf20Sopenharmony_ci struct cppi41_channel *chan_busy[ALLOC_DECS_NUM]; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci void __iomem *ctrl_mem; 1358c2ecf20Sopenharmony_ci void __iomem *sched_mem; 1368c2ecf20Sopenharmony_ci void __iomem *qmgr_mem; 1378c2ecf20Sopenharmony_ci unsigned int irq; 1388c2ecf20Sopenharmony_ci const struct chan_queues *queues_rx; 1398c2ecf20Sopenharmony_ci const struct chan_queues *queues_tx; 1408c2ecf20Sopenharmony_ci struct chan_queues td_queue; 1418c2ecf20Sopenharmony_ci u16 first_completion_queue; 1428c2ecf20Sopenharmony_ci u16 qmgr_num_pend; 1438c2ecf20Sopenharmony_ci u32 n_chans; 1448c2ecf20Sopenharmony_ci u8 platform; 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci struct list_head pending; /* Pending queued transfers */ 1478c2ecf20Sopenharmony_ci spinlock_t lock; /* Lock for pending list */ 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci /* context for suspend/resume */ 1508c2ecf20Sopenharmony_ci unsigned int dma_tdfdq; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci bool is_suspended; 1538c2ecf20Sopenharmony_ci}; 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic struct chan_queues am335x_usb_queues_tx[] = { 1568c2ecf20Sopenharmony_ci /* USB0 ENDP 1 */ 1578c2ecf20Sopenharmony_ci [ 0] = { .submit = 32, .complete = 93}, 1588c2ecf20Sopenharmony_ci [ 1] = { .submit = 34, .complete = 94}, 1598c2ecf20Sopenharmony_ci [ 2] = { .submit = 36, .complete = 95}, 1608c2ecf20Sopenharmony_ci [ 3] = { .submit = 38, .complete = 96}, 1618c2ecf20Sopenharmony_ci [ 4] = { .submit = 40, .complete = 97}, 1628c2ecf20Sopenharmony_ci [ 5] = { .submit = 42, .complete = 98}, 1638c2ecf20Sopenharmony_ci [ 6] = { .submit = 44, .complete = 99}, 1648c2ecf20Sopenharmony_ci [ 7] = { .submit = 46, .complete = 100}, 1658c2ecf20Sopenharmony_ci [ 8] = { .submit = 48, .complete = 101}, 1668c2ecf20Sopenharmony_ci [ 9] = { .submit = 50, .complete = 102}, 1678c2ecf20Sopenharmony_ci [10] = { .submit = 52, .complete = 103}, 1688c2ecf20Sopenharmony_ci [11] = { .submit = 54, .complete = 104}, 1698c2ecf20Sopenharmony_ci [12] = { .submit = 56, .complete = 105}, 1708c2ecf20Sopenharmony_ci [13] = { .submit = 58, .complete = 106}, 1718c2ecf20Sopenharmony_ci [14] = { .submit = 60, .complete = 107}, 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci /* USB1 ENDP1 */ 1748c2ecf20Sopenharmony_ci [15] = { .submit = 62, .complete = 125}, 1758c2ecf20Sopenharmony_ci [16] = { .submit = 64, .complete = 126}, 1768c2ecf20Sopenharmony_ci [17] = { .submit = 66, .complete = 127}, 1778c2ecf20Sopenharmony_ci [18] = { .submit = 68, .complete = 128}, 1788c2ecf20Sopenharmony_ci [19] = { .submit = 70, .complete = 129}, 1798c2ecf20Sopenharmony_ci [20] = { .submit = 72, .complete = 130}, 1808c2ecf20Sopenharmony_ci [21] = { .submit = 74, .complete = 131}, 1818c2ecf20Sopenharmony_ci [22] = { .submit = 76, .complete = 132}, 1828c2ecf20Sopenharmony_ci [23] = { .submit = 78, .complete = 133}, 1838c2ecf20Sopenharmony_ci [24] = { .submit = 80, .complete = 134}, 1848c2ecf20Sopenharmony_ci [25] = { .submit = 82, .complete = 135}, 1858c2ecf20Sopenharmony_ci [26] = { .submit = 84, .complete = 136}, 1868c2ecf20Sopenharmony_ci [27] = { .submit = 86, .complete = 137}, 1878c2ecf20Sopenharmony_ci [28] = { .submit = 88, .complete = 138}, 1888c2ecf20Sopenharmony_ci [29] = { .submit = 90, .complete = 139}, 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic const struct chan_queues am335x_usb_queues_rx[] = { 1928c2ecf20Sopenharmony_ci /* USB0 ENDP 1 */ 1938c2ecf20Sopenharmony_ci [ 0] = { .submit = 1, .complete = 109}, 1948c2ecf20Sopenharmony_ci [ 1] = { .submit = 2, .complete = 110}, 1958c2ecf20Sopenharmony_ci [ 2] = { .submit = 3, .complete = 111}, 1968c2ecf20Sopenharmony_ci [ 3] = { .submit = 4, .complete = 112}, 1978c2ecf20Sopenharmony_ci [ 4] = { .submit = 5, .complete = 113}, 1988c2ecf20Sopenharmony_ci [ 5] = { .submit = 6, .complete = 114}, 1998c2ecf20Sopenharmony_ci [ 6] = { .submit = 7, .complete = 115}, 2008c2ecf20Sopenharmony_ci [ 7] = { .submit = 8, .complete = 116}, 2018c2ecf20Sopenharmony_ci [ 8] = { .submit = 9, .complete = 117}, 2028c2ecf20Sopenharmony_ci [ 9] = { .submit = 10, .complete = 118}, 2038c2ecf20Sopenharmony_ci [10] = { .submit = 11, .complete = 119}, 2048c2ecf20Sopenharmony_ci [11] = { .submit = 12, .complete = 120}, 2058c2ecf20Sopenharmony_ci [12] = { .submit = 13, .complete = 121}, 2068c2ecf20Sopenharmony_ci [13] = { .submit = 14, .complete = 122}, 2078c2ecf20Sopenharmony_ci [14] = { .submit = 15, .complete = 123}, 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci /* USB1 ENDP 1 */ 2108c2ecf20Sopenharmony_ci [15] = { .submit = 16, .complete = 141}, 2118c2ecf20Sopenharmony_ci [16] = { .submit = 17, .complete = 142}, 2128c2ecf20Sopenharmony_ci [17] = { .submit = 18, .complete = 143}, 2138c2ecf20Sopenharmony_ci [18] = { .submit = 19, .complete = 144}, 2148c2ecf20Sopenharmony_ci [19] = { .submit = 20, .complete = 145}, 2158c2ecf20Sopenharmony_ci [20] = { .submit = 21, .complete = 146}, 2168c2ecf20Sopenharmony_ci [21] = { .submit = 22, .complete = 147}, 2178c2ecf20Sopenharmony_ci [22] = { .submit = 23, .complete = 148}, 2188c2ecf20Sopenharmony_ci [23] = { .submit = 24, .complete = 149}, 2198c2ecf20Sopenharmony_ci [24] = { .submit = 25, .complete = 150}, 2208c2ecf20Sopenharmony_ci [25] = { .submit = 26, .complete = 151}, 2218c2ecf20Sopenharmony_ci [26] = { .submit = 27, .complete = 152}, 2228c2ecf20Sopenharmony_ci [27] = { .submit = 28, .complete = 153}, 2238c2ecf20Sopenharmony_ci [28] = { .submit = 29, .complete = 154}, 2248c2ecf20Sopenharmony_ci [29] = { .submit = 30, .complete = 155}, 2258c2ecf20Sopenharmony_ci}; 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_tx[] = { 2288c2ecf20Sopenharmony_ci [0] = { .submit = 16, .complete = 24}, 2298c2ecf20Sopenharmony_ci [1] = { .submit = 18, .complete = 24}, 2308c2ecf20Sopenharmony_ci [2] = { .submit = 20, .complete = 24}, 2318c2ecf20Sopenharmony_ci [3] = { .submit = 22, .complete = 24}, 2328c2ecf20Sopenharmony_ci}; 2338c2ecf20Sopenharmony_ci 2348c2ecf20Sopenharmony_cistatic const struct chan_queues da8xx_usb_queues_rx[] = { 2358c2ecf20Sopenharmony_ci [0] = { .submit = 1, .complete = 26}, 2368c2ecf20Sopenharmony_ci [1] = { .submit = 3, .complete = 26}, 2378c2ecf20Sopenharmony_ci [2] = { .submit = 5, .complete = 26}, 2388c2ecf20Sopenharmony_ci [3] = { .submit = 7, .complete = 26}, 2398c2ecf20Sopenharmony_ci}; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistruct cppi_glue_infos { 2428c2ecf20Sopenharmony_ci const struct chan_queues *queues_rx; 2438c2ecf20Sopenharmony_ci const struct chan_queues *queues_tx; 2448c2ecf20Sopenharmony_ci struct chan_queues td_queue; 2458c2ecf20Sopenharmony_ci u16 first_completion_queue; 2468c2ecf20Sopenharmony_ci u16 qmgr_num_pend; 2478c2ecf20Sopenharmony_ci}; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_cistatic struct cppi41_channel *to_cpp41_chan(struct dma_chan *c) 2508c2ecf20Sopenharmony_ci{ 2518c2ecf20Sopenharmony_ci return container_of(c, struct cppi41_channel, chan); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic struct cppi41_channel *desc_to_chan(struct cppi41_dd *cdd, u32 desc) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci struct cppi41_channel *c; 2578c2ecf20Sopenharmony_ci u32 descs_size; 2588c2ecf20Sopenharmony_ci u32 desc_num; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci descs_size = sizeof(struct cppi41_desc) * ALLOC_DECS_NUM; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci if (!((desc >= cdd->descs_phys) && 2638c2ecf20Sopenharmony_ci (desc < (cdd->descs_phys + descs_size)))) { 2648c2ecf20Sopenharmony_ci return NULL; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci desc_num = (desc - cdd->descs_phys) / sizeof(struct cppi41_desc); 2688c2ecf20Sopenharmony_ci BUG_ON(desc_num >= ALLOC_DECS_NUM); 2698c2ecf20Sopenharmony_ci c = cdd->chan_busy[desc_num]; 2708c2ecf20Sopenharmony_ci cdd->chan_busy[desc_num] = NULL; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci /* Usecount for chan_busy[], paired with push_desc_queue() */ 2738c2ecf20Sopenharmony_ci pm_runtime_put(cdd->ddev.dev); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci return c; 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_cistatic void cppi_writel(u32 val, void *__iomem *mem) 2798c2ecf20Sopenharmony_ci{ 2808c2ecf20Sopenharmony_ci __raw_writel(val, mem); 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic u32 cppi_readl(void *__iomem *mem) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci return __raw_readl(mem); 2868c2ecf20Sopenharmony_ci} 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_cistatic u32 pd_trans_len(u32 val) 2898c2ecf20Sopenharmony_ci{ 2908c2ecf20Sopenharmony_ci return val & ((1 << (DESC_LENGTH_BITS_NUM + 1)) - 1); 2918c2ecf20Sopenharmony_ci} 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_cistatic u32 cppi41_pop_desc(struct cppi41_dd *cdd, unsigned queue_num) 2948c2ecf20Sopenharmony_ci{ 2958c2ecf20Sopenharmony_ci u32 desc; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci desc = cppi_readl(cdd->qmgr_mem + QMGR_QUEUE_D(queue_num)); 2988c2ecf20Sopenharmony_ci desc &= ~0x1f; 2998c2ecf20Sopenharmony_ci return desc; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic irqreturn_t cppi41_irq(int irq, void *data) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = data; 3058c2ecf20Sopenharmony_ci u16 first_completion_queue = cdd->first_completion_queue; 3068c2ecf20Sopenharmony_ci u16 qmgr_num_pend = cdd->qmgr_num_pend; 3078c2ecf20Sopenharmony_ci struct cppi41_channel *c; 3088c2ecf20Sopenharmony_ci int i; 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci for (i = QMGR_PENDING_SLOT_Q(first_completion_queue); i < qmgr_num_pend; 3118c2ecf20Sopenharmony_ci i++) { 3128c2ecf20Sopenharmony_ci u32 val; 3138c2ecf20Sopenharmony_ci u32 q_num; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci val = cppi_readl(cdd->qmgr_mem + QMGR_PEND(i)); 3168c2ecf20Sopenharmony_ci if (i == QMGR_PENDING_SLOT_Q(first_completion_queue) && val) { 3178c2ecf20Sopenharmony_ci u32 mask; 3188c2ecf20Sopenharmony_ci /* set corresponding bit for completetion Q 93 */ 3198c2ecf20Sopenharmony_ci mask = 1 << QMGR_PENDING_BIT_Q(first_completion_queue); 3208c2ecf20Sopenharmony_ci /* not set all bits for queues less than Q 93 */ 3218c2ecf20Sopenharmony_ci mask--; 3228c2ecf20Sopenharmony_ci /* now invert and keep only Q 93+ set */ 3238c2ecf20Sopenharmony_ci val &= ~mask; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci if (val) 3278c2ecf20Sopenharmony_ci __iormb(); 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci while (val) { 3308c2ecf20Sopenharmony_ci u32 desc, len; 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* 3338c2ecf20Sopenharmony_ci * This should never trigger, see the comments in 3348c2ecf20Sopenharmony_ci * push_desc_queue() 3358c2ecf20Sopenharmony_ci */ 3368c2ecf20Sopenharmony_ci WARN_ON(cdd->is_suspended); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci q_num = __fls(val); 3398c2ecf20Sopenharmony_ci val &= ~(1 << q_num); 3408c2ecf20Sopenharmony_ci q_num += 32 * i; 3418c2ecf20Sopenharmony_ci desc = cppi41_pop_desc(cdd, q_num); 3428c2ecf20Sopenharmony_ci c = desc_to_chan(cdd, desc); 3438c2ecf20Sopenharmony_ci if (WARN_ON(!c)) { 3448c2ecf20Sopenharmony_ci pr_err("%s() q %d desc %08x\n", __func__, 3458c2ecf20Sopenharmony_ci q_num, desc); 3468c2ecf20Sopenharmony_ci continue; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (c->desc->pd2 & PD2_ZERO_LENGTH) 3508c2ecf20Sopenharmony_ci len = 0; 3518c2ecf20Sopenharmony_ci else 3528c2ecf20Sopenharmony_ci len = pd_trans_len(c->desc->pd0); 3538c2ecf20Sopenharmony_ci 3548c2ecf20Sopenharmony_ci c->residue = pd_trans_len(c->desc->pd6) - len; 3558c2ecf20Sopenharmony_ci dma_cookie_complete(&c->txd); 3568c2ecf20Sopenharmony_ci dmaengine_desc_get_callback_invoke(&c->txd, NULL); 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci } 3598c2ecf20Sopenharmony_ci return IRQ_HANDLED; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic dma_cookie_t cppi41_tx_submit(struct dma_async_tx_descriptor *tx) 3638c2ecf20Sopenharmony_ci{ 3648c2ecf20Sopenharmony_ci dma_cookie_t cookie; 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_ci cookie = dma_cookie_assign(tx); 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci return cookie; 3698c2ecf20Sopenharmony_ci} 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_cistatic int cppi41_dma_alloc_chan_resources(struct dma_chan *chan) 3728c2ecf20Sopenharmony_ci{ 3738c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 3748c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 3758c2ecf20Sopenharmony_ci int error; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci error = pm_runtime_get_sync(cdd->ddev.dev); 3788c2ecf20Sopenharmony_ci if (error < 0) { 3798c2ecf20Sopenharmony_ci dev_err(cdd->ddev.dev, "%s pm runtime get: %i\n", 3808c2ecf20Sopenharmony_ci __func__, error); 3818c2ecf20Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_ci return error; 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci dma_cookie_init(chan); 3878c2ecf20Sopenharmony_ci dma_async_tx_descriptor_init(&c->txd, chan); 3888c2ecf20Sopenharmony_ci c->txd.tx_submit = cppi41_tx_submit; 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (!c->is_tx) 3918c2ecf20Sopenharmony_ci cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 3948c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci return 0; 3978c2ecf20Sopenharmony_ci} 3988c2ecf20Sopenharmony_ci 3998c2ecf20Sopenharmony_cistatic void cppi41_dma_free_chan_resources(struct dma_chan *chan) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 4028c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 4038c2ecf20Sopenharmony_ci int error; 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci error = pm_runtime_get_sync(cdd->ddev.dev); 4068c2ecf20Sopenharmony_ci if (error < 0) { 4078c2ecf20Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci return; 4108c2ecf20Sopenharmony_ci } 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&cdd->pending)); 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 4158c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic enum dma_status cppi41_dma_tx_status(struct dma_chan *chan, 4198c2ecf20Sopenharmony_ci dma_cookie_t cookie, struct dma_tx_state *txstate) 4208c2ecf20Sopenharmony_ci{ 4218c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 4228c2ecf20Sopenharmony_ci enum dma_status ret; 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci ret = dma_cookie_status(chan, cookie, txstate); 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci dma_set_residue(txstate, c->residue); 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci return ret; 4298c2ecf20Sopenharmony_ci} 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_cistatic void push_desc_queue(struct cppi41_channel *c) 4328c2ecf20Sopenharmony_ci{ 4338c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 4348c2ecf20Sopenharmony_ci u32 desc_num; 4358c2ecf20Sopenharmony_ci u32 desc_phys; 4368c2ecf20Sopenharmony_ci u32 reg; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci c->residue = 0; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci reg = GCR_CHAN_ENABLE; 4418c2ecf20Sopenharmony_ci if (!c->is_tx) { 4428c2ecf20Sopenharmony_ci reg |= GCR_STARV_RETRY; 4438c2ecf20Sopenharmony_ci reg |= GCR_DESC_TYPE_HOST; 4448c2ecf20Sopenharmony_ci reg |= c->q_comp_num; 4458c2ecf20Sopenharmony_ci } 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci cppi_writel(reg, c->gcr_reg); 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* 4508c2ecf20Sopenharmony_ci * We don't use writel() but __raw_writel() so we have to make sure 4518c2ecf20Sopenharmony_ci * that the DMA descriptor in coherent memory made to the main memory 4528c2ecf20Sopenharmony_ci * before starting the dma engine. 4538c2ecf20Sopenharmony_ci */ 4548c2ecf20Sopenharmony_ci __iowmb(); 4558c2ecf20Sopenharmony_ci 4568c2ecf20Sopenharmony_ci /* 4578c2ecf20Sopenharmony_ci * DMA transfers can take at least 200ms to complete with USB mass 4588c2ecf20Sopenharmony_ci * storage connected. To prevent autosuspend timeouts, we must use 4598c2ecf20Sopenharmony_ci * pm_runtime_get/put() when chan_busy[] is modified. This will get 4608c2ecf20Sopenharmony_ci * cleared in desc_to_chan() or cppi41_stop_chan() depending on the 4618c2ecf20Sopenharmony_ci * outcome of the transfer. 4628c2ecf20Sopenharmony_ci */ 4638c2ecf20Sopenharmony_ci pm_runtime_get(cdd->ddev.dev); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci desc_phys = lower_32_bits(c->desc_phys); 4668c2ecf20Sopenharmony_ci desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); 4678c2ecf20Sopenharmony_ci WARN_ON(cdd->chan_busy[desc_num]); 4688c2ecf20Sopenharmony_ci cdd->chan_busy[desc_num] = c; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci reg = (sizeof(struct cppi41_desc) - 24) / 4; 4718c2ecf20Sopenharmony_ci reg |= desc_phys; 4728c2ecf20Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + QMGR_QUEUE_D(c->q_num)); 4738c2ecf20Sopenharmony_ci} 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci/* 4768c2ecf20Sopenharmony_ci * Caller must hold cdd->lock to prevent push_desc_queue() 4778c2ecf20Sopenharmony_ci * getting called out of order. We have both cppi41_dma_issue_pending() 4788c2ecf20Sopenharmony_ci * and cppi41_runtime_resume() call this function. 4798c2ecf20Sopenharmony_ci */ 4808c2ecf20Sopenharmony_cistatic void cppi41_run_queue(struct cppi41_dd *cdd) 4818c2ecf20Sopenharmony_ci{ 4828c2ecf20Sopenharmony_ci struct cppi41_channel *c, *_c; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci list_for_each_entry_safe(c, _c, &cdd->pending, node) { 4858c2ecf20Sopenharmony_ci push_desc_queue(c); 4868c2ecf20Sopenharmony_ci list_del(&c->node); 4878c2ecf20Sopenharmony_ci } 4888c2ecf20Sopenharmony_ci} 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_cistatic void cppi41_dma_issue_pending(struct dma_chan *chan) 4918c2ecf20Sopenharmony_ci{ 4928c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 4938c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 4948c2ecf20Sopenharmony_ci unsigned long flags; 4958c2ecf20Sopenharmony_ci int error; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci error = pm_runtime_get(cdd->ddev.dev); 4988c2ecf20Sopenharmony_ci if ((error != -EINPROGRESS) && error < 0) { 4998c2ecf20Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 5008c2ecf20Sopenharmony_ci dev_err(cdd->ddev.dev, "Failed to pm_runtime_get: %i\n", 5018c2ecf20Sopenharmony_ci error); 5028c2ecf20Sopenharmony_ci 5038c2ecf20Sopenharmony_ci return; 5048c2ecf20Sopenharmony_ci } 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 5078c2ecf20Sopenharmony_ci list_add_tail(&c->node, &cdd->pending); 5088c2ecf20Sopenharmony_ci if (!cdd->is_suspended) 5098c2ecf20Sopenharmony_ci cppi41_run_queue(cdd); 5108c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 5138c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 5148c2ecf20Sopenharmony_ci} 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_cistatic u32 get_host_pd0(u32 length) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci u32 reg; 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci reg = DESC_TYPE_HOST << DESC_TYPE; 5218c2ecf20Sopenharmony_ci reg |= length; 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci return reg; 5248c2ecf20Sopenharmony_ci} 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_cistatic u32 get_host_pd1(struct cppi41_channel *c) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci u32 reg; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci reg = 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci return reg; 5338c2ecf20Sopenharmony_ci} 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cistatic u32 get_host_pd2(struct cppi41_channel *c) 5368c2ecf20Sopenharmony_ci{ 5378c2ecf20Sopenharmony_ci u32 reg; 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci reg = DESC_TYPE_USB; 5408c2ecf20Sopenharmony_ci reg |= c->q_comp_num; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return reg; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_cistatic u32 get_host_pd3(u32 length) 5468c2ecf20Sopenharmony_ci{ 5478c2ecf20Sopenharmony_ci u32 reg; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* PD3 = packet size */ 5508c2ecf20Sopenharmony_ci reg = length; 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci return reg; 5538c2ecf20Sopenharmony_ci} 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_cistatic u32 get_host_pd6(u32 length) 5568c2ecf20Sopenharmony_ci{ 5578c2ecf20Sopenharmony_ci u32 reg; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci /* PD6 buffer size */ 5608c2ecf20Sopenharmony_ci reg = DESC_PD_COMPLETE; 5618c2ecf20Sopenharmony_ci reg |= length; 5628c2ecf20Sopenharmony_ci 5638c2ecf20Sopenharmony_ci return reg; 5648c2ecf20Sopenharmony_ci} 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_cistatic u32 get_host_pd4_or_7(u32 addr) 5678c2ecf20Sopenharmony_ci{ 5688c2ecf20Sopenharmony_ci u32 reg; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci reg = addr; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return reg; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic u32 get_host_pd5(void) 5768c2ecf20Sopenharmony_ci{ 5778c2ecf20Sopenharmony_ci u32 reg; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci reg = 0; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci return reg; 5828c2ecf20Sopenharmony_ci} 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_cistatic struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg( 5858c2ecf20Sopenharmony_ci struct dma_chan *chan, struct scatterlist *sgl, unsigned sg_len, 5868c2ecf20Sopenharmony_ci enum dma_transfer_direction dir, unsigned long tx_flags, void *context) 5878c2ecf20Sopenharmony_ci{ 5888c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 5898c2ecf20Sopenharmony_ci struct dma_async_tx_descriptor *txd = NULL; 5908c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 5918c2ecf20Sopenharmony_ci struct cppi41_desc *d; 5928c2ecf20Sopenharmony_ci struct scatterlist *sg; 5938c2ecf20Sopenharmony_ci unsigned int i; 5948c2ecf20Sopenharmony_ci int error; 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci error = pm_runtime_get(cdd->ddev.dev); 5978c2ecf20Sopenharmony_ci if (error < 0) { 5988c2ecf20Sopenharmony_ci pm_runtime_put_noidle(cdd->ddev.dev); 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci return NULL; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci 6038c2ecf20Sopenharmony_ci if (cdd->is_suspended) 6048c2ecf20Sopenharmony_ci goto err_out_not_ready; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci d = c->desc; 6078c2ecf20Sopenharmony_ci for_each_sg(sgl, sg, sg_len, i) { 6088c2ecf20Sopenharmony_ci u32 addr; 6098c2ecf20Sopenharmony_ci u32 len; 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci /* We need to use more than one desc once musb supports sg */ 6128c2ecf20Sopenharmony_ci addr = lower_32_bits(sg_dma_address(sg)); 6138c2ecf20Sopenharmony_ci len = sg_dma_len(sg); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci d->pd0 = get_host_pd0(len); 6168c2ecf20Sopenharmony_ci d->pd1 = get_host_pd1(c); 6178c2ecf20Sopenharmony_ci d->pd2 = get_host_pd2(c); 6188c2ecf20Sopenharmony_ci d->pd3 = get_host_pd3(len); 6198c2ecf20Sopenharmony_ci d->pd4 = get_host_pd4_or_7(addr); 6208c2ecf20Sopenharmony_ci d->pd5 = get_host_pd5(); 6218c2ecf20Sopenharmony_ci d->pd6 = get_host_pd6(len); 6228c2ecf20Sopenharmony_ci d->pd7 = get_host_pd4_or_7(addr); 6238c2ecf20Sopenharmony_ci 6248c2ecf20Sopenharmony_ci d++; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci txd = &c->txd; 6288c2ecf20Sopenharmony_ci 6298c2ecf20Sopenharmony_cierr_out_not_ready: 6308c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(cdd->ddev.dev); 6318c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(cdd->ddev.dev); 6328c2ecf20Sopenharmony_ci 6338c2ecf20Sopenharmony_ci return txd; 6348c2ecf20Sopenharmony_ci} 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_cistatic void cppi41_compute_td_desc(struct cppi41_desc *d) 6378c2ecf20Sopenharmony_ci{ 6388c2ecf20Sopenharmony_ci d->pd0 = DESC_TYPE_TEARD << DESC_TYPE; 6398c2ecf20Sopenharmony_ci} 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_cistatic int cppi41_tear_down_chan(struct cppi41_channel *c) 6428c2ecf20Sopenharmony_ci{ 6438c2ecf20Sopenharmony_ci struct dmaengine_result abort_result; 6448c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 6458c2ecf20Sopenharmony_ci struct cppi41_desc *td; 6468c2ecf20Sopenharmony_ci u32 reg; 6478c2ecf20Sopenharmony_ci u32 desc_phys; 6488c2ecf20Sopenharmony_ci u32 td_desc_phys; 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci td = cdd->cd; 6518c2ecf20Sopenharmony_ci td += cdd->first_td_desc; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci td_desc_phys = cdd->descs_phys; 6548c2ecf20Sopenharmony_ci td_desc_phys += cdd->first_td_desc * sizeof(struct cppi41_desc); 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (!c->td_queued) { 6578c2ecf20Sopenharmony_ci cppi41_compute_td_desc(td); 6588c2ecf20Sopenharmony_ci __iowmb(); 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci reg = (sizeof(struct cppi41_desc) - 24) / 4; 6618c2ecf20Sopenharmony_ci reg |= td_desc_phys; 6628c2ecf20Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + 6638c2ecf20Sopenharmony_ci QMGR_QUEUE_D(cdd->td_queue.submit)); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci reg = GCR_CHAN_ENABLE; 6668c2ecf20Sopenharmony_ci if (!c->is_tx) { 6678c2ecf20Sopenharmony_ci reg |= GCR_STARV_RETRY; 6688c2ecf20Sopenharmony_ci reg |= GCR_DESC_TYPE_HOST; 6698c2ecf20Sopenharmony_ci reg |= cdd->td_queue.complete; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci reg |= GCR_TEARDOWN; 6728c2ecf20Sopenharmony_ci cppi_writel(reg, c->gcr_reg); 6738c2ecf20Sopenharmony_ci c->td_queued = 1; 6748c2ecf20Sopenharmony_ci c->td_retry = 500; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (!c->td_seen || !c->td_desc_seen) { 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, cdd->td_queue.complete); 6808c2ecf20Sopenharmony_ci if (!desc_phys && c->is_tx) 6818c2ecf20Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci if (desc_phys == c->desc_phys) { 6848c2ecf20Sopenharmony_ci c->td_desc_seen = 1; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci } else if (desc_phys == td_desc_phys) { 6878c2ecf20Sopenharmony_ci u32 pd0; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci __iormb(); 6908c2ecf20Sopenharmony_ci pd0 = td->pd0; 6918c2ecf20Sopenharmony_ci WARN_ON((pd0 >> DESC_TYPE) != DESC_TYPE_TEARD); 6928c2ecf20Sopenharmony_ci WARN_ON(!c->is_tx && !(pd0 & TD_DESC_IS_RX)); 6938c2ecf20Sopenharmony_ci WARN_ON((pd0 & 0x1f) != c->port_num); 6948c2ecf20Sopenharmony_ci c->td_seen = 1; 6958c2ecf20Sopenharmony_ci } else if (desc_phys) { 6968c2ecf20Sopenharmony_ci WARN_ON_ONCE(1); 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci c->td_retry--; 7008c2ecf20Sopenharmony_ci /* 7018c2ecf20Sopenharmony_ci * If the TX descriptor / channel is in use, the caller needs to poke 7028c2ecf20Sopenharmony_ci * his TD bit multiple times. After that he hardware releases the 7038c2ecf20Sopenharmony_ci * transfer descriptor followed by TD descriptor. Waiting seems not to 7048c2ecf20Sopenharmony_ci * cause any difference. 7058c2ecf20Sopenharmony_ci * RX seems to be thrown out right away. However once the TearDown 7068c2ecf20Sopenharmony_ci * descriptor gets through we are done. If we have seens the transfer 7078c2ecf20Sopenharmony_ci * descriptor before the TD we fetch it from enqueue, it has to be 7088c2ecf20Sopenharmony_ci * there waiting for us. 7098c2ecf20Sopenharmony_ci */ 7108c2ecf20Sopenharmony_ci if (!c->td_seen && c->td_retry) { 7118c2ecf20Sopenharmony_ci udelay(1); 7128c2ecf20Sopenharmony_ci return -EAGAIN; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci WARN_ON(!c->td_retry); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci if (!c->td_desc_seen) { 7178c2ecf20Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_num); 7188c2ecf20Sopenharmony_ci if (!desc_phys) 7198c2ecf20Sopenharmony_ci desc_phys = cppi41_pop_desc(cdd, c->q_comp_num); 7208c2ecf20Sopenharmony_ci WARN_ON(!desc_phys); 7218c2ecf20Sopenharmony_ci } 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci c->td_queued = 0; 7248c2ecf20Sopenharmony_ci c->td_seen = 0; 7258c2ecf20Sopenharmony_ci c->td_desc_seen = 0; 7268c2ecf20Sopenharmony_ci cppi_writel(0, c->gcr_reg); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci /* Invoke the callback to do the necessary clean-up */ 7298c2ecf20Sopenharmony_ci abort_result.result = DMA_TRANS_ABORTED; 7308c2ecf20Sopenharmony_ci dma_cookie_complete(&c->txd); 7318c2ecf20Sopenharmony_ci dmaengine_desc_get_callback_invoke(&c->txd, &abort_result); 7328c2ecf20Sopenharmony_ci 7338c2ecf20Sopenharmony_ci return 0; 7348c2ecf20Sopenharmony_ci} 7358c2ecf20Sopenharmony_ci 7368c2ecf20Sopenharmony_cistatic int cppi41_stop_chan(struct dma_chan *chan) 7378c2ecf20Sopenharmony_ci{ 7388c2ecf20Sopenharmony_ci struct cppi41_channel *c = to_cpp41_chan(chan); 7398c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = c->cdd; 7408c2ecf20Sopenharmony_ci u32 desc_num; 7418c2ecf20Sopenharmony_ci u32 desc_phys; 7428c2ecf20Sopenharmony_ci int ret; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci desc_phys = lower_32_bits(c->desc_phys); 7458c2ecf20Sopenharmony_ci desc_num = (desc_phys - cdd->descs_phys) / sizeof(struct cppi41_desc); 7468c2ecf20Sopenharmony_ci if (!cdd->chan_busy[desc_num]) { 7478c2ecf20Sopenharmony_ci struct cppi41_channel *cc, *_ct; 7488c2ecf20Sopenharmony_ci 7498c2ecf20Sopenharmony_ci /* 7508c2ecf20Sopenharmony_ci * channels might still be in the pendling list if 7518c2ecf20Sopenharmony_ci * cppi41_dma_issue_pending() is called after 7528c2ecf20Sopenharmony_ci * cppi41_runtime_suspend() is called 7538c2ecf20Sopenharmony_ci */ 7548c2ecf20Sopenharmony_ci list_for_each_entry_safe(cc, _ct, &cdd->pending, node) { 7558c2ecf20Sopenharmony_ci if (cc != c) 7568c2ecf20Sopenharmony_ci continue; 7578c2ecf20Sopenharmony_ci list_del(&cc->node); 7588c2ecf20Sopenharmony_ci break; 7598c2ecf20Sopenharmony_ci } 7608c2ecf20Sopenharmony_ci return 0; 7618c2ecf20Sopenharmony_ci } 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ret = cppi41_tear_down_chan(c); 7648c2ecf20Sopenharmony_ci if (ret) 7658c2ecf20Sopenharmony_ci return ret; 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci WARN_ON(!cdd->chan_busy[desc_num]); 7688c2ecf20Sopenharmony_ci cdd->chan_busy[desc_num] = NULL; 7698c2ecf20Sopenharmony_ci 7708c2ecf20Sopenharmony_ci /* Usecount for chan_busy[], paired with push_desc_queue() */ 7718c2ecf20Sopenharmony_ci pm_runtime_put(cdd->ddev.dev); 7728c2ecf20Sopenharmony_ci 7738c2ecf20Sopenharmony_ci return 0; 7748c2ecf20Sopenharmony_ci} 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_cistatic int cppi41_add_chans(struct device *dev, struct cppi41_dd *cdd) 7778c2ecf20Sopenharmony_ci{ 7788c2ecf20Sopenharmony_ci struct cppi41_channel *cchan, *chans; 7798c2ecf20Sopenharmony_ci int i; 7808c2ecf20Sopenharmony_ci u32 n_chans = cdd->n_chans; 7818c2ecf20Sopenharmony_ci 7828c2ecf20Sopenharmony_ci /* 7838c2ecf20Sopenharmony_ci * The channels can only be used as TX or as RX. So we add twice 7848c2ecf20Sopenharmony_ci * that much dma channels because USB can only do RX or TX. 7858c2ecf20Sopenharmony_ci */ 7868c2ecf20Sopenharmony_ci n_chans *= 2; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci chans = devm_kcalloc(dev, n_chans, sizeof(*chans), GFP_KERNEL); 7898c2ecf20Sopenharmony_ci if (!chans) 7908c2ecf20Sopenharmony_ci return -ENOMEM; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci for (i = 0; i < n_chans; i++) { 7938c2ecf20Sopenharmony_ci cchan = &chans[i]; 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ci cchan->cdd = cdd; 7968c2ecf20Sopenharmony_ci if (i & 1) { 7978c2ecf20Sopenharmony_ci cchan->gcr_reg = cdd->ctrl_mem + DMA_TXGCR(i >> 1); 7988c2ecf20Sopenharmony_ci cchan->is_tx = 1; 7998c2ecf20Sopenharmony_ci } else { 8008c2ecf20Sopenharmony_ci cchan->gcr_reg = cdd->ctrl_mem + DMA_RXGCR(i >> 1); 8018c2ecf20Sopenharmony_ci cchan->is_tx = 0; 8028c2ecf20Sopenharmony_ci } 8038c2ecf20Sopenharmony_ci cchan->port_num = i >> 1; 8048c2ecf20Sopenharmony_ci cchan->desc = &cdd->cd[i]; 8058c2ecf20Sopenharmony_ci cchan->desc_phys = cdd->descs_phys; 8068c2ecf20Sopenharmony_ci cchan->desc_phys += i * sizeof(struct cppi41_desc); 8078c2ecf20Sopenharmony_ci cchan->chan.device = &cdd->ddev; 8088c2ecf20Sopenharmony_ci list_add_tail(&cchan->chan.device_node, &cdd->ddev.channels); 8098c2ecf20Sopenharmony_ci } 8108c2ecf20Sopenharmony_ci cdd->first_td_desc = n_chans; 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_ci return 0; 8138c2ecf20Sopenharmony_ci} 8148c2ecf20Sopenharmony_ci 8158c2ecf20Sopenharmony_cistatic void purge_descs(struct device *dev, struct cppi41_dd *cdd) 8168c2ecf20Sopenharmony_ci{ 8178c2ecf20Sopenharmony_ci unsigned int mem_decs; 8188c2ecf20Sopenharmony_ci int i; 8198c2ecf20Sopenharmony_ci 8208c2ecf20Sopenharmony_ci mem_decs = ALLOC_DECS_NUM * sizeof(struct cppi41_desc); 8218c2ecf20Sopenharmony_ci 8228c2ecf20Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) { 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_MEMBASE(i)); 8258c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_MEMCTRL(i)); 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci dma_free_coherent(dev, mem_decs, cdd->cd, 8288c2ecf20Sopenharmony_ci cdd->descs_phys); 8298c2ecf20Sopenharmony_ci } 8308c2ecf20Sopenharmony_ci} 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_cistatic void disable_sched(struct cppi41_dd *cdd) 8338c2ecf20Sopenharmony_ci{ 8348c2ecf20Sopenharmony_ci cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); 8358c2ecf20Sopenharmony_ci} 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_cistatic void deinit_cppi41(struct device *dev, struct cppi41_dd *cdd) 8388c2ecf20Sopenharmony_ci{ 8398c2ecf20Sopenharmony_ci disable_sched(cdd); 8408c2ecf20Sopenharmony_ci 8418c2ecf20Sopenharmony_ci purge_descs(dev, cdd); 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); 8448c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM0_BASE); 8458c2ecf20Sopenharmony_ci dma_free_coherent(dev, QMGR_SCRATCH_SIZE, cdd->qmgr_scratch, 8468c2ecf20Sopenharmony_ci cdd->scratch_phys); 8478c2ecf20Sopenharmony_ci} 8488c2ecf20Sopenharmony_ci 8498c2ecf20Sopenharmony_cistatic int init_descs(struct device *dev, struct cppi41_dd *cdd) 8508c2ecf20Sopenharmony_ci{ 8518c2ecf20Sopenharmony_ci unsigned int desc_size; 8528c2ecf20Sopenharmony_ci unsigned int mem_decs; 8538c2ecf20Sopenharmony_ci int i; 8548c2ecf20Sopenharmony_ci u32 reg; 8558c2ecf20Sopenharmony_ci u32 idx; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cppi41_desc) & 8588c2ecf20Sopenharmony_ci (sizeof(struct cppi41_desc) - 1)); 8598c2ecf20Sopenharmony_ci BUILD_BUG_ON(sizeof(struct cppi41_desc) < 32); 8608c2ecf20Sopenharmony_ci BUILD_BUG_ON(ALLOC_DECS_NUM < 32); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci desc_size = sizeof(struct cppi41_desc); 8638c2ecf20Sopenharmony_ci mem_decs = ALLOC_DECS_NUM * desc_size; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci idx = 0; 8668c2ecf20Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) { 8678c2ecf20Sopenharmony_ci 8688c2ecf20Sopenharmony_ci reg = idx << QMGR_MEMCTRL_IDX_SH; 8698c2ecf20Sopenharmony_ci reg |= (ilog2(desc_size) - 5) << QMGR_MEMCTRL_DESC_SH; 8708c2ecf20Sopenharmony_ci reg |= ilog2(ALLOC_DECS_NUM) - 5; 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci BUILD_BUG_ON(DESCS_AREAS != 1); 8738c2ecf20Sopenharmony_ci cdd->cd = dma_alloc_coherent(dev, mem_decs, 8748c2ecf20Sopenharmony_ci &cdd->descs_phys, GFP_KERNEL); 8758c2ecf20Sopenharmony_ci if (!cdd->cd) 8768c2ecf20Sopenharmony_ci return -ENOMEM; 8778c2ecf20Sopenharmony_ci 8788c2ecf20Sopenharmony_ci cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); 8798c2ecf20Sopenharmony_ci cppi_writel(reg, cdd->qmgr_mem + QMGR_MEMCTRL(i)); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci idx += ALLOC_DECS_NUM; 8828c2ecf20Sopenharmony_ci } 8838c2ecf20Sopenharmony_ci return 0; 8848c2ecf20Sopenharmony_ci} 8858c2ecf20Sopenharmony_ci 8868c2ecf20Sopenharmony_cistatic void init_sched(struct cppi41_dd *cdd) 8878c2ecf20Sopenharmony_ci{ 8888c2ecf20Sopenharmony_ci unsigned ch; 8898c2ecf20Sopenharmony_ci unsigned word; 8908c2ecf20Sopenharmony_ci u32 reg; 8918c2ecf20Sopenharmony_ci 8928c2ecf20Sopenharmony_ci word = 0; 8938c2ecf20Sopenharmony_ci cppi_writel(0, cdd->sched_mem + DMA_SCHED_CTRL); 8948c2ecf20Sopenharmony_ci for (ch = 0; ch < cdd->n_chans; ch += 2) { 8958c2ecf20Sopenharmony_ci 8968c2ecf20Sopenharmony_ci reg = SCHED_ENTRY0_CHAN(ch); 8978c2ecf20Sopenharmony_ci reg |= SCHED_ENTRY1_CHAN(ch) | SCHED_ENTRY1_IS_RX; 8988c2ecf20Sopenharmony_ci 8998c2ecf20Sopenharmony_ci reg |= SCHED_ENTRY2_CHAN(ch + 1); 9008c2ecf20Sopenharmony_ci reg |= SCHED_ENTRY3_CHAN(ch + 1) | SCHED_ENTRY3_IS_RX; 9018c2ecf20Sopenharmony_ci cppi_writel(reg, cdd->sched_mem + DMA_SCHED_WORD(word)); 9028c2ecf20Sopenharmony_ci word++; 9038c2ecf20Sopenharmony_ci } 9048c2ecf20Sopenharmony_ci reg = cdd->n_chans * 2 - 1; 9058c2ecf20Sopenharmony_ci reg |= DMA_SCHED_CTRL_EN; 9068c2ecf20Sopenharmony_ci cppi_writel(reg, cdd->sched_mem + DMA_SCHED_CTRL); 9078c2ecf20Sopenharmony_ci} 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_cistatic int init_cppi41(struct device *dev, struct cppi41_dd *cdd) 9108c2ecf20Sopenharmony_ci{ 9118c2ecf20Sopenharmony_ci int ret; 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci BUILD_BUG_ON(QMGR_SCRATCH_SIZE > ((1 << 14) - 1)); 9148c2ecf20Sopenharmony_ci cdd->qmgr_scratch = dma_alloc_coherent(dev, QMGR_SCRATCH_SIZE, 9158c2ecf20Sopenharmony_ci &cdd->scratch_phys, GFP_KERNEL); 9168c2ecf20Sopenharmony_ci if (!cdd->qmgr_scratch) 9178c2ecf20Sopenharmony_ci return -ENOMEM; 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_ci cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); 9208c2ecf20Sopenharmony_ci cppi_writel(TOTAL_DESCS_NUM, cdd->qmgr_mem + QMGR_LRAM_SIZE); 9218c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci ret = init_descs(dev, cdd); 9248c2ecf20Sopenharmony_ci if (ret) 9258c2ecf20Sopenharmony_ci goto err_td; 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci cppi_writel(cdd->td_queue.submit, cdd->ctrl_mem + DMA_TDFDQ); 9288c2ecf20Sopenharmony_ci init_sched(cdd); 9298c2ecf20Sopenharmony_ci 9308c2ecf20Sopenharmony_ci return 0; 9318c2ecf20Sopenharmony_cierr_td: 9328c2ecf20Sopenharmony_ci deinit_cppi41(dev, cdd); 9338c2ecf20Sopenharmony_ci return ret; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_cistatic struct platform_driver cpp41_dma_driver; 9378c2ecf20Sopenharmony_ci/* 9388c2ecf20Sopenharmony_ci * The param format is: 9398c2ecf20Sopenharmony_ci * X Y 9408c2ecf20Sopenharmony_ci * X: Port 9418c2ecf20Sopenharmony_ci * Y: 0 = RX else TX 9428c2ecf20Sopenharmony_ci */ 9438c2ecf20Sopenharmony_ci#define INFO_PORT 0 9448c2ecf20Sopenharmony_ci#define INFO_IS_TX 1 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_cistatic bool cpp41_dma_filter_fn(struct dma_chan *chan, void *param) 9478c2ecf20Sopenharmony_ci{ 9488c2ecf20Sopenharmony_ci struct cppi41_channel *cchan; 9498c2ecf20Sopenharmony_ci struct cppi41_dd *cdd; 9508c2ecf20Sopenharmony_ci const struct chan_queues *queues; 9518c2ecf20Sopenharmony_ci u32 *num = param; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci if (chan->device->dev->driver != &cpp41_dma_driver.driver) 9548c2ecf20Sopenharmony_ci return false; 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci cchan = to_cpp41_chan(chan); 9578c2ecf20Sopenharmony_ci 9588c2ecf20Sopenharmony_ci if (cchan->port_num != num[INFO_PORT]) 9598c2ecf20Sopenharmony_ci return false; 9608c2ecf20Sopenharmony_ci 9618c2ecf20Sopenharmony_ci if (cchan->is_tx && !num[INFO_IS_TX]) 9628c2ecf20Sopenharmony_ci return false; 9638c2ecf20Sopenharmony_ci cdd = cchan->cdd; 9648c2ecf20Sopenharmony_ci if (cchan->is_tx) 9658c2ecf20Sopenharmony_ci queues = cdd->queues_tx; 9668c2ecf20Sopenharmony_ci else 9678c2ecf20Sopenharmony_ci queues = cdd->queues_rx; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci BUILD_BUG_ON(ARRAY_SIZE(am335x_usb_queues_rx) != 9708c2ecf20Sopenharmony_ci ARRAY_SIZE(am335x_usb_queues_tx)); 9718c2ecf20Sopenharmony_ci if (WARN_ON(cchan->port_num >= ARRAY_SIZE(am335x_usb_queues_rx))) 9728c2ecf20Sopenharmony_ci return false; 9738c2ecf20Sopenharmony_ci 9748c2ecf20Sopenharmony_ci cchan->q_num = queues[cchan->port_num].submit; 9758c2ecf20Sopenharmony_ci cchan->q_comp_num = queues[cchan->port_num].complete; 9768c2ecf20Sopenharmony_ci return true; 9778c2ecf20Sopenharmony_ci} 9788c2ecf20Sopenharmony_ci 9798c2ecf20Sopenharmony_cistatic struct of_dma_filter_info cpp41_dma_info = { 9808c2ecf20Sopenharmony_ci .filter_fn = cpp41_dma_filter_fn, 9818c2ecf20Sopenharmony_ci}; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_cistatic struct dma_chan *cppi41_dma_xlate(struct of_phandle_args *dma_spec, 9848c2ecf20Sopenharmony_ci struct of_dma *ofdma) 9858c2ecf20Sopenharmony_ci{ 9868c2ecf20Sopenharmony_ci int count = dma_spec->args_count; 9878c2ecf20Sopenharmony_ci struct of_dma_filter_info *info = ofdma->of_dma_data; 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (!info || !info->filter_fn) 9908c2ecf20Sopenharmony_ci return NULL; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (count != 2) 9938c2ecf20Sopenharmony_ci return NULL; 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return dma_request_channel(info->dma_cap, info->filter_fn, 9968c2ecf20Sopenharmony_ci &dma_spec->args[0]); 9978c2ecf20Sopenharmony_ci} 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_cistatic const struct cppi_glue_infos am335x_usb_infos = { 10008c2ecf20Sopenharmony_ci .queues_rx = am335x_usb_queues_rx, 10018c2ecf20Sopenharmony_ci .queues_tx = am335x_usb_queues_tx, 10028c2ecf20Sopenharmony_ci .td_queue = { .submit = 31, .complete = 0 }, 10038c2ecf20Sopenharmony_ci .first_completion_queue = 93, 10048c2ecf20Sopenharmony_ci .qmgr_num_pend = 5, 10058c2ecf20Sopenharmony_ci}; 10068c2ecf20Sopenharmony_ci 10078c2ecf20Sopenharmony_cistatic const struct cppi_glue_infos da8xx_usb_infos = { 10088c2ecf20Sopenharmony_ci .queues_rx = da8xx_usb_queues_rx, 10098c2ecf20Sopenharmony_ci .queues_tx = da8xx_usb_queues_tx, 10108c2ecf20Sopenharmony_ci .td_queue = { .submit = 31, .complete = 0 }, 10118c2ecf20Sopenharmony_ci .first_completion_queue = 24, 10128c2ecf20Sopenharmony_ci .qmgr_num_pend = 2, 10138c2ecf20Sopenharmony_ci}; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_cistatic const struct of_device_id cppi41_dma_ids[] = { 10168c2ecf20Sopenharmony_ci { .compatible = "ti,am3359-cppi41", .data = &am335x_usb_infos}, 10178c2ecf20Sopenharmony_ci { .compatible = "ti,da830-cppi41", .data = &da8xx_usb_infos}, 10188c2ecf20Sopenharmony_ci {}, 10198c2ecf20Sopenharmony_ci}; 10208c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, cppi41_dma_ids); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistatic const struct cppi_glue_infos *get_glue_info(struct device *dev) 10238c2ecf20Sopenharmony_ci{ 10248c2ecf20Sopenharmony_ci const struct of_device_id *of_id; 10258c2ecf20Sopenharmony_ci 10268c2ecf20Sopenharmony_ci of_id = of_match_node(cppi41_dma_ids, dev->of_node); 10278c2ecf20Sopenharmony_ci if (!of_id) 10288c2ecf20Sopenharmony_ci return NULL; 10298c2ecf20Sopenharmony_ci return of_id->data; 10308c2ecf20Sopenharmony_ci} 10318c2ecf20Sopenharmony_ci 10328c2ecf20Sopenharmony_ci#define CPPI41_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \ 10338c2ecf20Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \ 10348c2ecf20Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \ 10358c2ecf20Sopenharmony_ci BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)) 10368c2ecf20Sopenharmony_ci 10378c2ecf20Sopenharmony_cistatic int cppi41_dma_probe(struct platform_device *pdev) 10388c2ecf20Sopenharmony_ci{ 10398c2ecf20Sopenharmony_ci struct cppi41_dd *cdd; 10408c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 10418c2ecf20Sopenharmony_ci const struct cppi_glue_infos *glue_info; 10428c2ecf20Sopenharmony_ci struct resource *mem; 10438c2ecf20Sopenharmony_ci int index; 10448c2ecf20Sopenharmony_ci int irq; 10458c2ecf20Sopenharmony_ci int ret; 10468c2ecf20Sopenharmony_ci 10478c2ecf20Sopenharmony_ci glue_info = get_glue_info(dev); 10488c2ecf20Sopenharmony_ci if (!glue_info) 10498c2ecf20Sopenharmony_ci return -EINVAL; 10508c2ecf20Sopenharmony_ci 10518c2ecf20Sopenharmony_ci cdd = devm_kzalloc(&pdev->dev, sizeof(*cdd), GFP_KERNEL); 10528c2ecf20Sopenharmony_ci if (!cdd) 10538c2ecf20Sopenharmony_ci return -ENOMEM; 10548c2ecf20Sopenharmony_ci 10558c2ecf20Sopenharmony_ci dma_cap_set(DMA_SLAVE, cdd->ddev.cap_mask); 10568c2ecf20Sopenharmony_ci cdd->ddev.device_alloc_chan_resources = cppi41_dma_alloc_chan_resources; 10578c2ecf20Sopenharmony_ci cdd->ddev.device_free_chan_resources = cppi41_dma_free_chan_resources; 10588c2ecf20Sopenharmony_ci cdd->ddev.device_tx_status = cppi41_dma_tx_status; 10598c2ecf20Sopenharmony_ci cdd->ddev.device_issue_pending = cppi41_dma_issue_pending; 10608c2ecf20Sopenharmony_ci cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg; 10618c2ecf20Sopenharmony_ci cdd->ddev.device_terminate_all = cppi41_stop_chan; 10628c2ecf20Sopenharmony_ci cdd->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 10638c2ecf20Sopenharmony_ci cdd->ddev.src_addr_widths = CPPI41_DMA_BUSWIDTHS; 10648c2ecf20Sopenharmony_ci cdd->ddev.dst_addr_widths = CPPI41_DMA_BUSWIDTHS; 10658c2ecf20Sopenharmony_ci cdd->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 10668c2ecf20Sopenharmony_ci cdd->ddev.dev = dev; 10678c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cdd->ddev.channels); 10688c2ecf20Sopenharmony_ci cpp41_dma_info.dma_cap = cdd->ddev.cap_mask; 10698c2ecf20Sopenharmony_ci 10708c2ecf20Sopenharmony_ci index = of_property_match_string(dev->of_node, 10718c2ecf20Sopenharmony_ci "reg-names", "controller"); 10728c2ecf20Sopenharmony_ci if (index < 0) 10738c2ecf20Sopenharmony_ci return index; 10748c2ecf20Sopenharmony_ci 10758c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, index); 10768c2ecf20Sopenharmony_ci cdd->ctrl_mem = devm_ioremap_resource(dev, mem); 10778c2ecf20Sopenharmony_ci if (IS_ERR(cdd->ctrl_mem)) 10788c2ecf20Sopenharmony_ci return PTR_ERR(cdd->ctrl_mem); 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 1); 10818c2ecf20Sopenharmony_ci cdd->sched_mem = devm_ioremap_resource(dev, mem); 10828c2ecf20Sopenharmony_ci if (IS_ERR(cdd->sched_mem)) 10838c2ecf20Sopenharmony_ci return PTR_ERR(cdd->sched_mem); 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_ci mem = platform_get_resource(pdev, IORESOURCE_MEM, index + 2); 10868c2ecf20Sopenharmony_ci cdd->qmgr_mem = devm_ioremap_resource(dev, mem); 10878c2ecf20Sopenharmony_ci if (IS_ERR(cdd->qmgr_mem)) 10888c2ecf20Sopenharmony_ci return PTR_ERR(cdd->qmgr_mem); 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci spin_lock_init(&cdd->lock); 10918c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&cdd->pending); 10928c2ecf20Sopenharmony_ci 10938c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, cdd); 10948c2ecf20Sopenharmony_ci 10958c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 10968c2ecf20Sopenharmony_ci pm_runtime_set_autosuspend_delay(dev, 100); 10978c2ecf20Sopenharmony_ci pm_runtime_use_autosuspend(dev); 10988c2ecf20Sopenharmony_ci ret = pm_runtime_get_sync(dev); 10998c2ecf20Sopenharmony_ci if (ret < 0) 11008c2ecf20Sopenharmony_ci goto err_get_sync; 11018c2ecf20Sopenharmony_ci 11028c2ecf20Sopenharmony_ci cdd->queues_rx = glue_info->queues_rx; 11038c2ecf20Sopenharmony_ci cdd->queues_tx = glue_info->queues_tx; 11048c2ecf20Sopenharmony_ci cdd->td_queue = glue_info->td_queue; 11058c2ecf20Sopenharmony_ci cdd->qmgr_num_pend = glue_info->qmgr_num_pend; 11068c2ecf20Sopenharmony_ci cdd->first_completion_queue = glue_info->first_completion_queue; 11078c2ecf20Sopenharmony_ci 11088c2ecf20Sopenharmony_ci ret = of_property_read_u32(dev->of_node, 11098c2ecf20Sopenharmony_ci "#dma-channels", &cdd->n_chans); 11108c2ecf20Sopenharmony_ci if (ret) 11118c2ecf20Sopenharmony_ci goto err_get_n_chans; 11128c2ecf20Sopenharmony_ci 11138c2ecf20Sopenharmony_ci ret = init_cppi41(dev, cdd); 11148c2ecf20Sopenharmony_ci if (ret) 11158c2ecf20Sopenharmony_ci goto err_init_cppi; 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci ret = cppi41_add_chans(dev, cdd); 11188c2ecf20Sopenharmony_ci if (ret) 11198c2ecf20Sopenharmony_ci goto err_chans; 11208c2ecf20Sopenharmony_ci 11218c2ecf20Sopenharmony_ci irq = irq_of_parse_and_map(dev->of_node, 0); 11228c2ecf20Sopenharmony_ci if (!irq) { 11238c2ecf20Sopenharmony_ci ret = -EINVAL; 11248c2ecf20Sopenharmony_ci goto err_chans; 11258c2ecf20Sopenharmony_ci } 11268c2ecf20Sopenharmony_ci 11278c2ecf20Sopenharmony_ci ret = devm_request_irq(&pdev->dev, irq, cppi41_irq, IRQF_SHARED, 11288c2ecf20Sopenharmony_ci dev_name(dev), cdd); 11298c2ecf20Sopenharmony_ci if (ret) 11308c2ecf20Sopenharmony_ci goto err_chans; 11318c2ecf20Sopenharmony_ci cdd->irq = irq; 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci ret = dma_async_device_register(&cdd->ddev); 11348c2ecf20Sopenharmony_ci if (ret) 11358c2ecf20Sopenharmony_ci goto err_chans; 11368c2ecf20Sopenharmony_ci 11378c2ecf20Sopenharmony_ci ret = of_dma_controller_register(dev->of_node, 11388c2ecf20Sopenharmony_ci cppi41_dma_xlate, &cpp41_dma_info); 11398c2ecf20Sopenharmony_ci if (ret) 11408c2ecf20Sopenharmony_ci goto err_of; 11418c2ecf20Sopenharmony_ci 11428c2ecf20Sopenharmony_ci pm_runtime_mark_last_busy(dev); 11438c2ecf20Sopenharmony_ci pm_runtime_put_autosuspend(dev); 11448c2ecf20Sopenharmony_ci 11458c2ecf20Sopenharmony_ci return 0; 11468c2ecf20Sopenharmony_cierr_of: 11478c2ecf20Sopenharmony_ci dma_async_device_unregister(&cdd->ddev); 11488c2ecf20Sopenharmony_cierr_chans: 11498c2ecf20Sopenharmony_ci deinit_cppi41(dev, cdd); 11508c2ecf20Sopenharmony_cierr_init_cppi: 11518c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(dev); 11528c2ecf20Sopenharmony_cierr_get_n_chans: 11538c2ecf20Sopenharmony_cierr_get_sync: 11548c2ecf20Sopenharmony_ci pm_runtime_put_sync(dev); 11558c2ecf20Sopenharmony_ci pm_runtime_disable(dev); 11568c2ecf20Sopenharmony_ci return ret; 11578c2ecf20Sopenharmony_ci} 11588c2ecf20Sopenharmony_ci 11598c2ecf20Sopenharmony_cistatic int cppi41_dma_remove(struct platform_device *pdev) 11608c2ecf20Sopenharmony_ci{ 11618c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = platform_get_drvdata(pdev); 11628c2ecf20Sopenharmony_ci int error; 11638c2ecf20Sopenharmony_ci 11648c2ecf20Sopenharmony_ci error = pm_runtime_get_sync(&pdev->dev); 11658c2ecf20Sopenharmony_ci if (error < 0) 11668c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "%s could not pm_runtime_get: %i\n", 11678c2ecf20Sopenharmony_ci __func__, error); 11688c2ecf20Sopenharmony_ci of_dma_controller_free(pdev->dev.of_node); 11698c2ecf20Sopenharmony_ci dma_async_device_unregister(&cdd->ddev); 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci devm_free_irq(&pdev->dev, cdd->irq, cdd); 11728c2ecf20Sopenharmony_ci deinit_cppi41(&pdev->dev, cdd); 11738c2ecf20Sopenharmony_ci pm_runtime_dont_use_autosuspend(&pdev->dev); 11748c2ecf20Sopenharmony_ci pm_runtime_put_sync(&pdev->dev); 11758c2ecf20Sopenharmony_ci pm_runtime_disable(&pdev->dev); 11768c2ecf20Sopenharmony_ci return 0; 11778c2ecf20Sopenharmony_ci} 11788c2ecf20Sopenharmony_ci 11798c2ecf20Sopenharmony_cistatic int __maybe_unused cppi41_suspend(struct device *dev) 11808c2ecf20Sopenharmony_ci{ 11818c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci cdd->dma_tdfdq = cppi_readl(cdd->ctrl_mem + DMA_TDFDQ); 11848c2ecf20Sopenharmony_ci disable_sched(cdd); 11858c2ecf20Sopenharmony_ci 11868c2ecf20Sopenharmony_ci return 0; 11878c2ecf20Sopenharmony_ci} 11888c2ecf20Sopenharmony_ci 11898c2ecf20Sopenharmony_cistatic int __maybe_unused cppi41_resume(struct device *dev) 11908c2ecf20Sopenharmony_ci{ 11918c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 11928c2ecf20Sopenharmony_ci struct cppi41_channel *c; 11938c2ecf20Sopenharmony_ci int i; 11948c2ecf20Sopenharmony_ci 11958c2ecf20Sopenharmony_ci for (i = 0; i < DESCS_AREAS; i++) 11968c2ecf20Sopenharmony_ci cppi_writel(cdd->descs_phys, cdd->qmgr_mem + QMGR_MEMBASE(i)); 11978c2ecf20Sopenharmony_ci 11988c2ecf20Sopenharmony_ci list_for_each_entry(c, &cdd->ddev.channels, chan.device_node) 11998c2ecf20Sopenharmony_ci if (!c->is_tx) 12008c2ecf20Sopenharmony_ci cppi_writel(c->q_num, c->gcr_reg + RXHPCRA0); 12018c2ecf20Sopenharmony_ci 12028c2ecf20Sopenharmony_ci init_sched(cdd); 12038c2ecf20Sopenharmony_ci 12048c2ecf20Sopenharmony_ci cppi_writel(cdd->dma_tdfdq, cdd->ctrl_mem + DMA_TDFDQ); 12058c2ecf20Sopenharmony_ci cppi_writel(cdd->scratch_phys, cdd->qmgr_mem + QMGR_LRAM0_BASE); 12068c2ecf20Sopenharmony_ci cppi_writel(QMGR_SCRATCH_SIZE, cdd->qmgr_mem + QMGR_LRAM_SIZE); 12078c2ecf20Sopenharmony_ci cppi_writel(0, cdd->qmgr_mem + QMGR_LRAM1_BASE); 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci return 0; 12108c2ecf20Sopenharmony_ci} 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic int __maybe_unused cppi41_runtime_suspend(struct device *dev) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 12158c2ecf20Sopenharmony_ci unsigned long flags; 12168c2ecf20Sopenharmony_ci 12178c2ecf20Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 12188c2ecf20Sopenharmony_ci cdd->is_suspended = true; 12198c2ecf20Sopenharmony_ci WARN_ON(!list_empty(&cdd->pending)); 12208c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 12218c2ecf20Sopenharmony_ci 12228c2ecf20Sopenharmony_ci return 0; 12238c2ecf20Sopenharmony_ci} 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_cistatic int __maybe_unused cppi41_runtime_resume(struct device *dev) 12268c2ecf20Sopenharmony_ci{ 12278c2ecf20Sopenharmony_ci struct cppi41_dd *cdd = dev_get_drvdata(dev); 12288c2ecf20Sopenharmony_ci unsigned long flags; 12298c2ecf20Sopenharmony_ci 12308c2ecf20Sopenharmony_ci spin_lock_irqsave(&cdd->lock, flags); 12318c2ecf20Sopenharmony_ci cdd->is_suspended = false; 12328c2ecf20Sopenharmony_ci cppi41_run_queue(cdd); 12338c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&cdd->lock, flags); 12348c2ecf20Sopenharmony_ci 12358c2ecf20Sopenharmony_ci return 0; 12368c2ecf20Sopenharmony_ci} 12378c2ecf20Sopenharmony_ci 12388c2ecf20Sopenharmony_cistatic const struct dev_pm_ops cppi41_pm_ops = { 12398c2ecf20Sopenharmony_ci SET_LATE_SYSTEM_SLEEP_PM_OPS(cppi41_suspend, cppi41_resume) 12408c2ecf20Sopenharmony_ci SET_RUNTIME_PM_OPS(cppi41_runtime_suspend, 12418c2ecf20Sopenharmony_ci cppi41_runtime_resume, 12428c2ecf20Sopenharmony_ci NULL) 12438c2ecf20Sopenharmony_ci}; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_cistatic struct platform_driver cpp41_dma_driver = { 12468c2ecf20Sopenharmony_ci .probe = cppi41_dma_probe, 12478c2ecf20Sopenharmony_ci .remove = cppi41_dma_remove, 12488c2ecf20Sopenharmony_ci .driver = { 12498c2ecf20Sopenharmony_ci .name = "cppi41-dma-engine", 12508c2ecf20Sopenharmony_ci .pm = &cppi41_pm_ops, 12518c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(cppi41_dma_ids), 12528c2ecf20Sopenharmony_ci }, 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_cimodule_platform_driver(cpp41_dma_driver); 12568c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 12578c2ecf20Sopenharmony_ciMODULE_AUTHOR("Sebastian Andrzej Siewior <bigeasy@linutronix.de>"); 1258