18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * TI K3 NAVSS Ring Accelerator subsystem driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 98c2ecf20Sopenharmony_ci#include <linux/io.h> 108c2ecf20Sopenharmony_ci#include <linux/init.h> 118c2ecf20Sopenharmony_ci#include <linux/of.h> 128c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 138c2ecf20Sopenharmony_ci#include <linux/sys_soc.h> 148c2ecf20Sopenharmony_ci#include <linux/soc/ti/k3-ringacc.h> 158c2ecf20Sopenharmony_ci#include <linux/soc/ti/ti_sci_protocol.h> 168c2ecf20Sopenharmony_ci#include <linux/soc/ti/ti_sci_inta_msi.h> 178c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 188c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic LIST_HEAD(k3_ringacc_list); 218c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(k3_ringacc_list_lock); 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define K3_RINGACC_CFG_RING_SIZE_ELCNT_MASK GENMASK(19, 0) 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/** 268c2ecf20Sopenharmony_ci * struct k3_ring_rt_regs - The RA realtime Control/Status Registers region 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * @resv_16: Reserved 298c2ecf20Sopenharmony_ci * @db: Ring Doorbell Register 308c2ecf20Sopenharmony_ci * @resv_4: Reserved 318c2ecf20Sopenharmony_ci * @occ: Ring Occupancy Register 328c2ecf20Sopenharmony_ci * @indx: Ring Current Index Register 338c2ecf20Sopenharmony_ci * @hwocc: Ring Hardware Occupancy Register 348c2ecf20Sopenharmony_ci * @hwindx: Ring Hardware Current Index Register 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct k3_ring_rt_regs { 378c2ecf20Sopenharmony_ci u32 resv_16[4]; 388c2ecf20Sopenharmony_ci u32 db; 398c2ecf20Sopenharmony_ci u32 resv_4[1]; 408c2ecf20Sopenharmony_ci u32 occ; 418c2ecf20Sopenharmony_ci u32 indx; 428c2ecf20Sopenharmony_ci u32 hwocc; 438c2ecf20Sopenharmony_ci u32 hwindx; 448c2ecf20Sopenharmony_ci}; 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define K3_RINGACC_RT_REGS_STEP 0x1000 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci/** 498c2ecf20Sopenharmony_ci * struct k3_ring_fifo_regs - The Ring Accelerator Queues Registers region 508c2ecf20Sopenharmony_ci * 518c2ecf20Sopenharmony_ci * @head_data: Ring Head Entry Data Registers 528c2ecf20Sopenharmony_ci * @tail_data: Ring Tail Entry Data Registers 538c2ecf20Sopenharmony_ci * @peek_head_data: Ring Peek Head Entry Data Regs 548c2ecf20Sopenharmony_ci * @peek_tail_data: Ring Peek Tail Entry Data Regs 558c2ecf20Sopenharmony_ci */ 568c2ecf20Sopenharmony_cistruct k3_ring_fifo_regs { 578c2ecf20Sopenharmony_ci u32 head_data[128]; 588c2ecf20Sopenharmony_ci u32 tail_data[128]; 598c2ecf20Sopenharmony_ci u32 peek_head_data[128]; 608c2ecf20Sopenharmony_ci u32 peek_tail_data[128]; 618c2ecf20Sopenharmony_ci}; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/** 648c2ecf20Sopenharmony_ci * struct k3_ringacc_proxy_gcfg_regs - RA Proxy Global Config MMIO Region 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * @revision: Revision Register 678c2ecf20Sopenharmony_ci * @config: Config Register 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_cistruct k3_ringacc_proxy_gcfg_regs { 708c2ecf20Sopenharmony_ci u32 revision; 718c2ecf20Sopenharmony_ci u32 config; 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci#define K3_RINGACC_PROXY_CFG_THREADS_MASK GENMASK(15, 0) 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci/** 778c2ecf20Sopenharmony_ci * struct k3_ringacc_proxy_target_regs - Proxy Datapath MMIO Region 788c2ecf20Sopenharmony_ci * 798c2ecf20Sopenharmony_ci * @control: Proxy Control Register 808c2ecf20Sopenharmony_ci * @status: Proxy Status Register 818c2ecf20Sopenharmony_ci * @resv_512: Reserved 828c2ecf20Sopenharmony_ci * @data: Proxy Data Register 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistruct k3_ringacc_proxy_target_regs { 858c2ecf20Sopenharmony_ci u32 control; 868c2ecf20Sopenharmony_ci u32 status; 878c2ecf20Sopenharmony_ci u8 resv_512[504]; 888c2ecf20Sopenharmony_ci u32 data[128]; 898c2ecf20Sopenharmony_ci}; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci#define K3_RINGACC_PROXY_TARGET_STEP 0x1000 928c2ecf20Sopenharmony_ci#define K3_RINGACC_PROXY_NOT_USED (-1) 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_cienum k3_ringacc_proxy_access_mode { 958c2ecf20Sopenharmony_ci PROXY_ACCESS_MODE_HEAD = 0, 968c2ecf20Sopenharmony_ci PROXY_ACCESS_MODE_TAIL = 1, 978c2ecf20Sopenharmony_ci PROXY_ACCESS_MODE_PEEK_HEAD = 2, 988c2ecf20Sopenharmony_ci PROXY_ACCESS_MODE_PEEK_TAIL = 3, 998c2ecf20Sopenharmony_ci}; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci#define K3_RINGACC_FIFO_WINDOW_SIZE_BYTES (512U) 1028c2ecf20Sopenharmony_ci#define K3_RINGACC_FIFO_REGS_STEP 0x1000 1038c2ecf20Sopenharmony_ci#define K3_RINGACC_MAX_DB_RING_CNT (127U) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistruct k3_ring_ops { 1068c2ecf20Sopenharmony_ci int (*push_tail)(struct k3_ring *ring, void *elm); 1078c2ecf20Sopenharmony_ci int (*push_head)(struct k3_ring *ring, void *elm); 1088c2ecf20Sopenharmony_ci int (*pop_tail)(struct k3_ring *ring, void *elm); 1098c2ecf20Sopenharmony_ci int (*pop_head)(struct k3_ring *ring, void *elm); 1108c2ecf20Sopenharmony_ci}; 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci/** 1138c2ecf20Sopenharmony_ci * struct k3_ring_state - Internal state tracking structure 1148c2ecf20Sopenharmony_ci * 1158c2ecf20Sopenharmony_ci * @free: Number of free entries 1168c2ecf20Sopenharmony_ci * @occ: Occupancy 1178c2ecf20Sopenharmony_ci * @windex: Write index 1188c2ecf20Sopenharmony_ci * @rindex: Read index 1198c2ecf20Sopenharmony_ci */ 1208c2ecf20Sopenharmony_cistruct k3_ring_state { 1218c2ecf20Sopenharmony_ci u32 free; 1228c2ecf20Sopenharmony_ci u32 occ; 1238c2ecf20Sopenharmony_ci u32 windex; 1248c2ecf20Sopenharmony_ci u32 rindex; 1258c2ecf20Sopenharmony_ci}; 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci/** 1288c2ecf20Sopenharmony_ci * struct k3_ring - RA Ring descriptor 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * @rt: Ring control/status registers 1318c2ecf20Sopenharmony_ci * @fifos: Ring queues registers 1328c2ecf20Sopenharmony_ci * @proxy: Ring Proxy Datapath registers 1338c2ecf20Sopenharmony_ci * @ring_mem_dma: Ring buffer dma address 1348c2ecf20Sopenharmony_ci * @ring_mem_virt: Ring buffer virt address 1358c2ecf20Sopenharmony_ci * @ops: Ring operations 1368c2ecf20Sopenharmony_ci * @size: Ring size in elements 1378c2ecf20Sopenharmony_ci * @elm_size: Size of the ring element 1388c2ecf20Sopenharmony_ci * @mode: Ring mode 1398c2ecf20Sopenharmony_ci * @flags: flags 1408c2ecf20Sopenharmony_ci * @ring_id: Ring Id 1418c2ecf20Sopenharmony_ci * @parent: Pointer on struct @k3_ringacc 1428c2ecf20Sopenharmony_ci * @use_count: Use count for shared rings 1438c2ecf20Sopenharmony_ci * @proxy_id: RA Ring Proxy Id (only if @K3_RINGACC_RING_USE_PROXY) 1448c2ecf20Sopenharmony_ci */ 1458c2ecf20Sopenharmony_cistruct k3_ring { 1468c2ecf20Sopenharmony_ci struct k3_ring_rt_regs __iomem *rt; 1478c2ecf20Sopenharmony_ci struct k3_ring_fifo_regs __iomem *fifos; 1488c2ecf20Sopenharmony_ci struct k3_ringacc_proxy_target_regs __iomem *proxy; 1498c2ecf20Sopenharmony_ci dma_addr_t ring_mem_dma; 1508c2ecf20Sopenharmony_ci void *ring_mem_virt; 1518c2ecf20Sopenharmony_ci struct k3_ring_ops *ops; 1528c2ecf20Sopenharmony_ci u32 size; 1538c2ecf20Sopenharmony_ci enum k3_ring_size elm_size; 1548c2ecf20Sopenharmony_ci enum k3_ring_mode mode; 1558c2ecf20Sopenharmony_ci u32 flags; 1568c2ecf20Sopenharmony_ci#define K3_RING_FLAG_BUSY BIT(1) 1578c2ecf20Sopenharmony_ci#define K3_RING_FLAG_SHARED BIT(2) 1588c2ecf20Sopenharmony_ci struct k3_ring_state state; 1598c2ecf20Sopenharmony_ci u32 ring_id; 1608c2ecf20Sopenharmony_ci struct k3_ringacc *parent; 1618c2ecf20Sopenharmony_ci u32 use_count; 1628c2ecf20Sopenharmony_ci int proxy_id; 1638c2ecf20Sopenharmony_ci}; 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistruct k3_ringacc_ops { 1668c2ecf20Sopenharmony_ci int (*init)(struct platform_device *pdev, struct k3_ringacc *ringacc); 1678c2ecf20Sopenharmony_ci}; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci/** 1708c2ecf20Sopenharmony_ci * struct k3_ringacc - Rings accelerator descriptor 1718c2ecf20Sopenharmony_ci * 1728c2ecf20Sopenharmony_ci * @dev: pointer on RA device 1738c2ecf20Sopenharmony_ci * @proxy_gcfg: RA proxy global config registers 1748c2ecf20Sopenharmony_ci * @proxy_target_base: RA proxy datapath region 1758c2ecf20Sopenharmony_ci * @num_rings: number of ring in RA 1768c2ecf20Sopenharmony_ci * @rings_inuse: bitfield for ring usage tracking 1778c2ecf20Sopenharmony_ci * @rm_gp_range: general purpose rings range from tisci 1788c2ecf20Sopenharmony_ci * @dma_ring_reset_quirk: DMA reset w/a enable 1798c2ecf20Sopenharmony_ci * @num_proxies: number of RA proxies 1808c2ecf20Sopenharmony_ci * @proxy_inuse: bitfield for proxy usage tracking 1818c2ecf20Sopenharmony_ci * @rings: array of rings descriptors (struct @k3_ring) 1828c2ecf20Sopenharmony_ci * @list: list of RAs in the system 1838c2ecf20Sopenharmony_ci * @req_lock: protect rings allocation 1848c2ecf20Sopenharmony_ci * @tisci: pointer ti-sci handle 1858c2ecf20Sopenharmony_ci * @tisci_ring_ops: ti-sci rings ops 1868c2ecf20Sopenharmony_ci * @tisci_dev_id: ti-sci device id 1878c2ecf20Sopenharmony_ci * @ops: SoC specific ringacc operation 1888c2ecf20Sopenharmony_ci */ 1898c2ecf20Sopenharmony_cistruct k3_ringacc { 1908c2ecf20Sopenharmony_ci struct device *dev; 1918c2ecf20Sopenharmony_ci struct k3_ringacc_proxy_gcfg_regs __iomem *proxy_gcfg; 1928c2ecf20Sopenharmony_ci void __iomem *proxy_target_base; 1938c2ecf20Sopenharmony_ci u32 num_rings; /* number of rings in Ringacc module */ 1948c2ecf20Sopenharmony_ci unsigned long *rings_inuse; 1958c2ecf20Sopenharmony_ci struct ti_sci_resource *rm_gp_range; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci bool dma_ring_reset_quirk; 1988c2ecf20Sopenharmony_ci u32 num_proxies; 1998c2ecf20Sopenharmony_ci unsigned long *proxy_inuse; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci struct k3_ring *rings; 2028c2ecf20Sopenharmony_ci struct list_head list; 2038c2ecf20Sopenharmony_ci struct mutex req_lock; /* protect rings allocation */ 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci const struct ti_sci_handle *tisci; 2068c2ecf20Sopenharmony_ci const struct ti_sci_rm_ringacc_ops *tisci_ring_ops; 2078c2ecf20Sopenharmony_ci u32 tisci_dev_id; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci const struct k3_ringacc_ops *ops; 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci/** 2138c2ecf20Sopenharmony_ci * struct k3_ringacc - Rings accelerator SoC data 2148c2ecf20Sopenharmony_ci * 2158c2ecf20Sopenharmony_ci * @dma_ring_reset_quirk: DMA reset w/a enable 2168c2ecf20Sopenharmony_ci */ 2178c2ecf20Sopenharmony_cistruct k3_ringacc_soc_data { 2188c2ecf20Sopenharmony_ci unsigned dma_ring_reset_quirk:1; 2198c2ecf20Sopenharmony_ci}; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_cistatic long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring) 2228c2ecf20Sopenharmony_ci{ 2238c2ecf20Sopenharmony_ci return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES - 2248c2ecf20Sopenharmony_ci (4 << ring->elm_size); 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_cistatic void *k3_ringacc_get_elm_addr(struct k3_ring *ring, u32 idx) 2288c2ecf20Sopenharmony_ci{ 2298c2ecf20Sopenharmony_ci return (ring->ring_mem_virt + idx * (4 << ring->elm_size)); 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_mem(struct k3_ring *ring, void *elem); 2338c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem); 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_cistatic struct k3_ring_ops k3_ring_mode_ring_ops = { 2368c2ecf20Sopenharmony_ci .push_tail = k3_ringacc_ring_push_mem, 2378c2ecf20Sopenharmony_ci .pop_head = k3_ringacc_ring_pop_mem, 2388c2ecf20Sopenharmony_ci}; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_io(struct k3_ring *ring, void *elem); 2418c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem); 2428c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_head_io(struct k3_ring *ring, void *elem); 2438c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem); 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic struct k3_ring_ops k3_ring_mode_msg_ops = { 2468c2ecf20Sopenharmony_ci .push_tail = k3_ringacc_ring_push_io, 2478c2ecf20Sopenharmony_ci .push_head = k3_ringacc_ring_push_head_io, 2488c2ecf20Sopenharmony_ci .pop_tail = k3_ringacc_ring_pop_tail_io, 2498c2ecf20Sopenharmony_ci .pop_head = k3_ringacc_ring_pop_io, 2508c2ecf20Sopenharmony_ci}; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_head_proxy(struct k3_ring *ring, void *elem); 2538c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_tail_proxy(struct k3_ring *ring, void *elem); 2548c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem); 2558c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem); 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_cistatic struct k3_ring_ops k3_ring_mode_proxy_ops = { 2588c2ecf20Sopenharmony_ci .push_tail = k3_ringacc_ring_push_tail_proxy, 2598c2ecf20Sopenharmony_ci .push_head = k3_ringacc_ring_push_head_proxy, 2608c2ecf20Sopenharmony_ci .pop_tail = k3_ringacc_ring_pop_tail_proxy, 2618c2ecf20Sopenharmony_ci .pop_head = k3_ringacc_ring_pop_head_proxy, 2628c2ecf20Sopenharmony_ci}; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_cistatic void k3_ringacc_ring_dump(struct k3_ring *ring) 2658c2ecf20Sopenharmony_ci{ 2668c2ecf20Sopenharmony_ci struct device *dev = ring->parent->dev; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci dev_dbg(dev, "dump ring: %d\n", ring->ring_id); 2698c2ecf20Sopenharmony_ci dev_dbg(dev, "dump mem virt %p, dma %pad\n", ring->ring_mem_virt, 2708c2ecf20Sopenharmony_ci &ring->ring_mem_dma); 2718c2ecf20Sopenharmony_ci dev_dbg(dev, "dump elmsize %d, size %d, mode %d, proxy_id %d\n", 2728c2ecf20Sopenharmony_ci ring->elm_size, ring->size, ring->mode, ring->proxy_id); 2738c2ecf20Sopenharmony_ci dev_dbg(dev, "dump flags %08X\n", ring->flags); 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci dev_dbg(dev, "dump ring_rt_regs: db%08x\n", readl(&ring->rt->db)); 2768c2ecf20Sopenharmony_ci dev_dbg(dev, "dump occ%08x\n", readl(&ring->rt->occ)); 2778c2ecf20Sopenharmony_ci dev_dbg(dev, "dump indx%08x\n", readl(&ring->rt->indx)); 2788c2ecf20Sopenharmony_ci dev_dbg(dev, "dump hwocc%08x\n", readl(&ring->rt->hwocc)); 2798c2ecf20Sopenharmony_ci dev_dbg(dev, "dump hwindx%08x\n", readl(&ring->rt->hwindx)); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci if (ring->ring_mem_virt) 2828c2ecf20Sopenharmony_ci print_hex_dump_debug("dump ring_mem_virt ", DUMP_PREFIX_NONE, 2838c2ecf20Sopenharmony_ci 16, 1, ring->ring_mem_virt, 16 * 8, false); 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistruct k3_ring *k3_ringacc_request_ring(struct k3_ringacc *ringacc, 2878c2ecf20Sopenharmony_ci int id, u32 flags) 2888c2ecf20Sopenharmony_ci{ 2898c2ecf20Sopenharmony_ci int proxy_id = K3_RINGACC_PROXY_NOT_USED; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci mutex_lock(&ringacc->req_lock); 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (id == K3_RINGACC_RING_ID_ANY) { 2948c2ecf20Sopenharmony_ci /* Request for any general purpose ring */ 2958c2ecf20Sopenharmony_ci struct ti_sci_resource_desc *gp_rings = 2968c2ecf20Sopenharmony_ci &ringacc->rm_gp_range->desc[0]; 2978c2ecf20Sopenharmony_ci unsigned long size; 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci size = gp_rings->start + gp_rings->num; 3008c2ecf20Sopenharmony_ci id = find_next_zero_bit(ringacc->rings_inuse, size, 3018c2ecf20Sopenharmony_ci gp_rings->start); 3028c2ecf20Sopenharmony_ci if (id == size) 3038c2ecf20Sopenharmony_ci goto error; 3048c2ecf20Sopenharmony_ci } else if (id < 0) { 3058c2ecf20Sopenharmony_ci goto error; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if (test_bit(id, ringacc->rings_inuse) && 3098c2ecf20Sopenharmony_ci !(ringacc->rings[id].flags & K3_RING_FLAG_SHARED)) 3108c2ecf20Sopenharmony_ci goto error; 3118c2ecf20Sopenharmony_ci else if (ringacc->rings[id].flags & K3_RING_FLAG_SHARED) 3128c2ecf20Sopenharmony_ci goto out; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (flags & K3_RINGACC_RING_USE_PROXY) { 3158c2ecf20Sopenharmony_ci proxy_id = find_next_zero_bit(ringacc->proxy_inuse, 3168c2ecf20Sopenharmony_ci ringacc->num_proxies, 0); 3178c2ecf20Sopenharmony_ci if (proxy_id == ringacc->num_proxies) 3188c2ecf20Sopenharmony_ci goto error; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (proxy_id != K3_RINGACC_PROXY_NOT_USED) { 3228c2ecf20Sopenharmony_ci set_bit(proxy_id, ringacc->proxy_inuse); 3238c2ecf20Sopenharmony_ci ringacc->rings[id].proxy_id = proxy_id; 3248c2ecf20Sopenharmony_ci dev_dbg(ringacc->dev, "Giving ring#%d proxy#%d\n", id, 3258c2ecf20Sopenharmony_ci proxy_id); 3268c2ecf20Sopenharmony_ci } else { 3278c2ecf20Sopenharmony_ci dev_dbg(ringacc->dev, "Giving ring#%d\n", id); 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci set_bit(id, ringacc->rings_inuse); 3318c2ecf20Sopenharmony_ciout: 3328c2ecf20Sopenharmony_ci ringacc->rings[id].use_count++; 3338c2ecf20Sopenharmony_ci mutex_unlock(&ringacc->req_lock); 3348c2ecf20Sopenharmony_ci return &ringacc->rings[id]; 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_cierror: 3378c2ecf20Sopenharmony_ci mutex_unlock(&ringacc->req_lock); 3388c2ecf20Sopenharmony_ci return NULL; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_request_ring); 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ciint k3_ringacc_request_rings_pair(struct k3_ringacc *ringacc, 3438c2ecf20Sopenharmony_ci int fwd_id, int compl_id, 3448c2ecf20Sopenharmony_ci struct k3_ring **fwd_ring, 3458c2ecf20Sopenharmony_ci struct k3_ring **compl_ring) 3468c2ecf20Sopenharmony_ci{ 3478c2ecf20Sopenharmony_ci int ret = 0; 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if (!fwd_ring || !compl_ring) 3508c2ecf20Sopenharmony_ci return -EINVAL; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci *fwd_ring = k3_ringacc_request_ring(ringacc, fwd_id, 0); 3538c2ecf20Sopenharmony_ci if (!(*fwd_ring)) 3548c2ecf20Sopenharmony_ci return -ENODEV; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci *compl_ring = k3_ringacc_request_ring(ringacc, compl_id, 0); 3578c2ecf20Sopenharmony_ci if (!(*compl_ring)) { 3588c2ecf20Sopenharmony_ci k3_ringacc_ring_free(*fwd_ring); 3598c2ecf20Sopenharmony_ci ret = -ENODEV; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci return ret; 3638c2ecf20Sopenharmony_ci} 3648c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_request_rings_pair); 3658c2ecf20Sopenharmony_ci 3668c2ecf20Sopenharmony_cistatic void k3_ringacc_ring_reset_sci(struct k3_ring *ring) 3678c2ecf20Sopenharmony_ci{ 3688c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc = ring->parent; 3698c2ecf20Sopenharmony_ci int ret; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci ret = ringacc->tisci_ring_ops->config( 3728c2ecf20Sopenharmony_ci ringacc->tisci, 3738c2ecf20Sopenharmony_ci TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID, 3748c2ecf20Sopenharmony_ci ringacc->tisci_dev_id, 3758c2ecf20Sopenharmony_ci ring->ring_id, 3768c2ecf20Sopenharmony_ci 0, 3778c2ecf20Sopenharmony_ci 0, 3788c2ecf20Sopenharmony_ci ring->size, 3798c2ecf20Sopenharmony_ci 0, 3808c2ecf20Sopenharmony_ci 0, 3818c2ecf20Sopenharmony_ci 0); 3828c2ecf20Sopenharmony_ci if (ret) 3838c2ecf20Sopenharmony_ci dev_err(ringacc->dev, "TISCI reset ring fail (%d) ring_idx %d\n", 3848c2ecf20Sopenharmony_ci ret, ring->ring_id); 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_civoid k3_ringacc_ring_reset(struct k3_ring *ring) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 3908c2ecf20Sopenharmony_ci return; 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci memset(&ring->state, 0, sizeof(ring->state)); 3938c2ecf20Sopenharmony_ci 3948c2ecf20Sopenharmony_ci k3_ringacc_ring_reset_sci(ring); 3958c2ecf20Sopenharmony_ci} 3968c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_reset); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic void k3_ringacc_ring_reconfig_qmode_sci(struct k3_ring *ring, 3998c2ecf20Sopenharmony_ci enum k3_ring_mode mode) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc = ring->parent; 4028c2ecf20Sopenharmony_ci int ret; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci ret = ringacc->tisci_ring_ops->config( 4058c2ecf20Sopenharmony_ci ringacc->tisci, 4068c2ecf20Sopenharmony_ci TI_SCI_MSG_VALUE_RM_RING_MODE_VALID, 4078c2ecf20Sopenharmony_ci ringacc->tisci_dev_id, 4088c2ecf20Sopenharmony_ci ring->ring_id, 4098c2ecf20Sopenharmony_ci 0, 4108c2ecf20Sopenharmony_ci 0, 4118c2ecf20Sopenharmony_ci 0, 4128c2ecf20Sopenharmony_ci mode, 4138c2ecf20Sopenharmony_ci 0, 4148c2ecf20Sopenharmony_ci 0); 4158c2ecf20Sopenharmony_ci if (ret) 4168c2ecf20Sopenharmony_ci dev_err(ringacc->dev, "TISCI reconf qmode fail (%d) ring_idx %d\n", 4178c2ecf20Sopenharmony_ci ret, ring->ring_id); 4188c2ecf20Sopenharmony_ci} 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_civoid k3_ringacc_ring_reset_dma(struct k3_ring *ring, u32 occ) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 4238c2ecf20Sopenharmony_ci return; 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci if (!ring->parent->dma_ring_reset_quirk) 4268c2ecf20Sopenharmony_ci goto reset; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci if (!occ) 4298c2ecf20Sopenharmony_ci occ = readl(&ring->rt->occ); 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci if (occ) { 4328c2ecf20Sopenharmony_ci u32 db_ring_cnt, db_ring_cnt_cur; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "%s %u occ: %u\n", __func__, 4358c2ecf20Sopenharmony_ci ring->ring_id, occ); 4368c2ecf20Sopenharmony_ci /* TI-SCI ring reset */ 4378c2ecf20Sopenharmony_ci k3_ringacc_ring_reset_sci(ring); 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci /* 4408c2ecf20Sopenharmony_ci * Setup the ring in ring/doorbell mode (if not already in this 4418c2ecf20Sopenharmony_ci * mode) 4428c2ecf20Sopenharmony_ci */ 4438c2ecf20Sopenharmony_ci if (ring->mode != K3_RINGACC_RING_MODE_RING) 4448c2ecf20Sopenharmony_ci k3_ringacc_ring_reconfig_qmode_sci( 4458c2ecf20Sopenharmony_ci ring, K3_RINGACC_RING_MODE_RING); 4468c2ecf20Sopenharmony_ci /* 4478c2ecf20Sopenharmony_ci * Ring the doorbell 2**22 – ringOcc times. 4488c2ecf20Sopenharmony_ci * This will wrap the internal UDMAP ring state occupancy 4498c2ecf20Sopenharmony_ci * counter (which is 21-bits wide) to 0. 4508c2ecf20Sopenharmony_ci */ 4518c2ecf20Sopenharmony_ci db_ring_cnt = (1U << 22) - occ; 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci while (db_ring_cnt != 0) { 4548c2ecf20Sopenharmony_ci /* 4558c2ecf20Sopenharmony_ci * Ring the doorbell with the maximum count each 4568c2ecf20Sopenharmony_ci * iteration if possible to minimize the total 4578c2ecf20Sopenharmony_ci * of writes 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci if (db_ring_cnt > K3_RINGACC_MAX_DB_RING_CNT) 4608c2ecf20Sopenharmony_ci db_ring_cnt_cur = K3_RINGACC_MAX_DB_RING_CNT; 4618c2ecf20Sopenharmony_ci else 4628c2ecf20Sopenharmony_ci db_ring_cnt_cur = db_ring_cnt; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci writel(db_ring_cnt_cur, &ring->rt->db); 4658c2ecf20Sopenharmony_ci db_ring_cnt -= db_ring_cnt_cur; 4668c2ecf20Sopenharmony_ci } 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci /* Restore the original ring mode (if not ring mode) */ 4698c2ecf20Sopenharmony_ci if (ring->mode != K3_RINGACC_RING_MODE_RING) 4708c2ecf20Sopenharmony_ci k3_ringacc_ring_reconfig_qmode_sci(ring, ring->mode); 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_cireset: 4748c2ecf20Sopenharmony_ci /* Reset the ring */ 4758c2ecf20Sopenharmony_ci k3_ringacc_ring_reset(ring); 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_reset_dma); 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_cistatic void k3_ringacc_ring_free_sci(struct k3_ring *ring) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc = ring->parent; 4828c2ecf20Sopenharmony_ci int ret; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci ret = ringacc->tisci_ring_ops->config( 4858c2ecf20Sopenharmony_ci ringacc->tisci, 4868c2ecf20Sopenharmony_ci TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER, 4878c2ecf20Sopenharmony_ci ringacc->tisci_dev_id, 4888c2ecf20Sopenharmony_ci ring->ring_id, 4898c2ecf20Sopenharmony_ci 0, 4908c2ecf20Sopenharmony_ci 0, 4918c2ecf20Sopenharmony_ci 0, 4928c2ecf20Sopenharmony_ci 0, 4938c2ecf20Sopenharmony_ci 0, 4948c2ecf20Sopenharmony_ci 0); 4958c2ecf20Sopenharmony_ci if (ret) 4968c2ecf20Sopenharmony_ci dev_err(ringacc->dev, "TISCI ring free fail (%d) ring_idx %d\n", 4978c2ecf20Sopenharmony_ci ret, ring->ring_id); 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciint k3_ringacc_ring_free(struct k3_ring *ring) 5018c2ecf20Sopenharmony_ci{ 5028c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (!ring) 5058c2ecf20Sopenharmony_ci return -EINVAL; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci ringacc = ring->parent; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "flags: 0x%08x\n", ring->flags); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci if (!test_bit(ring->ring_id, ringacc->rings_inuse)) 5128c2ecf20Sopenharmony_ci return -EINVAL; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci mutex_lock(&ringacc->req_lock); 5158c2ecf20Sopenharmony_ci 5168c2ecf20Sopenharmony_ci if (--ring->use_count) 5178c2ecf20Sopenharmony_ci goto out; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (!(ring->flags & K3_RING_FLAG_BUSY)) 5208c2ecf20Sopenharmony_ci goto no_init; 5218c2ecf20Sopenharmony_ci 5228c2ecf20Sopenharmony_ci k3_ringacc_ring_free_sci(ring); 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci dma_free_coherent(ringacc->dev, 5258c2ecf20Sopenharmony_ci ring->size * (4 << ring->elm_size), 5268c2ecf20Sopenharmony_ci ring->ring_mem_virt, ring->ring_mem_dma); 5278c2ecf20Sopenharmony_ci ring->flags = 0; 5288c2ecf20Sopenharmony_ci ring->ops = NULL; 5298c2ecf20Sopenharmony_ci if (ring->proxy_id != K3_RINGACC_PROXY_NOT_USED) { 5308c2ecf20Sopenharmony_ci clear_bit(ring->proxy_id, ringacc->proxy_inuse); 5318c2ecf20Sopenharmony_ci ring->proxy = NULL; 5328c2ecf20Sopenharmony_ci ring->proxy_id = K3_RINGACC_PROXY_NOT_USED; 5338c2ecf20Sopenharmony_ci } 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_cino_init: 5368c2ecf20Sopenharmony_ci clear_bit(ring->ring_id, ringacc->rings_inuse); 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ciout: 5398c2ecf20Sopenharmony_ci mutex_unlock(&ringacc->req_lock); 5408c2ecf20Sopenharmony_ci return 0; 5418c2ecf20Sopenharmony_ci} 5428c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_free); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ciu32 k3_ringacc_get_ring_id(struct k3_ring *ring) 5458c2ecf20Sopenharmony_ci{ 5468c2ecf20Sopenharmony_ci if (!ring) 5478c2ecf20Sopenharmony_ci return -EINVAL; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci return ring->ring_id; 5508c2ecf20Sopenharmony_ci} 5518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_get_ring_id); 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ciu32 k3_ringacc_get_tisci_dev_id(struct k3_ring *ring) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci if (!ring) 5568c2ecf20Sopenharmony_ci return -EINVAL; 5578c2ecf20Sopenharmony_ci 5588c2ecf20Sopenharmony_ci return ring->parent->tisci_dev_id; 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_get_tisci_dev_id); 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ciint k3_ringacc_get_ring_irq_num(struct k3_ring *ring) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci int irq_num; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci if (!ring) 5678c2ecf20Sopenharmony_ci return -EINVAL; 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci irq_num = ti_sci_inta_msi_get_virq(ring->parent->dev, ring->ring_id); 5708c2ecf20Sopenharmony_ci if (irq_num <= 0) 5718c2ecf20Sopenharmony_ci irq_num = -EINVAL; 5728c2ecf20Sopenharmony_ci return irq_num; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_get_ring_irq_num); 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_cfg_sci(struct k3_ring *ring) 5778c2ecf20Sopenharmony_ci{ 5788c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc = ring->parent; 5798c2ecf20Sopenharmony_ci u32 ring_idx; 5808c2ecf20Sopenharmony_ci int ret; 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci if (!ringacc->tisci) 5838c2ecf20Sopenharmony_ci return -EINVAL; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci ring_idx = ring->ring_id; 5868c2ecf20Sopenharmony_ci ret = ringacc->tisci_ring_ops->config( 5878c2ecf20Sopenharmony_ci ringacc->tisci, 5888c2ecf20Sopenharmony_ci TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER, 5898c2ecf20Sopenharmony_ci ringacc->tisci_dev_id, 5908c2ecf20Sopenharmony_ci ring_idx, 5918c2ecf20Sopenharmony_ci lower_32_bits(ring->ring_mem_dma), 5928c2ecf20Sopenharmony_ci upper_32_bits(ring->ring_mem_dma), 5938c2ecf20Sopenharmony_ci ring->size, 5948c2ecf20Sopenharmony_ci ring->mode, 5958c2ecf20Sopenharmony_ci ring->elm_size, 5968c2ecf20Sopenharmony_ci 0); 5978c2ecf20Sopenharmony_ci if (ret) 5988c2ecf20Sopenharmony_ci dev_err(ringacc->dev, "TISCI config ring fail (%d) ring_idx %d\n", 5998c2ecf20Sopenharmony_ci ret, ring_idx); 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci return ret; 6028c2ecf20Sopenharmony_ci} 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ciint k3_ringacc_ring_cfg(struct k3_ring *ring, struct k3_ring_cfg *cfg) 6058c2ecf20Sopenharmony_ci{ 6068c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc; 6078c2ecf20Sopenharmony_ci int ret = 0; 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci if (!ring || !cfg) 6108c2ecf20Sopenharmony_ci return -EINVAL; 6118c2ecf20Sopenharmony_ci ringacc = ring->parent; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci if (cfg->elm_size > K3_RINGACC_RING_ELSIZE_256 || 6148c2ecf20Sopenharmony_ci cfg->mode >= K3_RINGACC_RING_MODE_INVALID || 6158c2ecf20Sopenharmony_ci cfg->size & ~K3_RINGACC_CFG_RING_SIZE_ELCNT_MASK || 6168c2ecf20Sopenharmony_ci !test_bit(ring->ring_id, ringacc->rings_inuse)) 6178c2ecf20Sopenharmony_ci return -EINVAL; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci if (cfg->mode == K3_RINGACC_RING_MODE_MESSAGE && 6208c2ecf20Sopenharmony_ci ring->proxy_id == K3_RINGACC_PROXY_NOT_USED && 6218c2ecf20Sopenharmony_ci cfg->elm_size > K3_RINGACC_RING_ELSIZE_8) { 6228c2ecf20Sopenharmony_ci dev_err(ringacc->dev, 6238c2ecf20Sopenharmony_ci "Message mode must use proxy for %u element size\n", 6248c2ecf20Sopenharmony_ci 4 << ring->elm_size); 6258c2ecf20Sopenharmony_ci return -EINVAL; 6268c2ecf20Sopenharmony_ci } 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci /* 6298c2ecf20Sopenharmony_ci * In case of shared ring only the first user (master user) can 6308c2ecf20Sopenharmony_ci * configure the ring. The sequence should be by the client: 6318c2ecf20Sopenharmony_ci * ring = k3_ringacc_request_ring(ringacc, ring_id, 0); # master user 6328c2ecf20Sopenharmony_ci * k3_ringacc_ring_cfg(ring, cfg); # master configuration 6338c2ecf20Sopenharmony_ci * k3_ringacc_request_ring(ringacc, ring_id, K3_RING_FLAG_SHARED); 6348c2ecf20Sopenharmony_ci * k3_ringacc_request_ring(ringacc, ring_id, K3_RING_FLAG_SHARED); 6358c2ecf20Sopenharmony_ci */ 6368c2ecf20Sopenharmony_ci if (ring->use_count != 1) 6378c2ecf20Sopenharmony_ci return 0; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci ring->size = cfg->size; 6408c2ecf20Sopenharmony_ci ring->elm_size = cfg->elm_size; 6418c2ecf20Sopenharmony_ci ring->mode = cfg->mode; 6428c2ecf20Sopenharmony_ci memset(&ring->state, 0, sizeof(ring->state)); 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_ci if (ring->proxy_id != K3_RINGACC_PROXY_NOT_USED) 6458c2ecf20Sopenharmony_ci ring->proxy = ringacc->proxy_target_base + 6468c2ecf20Sopenharmony_ci ring->proxy_id * K3_RINGACC_PROXY_TARGET_STEP; 6478c2ecf20Sopenharmony_ci 6488c2ecf20Sopenharmony_ci switch (ring->mode) { 6498c2ecf20Sopenharmony_ci case K3_RINGACC_RING_MODE_RING: 6508c2ecf20Sopenharmony_ci ring->ops = &k3_ring_mode_ring_ops; 6518c2ecf20Sopenharmony_ci break; 6528c2ecf20Sopenharmony_ci case K3_RINGACC_RING_MODE_MESSAGE: 6538c2ecf20Sopenharmony_ci if (ring->proxy) 6548c2ecf20Sopenharmony_ci ring->ops = &k3_ring_mode_proxy_ops; 6558c2ecf20Sopenharmony_ci else 6568c2ecf20Sopenharmony_ci ring->ops = &k3_ring_mode_msg_ops; 6578c2ecf20Sopenharmony_ci break; 6588c2ecf20Sopenharmony_ci default: 6598c2ecf20Sopenharmony_ci ring->ops = NULL; 6608c2ecf20Sopenharmony_ci ret = -EINVAL; 6618c2ecf20Sopenharmony_ci goto err_free_proxy; 6628c2ecf20Sopenharmony_ci } 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_ci ring->ring_mem_virt = dma_alloc_coherent(ringacc->dev, 6658c2ecf20Sopenharmony_ci ring->size * (4 << ring->elm_size), 6668c2ecf20Sopenharmony_ci &ring->ring_mem_dma, GFP_KERNEL); 6678c2ecf20Sopenharmony_ci if (!ring->ring_mem_virt) { 6688c2ecf20Sopenharmony_ci dev_err(ringacc->dev, "Failed to alloc ring mem\n"); 6698c2ecf20Sopenharmony_ci ret = -ENOMEM; 6708c2ecf20Sopenharmony_ci goto err_free_ops; 6718c2ecf20Sopenharmony_ci } 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ci ret = k3_ringacc_ring_cfg_sci(ring); 6748c2ecf20Sopenharmony_ci 6758c2ecf20Sopenharmony_ci if (ret) 6768c2ecf20Sopenharmony_ci goto err_free_mem; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci ring->flags |= K3_RING_FLAG_BUSY; 6798c2ecf20Sopenharmony_ci ring->flags |= (cfg->flags & K3_RINGACC_RING_SHARED) ? 6808c2ecf20Sopenharmony_ci K3_RING_FLAG_SHARED : 0; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci k3_ringacc_ring_dump(ring); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci return 0; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_cierr_free_mem: 6878c2ecf20Sopenharmony_ci dma_free_coherent(ringacc->dev, 6888c2ecf20Sopenharmony_ci ring->size * (4 << ring->elm_size), 6898c2ecf20Sopenharmony_ci ring->ring_mem_virt, 6908c2ecf20Sopenharmony_ci ring->ring_mem_dma); 6918c2ecf20Sopenharmony_cierr_free_ops: 6928c2ecf20Sopenharmony_ci ring->ops = NULL; 6938c2ecf20Sopenharmony_cierr_free_proxy: 6948c2ecf20Sopenharmony_ci ring->proxy = NULL; 6958c2ecf20Sopenharmony_ci return ret; 6968c2ecf20Sopenharmony_ci} 6978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_cfg); 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ciu32 k3_ringacc_ring_get_size(struct k3_ring *ring) 7008c2ecf20Sopenharmony_ci{ 7018c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 7028c2ecf20Sopenharmony_ci return -EINVAL; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci return ring->size; 7058c2ecf20Sopenharmony_ci} 7068c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_get_size); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ciu32 k3_ringacc_ring_get_free(struct k3_ring *ring) 7098c2ecf20Sopenharmony_ci{ 7108c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 7118c2ecf20Sopenharmony_ci return -EINVAL; 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci if (!ring->state.free) 7148c2ecf20Sopenharmony_ci ring->state.free = ring->size - readl(&ring->rt->occ); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci return ring->state.free; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_get_free); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ciu32 k3_ringacc_ring_get_occ(struct k3_ring *ring) 7218c2ecf20Sopenharmony_ci{ 7228c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 7238c2ecf20Sopenharmony_ci return -EINVAL; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci return readl(&ring->rt->occ); 7268c2ecf20Sopenharmony_ci} 7278c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_get_occ); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ciu32 k3_ringacc_ring_is_full(struct k3_ring *ring) 7308c2ecf20Sopenharmony_ci{ 7318c2ecf20Sopenharmony_ci return !k3_ringacc_ring_get_free(ring); 7328c2ecf20Sopenharmony_ci} 7338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_is_full); 7348c2ecf20Sopenharmony_ci 7358c2ecf20Sopenharmony_cienum k3_ringacc_access_mode { 7368c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_HEAD, 7378c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_HEAD, 7388c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_TAIL, 7398c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_TAIL, 7408c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PEEK_HEAD, 7418c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PEEK_TAIL, 7428c2ecf20Sopenharmony_ci}; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ci#define K3_RINGACC_PROXY_MODE(x) (((x) & 0x3) << 16) 7458c2ecf20Sopenharmony_ci#define K3_RINGACC_PROXY_ELSIZE(x) (((x) & 0x7) << 24) 7468c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_cfg_proxy(struct k3_ring *ring, 7478c2ecf20Sopenharmony_ci enum k3_ringacc_proxy_access_mode mode) 7488c2ecf20Sopenharmony_ci{ 7498c2ecf20Sopenharmony_ci u32 val; 7508c2ecf20Sopenharmony_ci 7518c2ecf20Sopenharmony_ci val = ring->ring_id; 7528c2ecf20Sopenharmony_ci val |= K3_RINGACC_PROXY_MODE(mode); 7538c2ecf20Sopenharmony_ci val |= K3_RINGACC_PROXY_ELSIZE(ring->elm_size); 7548c2ecf20Sopenharmony_ci writel(val, &ring->proxy->control); 7558c2ecf20Sopenharmony_ci return 0; 7568c2ecf20Sopenharmony_ci} 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_access_proxy(struct k3_ring *ring, void *elem, 7598c2ecf20Sopenharmony_ci enum k3_ringacc_access_mode access_mode) 7608c2ecf20Sopenharmony_ci{ 7618c2ecf20Sopenharmony_ci void __iomem *ptr; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci ptr = (void __iomem *)&ring->proxy->data; 7648c2ecf20Sopenharmony_ci 7658c2ecf20Sopenharmony_ci switch (access_mode) { 7668c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: 7678c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_HEAD: 7688c2ecf20Sopenharmony_ci k3_ringacc_ring_cfg_proxy(ring, PROXY_ACCESS_MODE_HEAD); 7698c2ecf20Sopenharmony_ci break; 7708c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: 7718c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_TAIL: 7728c2ecf20Sopenharmony_ci k3_ringacc_ring_cfg_proxy(ring, PROXY_ACCESS_MODE_TAIL); 7738c2ecf20Sopenharmony_ci break; 7748c2ecf20Sopenharmony_ci default: 7758c2ecf20Sopenharmony_ci return -EINVAL; 7768c2ecf20Sopenharmony_ci } 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci ptr += k3_ringacc_ring_get_fifo_pos(ring); 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ci switch (access_mode) { 7818c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_HEAD: 7828c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_TAIL: 7838c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, 7848c2ecf20Sopenharmony_ci "proxy:memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, 7858c2ecf20Sopenharmony_ci access_mode); 7868c2ecf20Sopenharmony_ci memcpy_fromio(elem, ptr, (4 << ring->elm_size)); 7878c2ecf20Sopenharmony_ci ring->state.occ--; 7888c2ecf20Sopenharmony_ci break; 7898c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: 7908c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: 7918c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, 7928c2ecf20Sopenharmony_ci "proxy:memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, 7938c2ecf20Sopenharmony_ci access_mode); 7948c2ecf20Sopenharmony_ci memcpy_toio(ptr, elem, (4 << ring->elm_size)); 7958c2ecf20Sopenharmony_ci ring->state.free--; 7968c2ecf20Sopenharmony_ci break; 7978c2ecf20Sopenharmony_ci default: 7988c2ecf20Sopenharmony_ci return -EINVAL; 7998c2ecf20Sopenharmony_ci } 8008c2ecf20Sopenharmony_ci 8018c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "proxy: free%d occ%d\n", ring->state.free, 8028c2ecf20Sopenharmony_ci ring->state.occ); 8038c2ecf20Sopenharmony_ci return 0; 8048c2ecf20Sopenharmony_ci} 8058c2ecf20Sopenharmony_ci 8068c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_head_proxy(struct k3_ring *ring, void *elem) 8078c2ecf20Sopenharmony_ci{ 8088c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_proxy(ring, elem, 8098c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_HEAD); 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_tail_proxy(struct k3_ring *ring, void *elem) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_proxy(ring, elem, 8158c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_TAIL); 8168c2ecf20Sopenharmony_ci} 8178c2ecf20Sopenharmony_ci 8188c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_head_proxy(struct k3_ring *ring, void *elem) 8198c2ecf20Sopenharmony_ci{ 8208c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_proxy(ring, elem, 8218c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_HEAD); 8228c2ecf20Sopenharmony_ci} 8238c2ecf20Sopenharmony_ci 8248c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_tail_proxy(struct k3_ring *ring, void *elem) 8258c2ecf20Sopenharmony_ci{ 8268c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_proxy(ring, elem, 8278c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_HEAD); 8288c2ecf20Sopenharmony_ci} 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_access_io(struct k3_ring *ring, void *elem, 8318c2ecf20Sopenharmony_ci enum k3_ringacc_access_mode access_mode) 8328c2ecf20Sopenharmony_ci{ 8338c2ecf20Sopenharmony_ci void __iomem *ptr; 8348c2ecf20Sopenharmony_ci 8358c2ecf20Sopenharmony_ci switch (access_mode) { 8368c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: 8378c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_HEAD: 8388c2ecf20Sopenharmony_ci ptr = (void __iomem *)&ring->fifos->head_data; 8398c2ecf20Sopenharmony_ci break; 8408c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: 8418c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_TAIL: 8428c2ecf20Sopenharmony_ci ptr = (void __iomem *)&ring->fifos->tail_data; 8438c2ecf20Sopenharmony_ci break; 8448c2ecf20Sopenharmony_ci default: 8458c2ecf20Sopenharmony_ci return -EINVAL; 8468c2ecf20Sopenharmony_ci } 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci ptr += k3_ringacc_ring_get_fifo_pos(ring); 8498c2ecf20Sopenharmony_ci 8508c2ecf20Sopenharmony_ci switch (access_mode) { 8518c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_HEAD: 8528c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_POP_TAIL: 8538c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, 8548c2ecf20Sopenharmony_ci "memcpy_fromio(x): --> ptr(%p), mode:%d\n", ptr, 8558c2ecf20Sopenharmony_ci access_mode); 8568c2ecf20Sopenharmony_ci memcpy_fromio(elem, ptr, (4 << ring->elm_size)); 8578c2ecf20Sopenharmony_ci ring->state.occ--; 8588c2ecf20Sopenharmony_ci break; 8598c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_TAIL: 8608c2ecf20Sopenharmony_ci case K3_RINGACC_ACCESS_MODE_PUSH_HEAD: 8618c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, 8628c2ecf20Sopenharmony_ci "memcpy_toio(x): --> ptr(%p), mode:%d\n", ptr, 8638c2ecf20Sopenharmony_ci access_mode); 8648c2ecf20Sopenharmony_ci memcpy_toio(ptr, elem, (4 << ring->elm_size)); 8658c2ecf20Sopenharmony_ci ring->state.free--; 8668c2ecf20Sopenharmony_ci break; 8678c2ecf20Sopenharmony_ci default: 8688c2ecf20Sopenharmony_ci return -EINVAL; 8698c2ecf20Sopenharmony_ci } 8708c2ecf20Sopenharmony_ci 8718c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "free%d index%d occ%d index%d\n", 8728c2ecf20Sopenharmony_ci ring->state.free, ring->state.windex, ring->state.occ, 8738c2ecf20Sopenharmony_ci ring->state.rindex); 8748c2ecf20Sopenharmony_ci return 0; 8758c2ecf20Sopenharmony_ci} 8768c2ecf20Sopenharmony_ci 8778c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_head_io(struct k3_ring *ring, void *elem) 8788c2ecf20Sopenharmony_ci{ 8798c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_io(ring, elem, 8808c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_HEAD); 8818c2ecf20Sopenharmony_ci} 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_io(struct k3_ring *ring, void *elem) 8848c2ecf20Sopenharmony_ci{ 8858c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_io(ring, elem, 8868c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_PUSH_TAIL); 8878c2ecf20Sopenharmony_ci} 8888c2ecf20Sopenharmony_ci 8898c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_io(struct k3_ring *ring, void *elem) 8908c2ecf20Sopenharmony_ci{ 8918c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_io(ring, elem, 8928c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_HEAD); 8938c2ecf20Sopenharmony_ci} 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_tail_io(struct k3_ring *ring, void *elem) 8968c2ecf20Sopenharmony_ci{ 8978c2ecf20Sopenharmony_ci return k3_ringacc_ring_access_io(ring, elem, 8988c2ecf20Sopenharmony_ci K3_RINGACC_ACCESS_MODE_POP_HEAD); 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_push_mem(struct k3_ring *ring, void *elem) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci void *elem_ptr; 9048c2ecf20Sopenharmony_ci 9058c2ecf20Sopenharmony_ci elem_ptr = k3_ringacc_get_elm_addr(ring, ring->state.windex); 9068c2ecf20Sopenharmony_ci 9078c2ecf20Sopenharmony_ci memcpy(elem_ptr, elem, (4 << ring->elm_size)); 9088c2ecf20Sopenharmony_ci 9098c2ecf20Sopenharmony_ci ring->state.windex = (ring->state.windex + 1) % ring->size; 9108c2ecf20Sopenharmony_ci ring->state.free--; 9118c2ecf20Sopenharmony_ci writel(1, &ring->rt->db); 9128c2ecf20Sopenharmony_ci 9138c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_push_mem: free%d index%d\n", 9148c2ecf20Sopenharmony_ci ring->state.free, ring->state.windex); 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci return 0; 9178c2ecf20Sopenharmony_ci} 9188c2ecf20Sopenharmony_ci 9198c2ecf20Sopenharmony_cistatic int k3_ringacc_ring_pop_mem(struct k3_ring *ring, void *elem) 9208c2ecf20Sopenharmony_ci{ 9218c2ecf20Sopenharmony_ci void *elem_ptr; 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci elem_ptr = k3_ringacc_get_elm_addr(ring, ring->state.rindex); 9248c2ecf20Sopenharmony_ci 9258c2ecf20Sopenharmony_ci memcpy(elem, elem_ptr, (4 << ring->elm_size)); 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci ring->state.rindex = (ring->state.rindex + 1) % ring->size; 9288c2ecf20Sopenharmony_ci ring->state.occ--; 9298c2ecf20Sopenharmony_ci writel(-1, &ring->rt->db); 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_pop_mem: occ%d index%d pos_ptr%p\n", 9328c2ecf20Sopenharmony_ci ring->state.occ, ring->state.rindex, elem_ptr); 9338c2ecf20Sopenharmony_ci return 0; 9348c2ecf20Sopenharmony_ci} 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ciint k3_ringacc_ring_push(struct k3_ring *ring, void *elem) 9378c2ecf20Sopenharmony_ci{ 9388c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 9398c2ecf20Sopenharmony_ci 9408c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 9418c2ecf20Sopenharmony_ci return -EINVAL; 9428c2ecf20Sopenharmony_ci 9438c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_push: free%d index%d\n", 9448c2ecf20Sopenharmony_ci ring->state.free, ring->state.windex); 9458c2ecf20Sopenharmony_ci 9468c2ecf20Sopenharmony_ci if (k3_ringacc_ring_is_full(ring)) 9478c2ecf20Sopenharmony_ci return -ENOMEM; 9488c2ecf20Sopenharmony_ci 9498c2ecf20Sopenharmony_ci if (ring->ops && ring->ops->push_tail) 9508c2ecf20Sopenharmony_ci ret = ring->ops->push_tail(ring, elem); 9518c2ecf20Sopenharmony_ci 9528c2ecf20Sopenharmony_ci return ret; 9538c2ecf20Sopenharmony_ci} 9548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_push); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ciint k3_ringacc_ring_push_head(struct k3_ring *ring, void *elem) 9578c2ecf20Sopenharmony_ci{ 9588c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 9598c2ecf20Sopenharmony_ci 9608c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 9618c2ecf20Sopenharmony_ci return -EINVAL; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_push_head: free%d index%d\n", 9648c2ecf20Sopenharmony_ci ring->state.free, ring->state.windex); 9658c2ecf20Sopenharmony_ci 9668c2ecf20Sopenharmony_ci if (k3_ringacc_ring_is_full(ring)) 9678c2ecf20Sopenharmony_ci return -ENOMEM; 9688c2ecf20Sopenharmony_ci 9698c2ecf20Sopenharmony_ci if (ring->ops && ring->ops->push_head) 9708c2ecf20Sopenharmony_ci ret = ring->ops->push_head(ring, elem); 9718c2ecf20Sopenharmony_ci 9728c2ecf20Sopenharmony_ci return ret; 9738c2ecf20Sopenharmony_ci} 9748c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_push_head); 9758c2ecf20Sopenharmony_ci 9768c2ecf20Sopenharmony_ciint k3_ringacc_ring_pop(struct k3_ring *ring, void *elem) 9778c2ecf20Sopenharmony_ci{ 9788c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 9798c2ecf20Sopenharmony_ci 9808c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 9818c2ecf20Sopenharmony_ci return -EINVAL; 9828c2ecf20Sopenharmony_ci 9838c2ecf20Sopenharmony_ci if (!ring->state.occ) 9848c2ecf20Sopenharmony_ci ring->state.occ = k3_ringacc_ring_get_occ(ring); 9858c2ecf20Sopenharmony_ci 9868c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_pop: occ%d index%d\n", ring->state.occ, 9878c2ecf20Sopenharmony_ci ring->state.rindex); 9888c2ecf20Sopenharmony_ci 9898c2ecf20Sopenharmony_ci if (!ring->state.occ) 9908c2ecf20Sopenharmony_ci return -ENODATA; 9918c2ecf20Sopenharmony_ci 9928c2ecf20Sopenharmony_ci if (ring->ops && ring->ops->pop_head) 9938c2ecf20Sopenharmony_ci ret = ring->ops->pop_head(ring, elem); 9948c2ecf20Sopenharmony_ci 9958c2ecf20Sopenharmony_ci return ret; 9968c2ecf20Sopenharmony_ci} 9978c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_pop); 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ciint k3_ringacc_ring_pop_tail(struct k3_ring *ring, void *elem) 10008c2ecf20Sopenharmony_ci{ 10018c2ecf20Sopenharmony_ci int ret = -EOPNOTSUPP; 10028c2ecf20Sopenharmony_ci 10038c2ecf20Sopenharmony_ci if (!ring || !(ring->flags & K3_RING_FLAG_BUSY)) 10048c2ecf20Sopenharmony_ci return -EINVAL; 10058c2ecf20Sopenharmony_ci 10068c2ecf20Sopenharmony_ci if (!ring->state.occ) 10078c2ecf20Sopenharmony_ci ring->state.occ = k3_ringacc_ring_get_occ(ring); 10088c2ecf20Sopenharmony_ci 10098c2ecf20Sopenharmony_ci dev_dbg(ring->parent->dev, "ring_pop_tail: occ%d index%d\n", 10108c2ecf20Sopenharmony_ci ring->state.occ, ring->state.rindex); 10118c2ecf20Sopenharmony_ci 10128c2ecf20Sopenharmony_ci if (!ring->state.occ) 10138c2ecf20Sopenharmony_ci return -ENODATA; 10148c2ecf20Sopenharmony_ci 10158c2ecf20Sopenharmony_ci if (ring->ops && ring->ops->pop_tail) 10168c2ecf20Sopenharmony_ci ret = ring->ops->pop_tail(ring, elem); 10178c2ecf20Sopenharmony_ci 10188c2ecf20Sopenharmony_ci return ret; 10198c2ecf20Sopenharmony_ci} 10208c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(k3_ringacc_ring_pop_tail); 10218c2ecf20Sopenharmony_ci 10228c2ecf20Sopenharmony_cistruct k3_ringacc *of_k3_ringacc_get_by_phandle(struct device_node *np, 10238c2ecf20Sopenharmony_ci const char *property) 10248c2ecf20Sopenharmony_ci{ 10258c2ecf20Sopenharmony_ci struct device_node *ringacc_np; 10268c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc = ERR_PTR(-EPROBE_DEFER); 10278c2ecf20Sopenharmony_ci struct k3_ringacc *entry; 10288c2ecf20Sopenharmony_ci 10298c2ecf20Sopenharmony_ci ringacc_np = of_parse_phandle(np, property, 0); 10308c2ecf20Sopenharmony_ci if (!ringacc_np) 10318c2ecf20Sopenharmony_ci return ERR_PTR(-ENODEV); 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_ci mutex_lock(&k3_ringacc_list_lock); 10348c2ecf20Sopenharmony_ci list_for_each_entry(entry, &k3_ringacc_list, list) 10358c2ecf20Sopenharmony_ci if (entry->dev->of_node == ringacc_np) { 10368c2ecf20Sopenharmony_ci ringacc = entry; 10378c2ecf20Sopenharmony_ci break; 10388c2ecf20Sopenharmony_ci } 10398c2ecf20Sopenharmony_ci mutex_unlock(&k3_ringacc_list_lock); 10408c2ecf20Sopenharmony_ci of_node_put(ringacc_np); 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci return ringacc; 10438c2ecf20Sopenharmony_ci} 10448c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(of_k3_ringacc_get_by_phandle); 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_cistatic int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) 10478c2ecf20Sopenharmony_ci{ 10488c2ecf20Sopenharmony_ci struct device_node *node = ringacc->dev->of_node; 10498c2ecf20Sopenharmony_ci struct device *dev = ringacc->dev; 10508c2ecf20Sopenharmony_ci struct platform_device *pdev = to_platform_device(dev); 10518c2ecf20Sopenharmony_ci int ret; 10528c2ecf20Sopenharmony_ci 10538c2ecf20Sopenharmony_ci if (!node) { 10548c2ecf20Sopenharmony_ci dev_err(dev, "device tree info unavailable\n"); 10558c2ecf20Sopenharmony_ci return -ENODEV; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci 10588c2ecf20Sopenharmony_ci ret = of_property_read_u32(node, "ti,num-rings", &ringacc->num_rings); 10598c2ecf20Sopenharmony_ci if (ret) { 10608c2ecf20Sopenharmony_ci dev_err(dev, "ti,num-rings read failure %d\n", ret); 10618c2ecf20Sopenharmony_ci return ret; 10628c2ecf20Sopenharmony_ci } 10638c2ecf20Sopenharmony_ci 10648c2ecf20Sopenharmony_ci ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci"); 10658c2ecf20Sopenharmony_ci if (IS_ERR(ringacc->tisci)) { 10668c2ecf20Sopenharmony_ci ret = PTR_ERR(ringacc->tisci); 10678c2ecf20Sopenharmony_ci if (ret != -EPROBE_DEFER) 10688c2ecf20Sopenharmony_ci dev_err(dev, "ti,sci read fail %d\n", ret); 10698c2ecf20Sopenharmony_ci ringacc->tisci = NULL; 10708c2ecf20Sopenharmony_ci return ret; 10718c2ecf20Sopenharmony_ci } 10728c2ecf20Sopenharmony_ci 10738c2ecf20Sopenharmony_ci ret = of_property_read_u32(node, "ti,sci-dev-id", 10748c2ecf20Sopenharmony_ci &ringacc->tisci_dev_id); 10758c2ecf20Sopenharmony_ci if (ret) { 10768c2ecf20Sopenharmony_ci dev_err(dev, "ti,sci-dev-id read fail %d\n", ret); 10778c2ecf20Sopenharmony_ci return ret; 10788c2ecf20Sopenharmony_ci } 10798c2ecf20Sopenharmony_ci 10808c2ecf20Sopenharmony_ci pdev->id = ringacc->tisci_dev_id; 10818c2ecf20Sopenharmony_ci 10828c2ecf20Sopenharmony_ci ringacc->rm_gp_range = devm_ti_sci_get_of_resource(ringacc->tisci, dev, 10838c2ecf20Sopenharmony_ci ringacc->tisci_dev_id, 10848c2ecf20Sopenharmony_ci "ti,sci-rm-range-gp-rings"); 10858c2ecf20Sopenharmony_ci if (IS_ERR(ringacc->rm_gp_range)) { 10868c2ecf20Sopenharmony_ci dev_err(dev, "Failed to allocate MSI interrupts\n"); 10878c2ecf20Sopenharmony_ci return PTR_ERR(ringacc->rm_gp_range); 10888c2ecf20Sopenharmony_ci } 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci return ti_sci_inta_msi_domain_alloc_irqs(ringacc->dev, 10918c2ecf20Sopenharmony_ci ringacc->rm_gp_range); 10928c2ecf20Sopenharmony_ci} 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_cistatic const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = { 10958c2ecf20Sopenharmony_ci .dma_ring_reset_quirk = 1, 10968c2ecf20Sopenharmony_ci}; 10978c2ecf20Sopenharmony_ci 10988c2ecf20Sopenharmony_cistatic const struct soc_device_attribute k3_ringacc_socinfo[] = { 10998c2ecf20Sopenharmony_ci { .family = "AM65X", 11008c2ecf20Sopenharmony_ci .revision = "SR1.0", 11018c2ecf20Sopenharmony_ci .data = &k3_ringacc_soc_data_sr1 11028c2ecf20Sopenharmony_ci }, 11038c2ecf20Sopenharmony_ci {/* sentinel */} 11048c2ecf20Sopenharmony_ci}; 11058c2ecf20Sopenharmony_ci 11068c2ecf20Sopenharmony_cistatic int k3_ringacc_init(struct platform_device *pdev, 11078c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc) 11088c2ecf20Sopenharmony_ci{ 11098c2ecf20Sopenharmony_ci const struct soc_device_attribute *soc; 11108c2ecf20Sopenharmony_ci void __iomem *base_fifo, *base_rt; 11118c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 11128c2ecf20Sopenharmony_ci struct resource *res; 11138c2ecf20Sopenharmony_ci int ret, i; 11148c2ecf20Sopenharmony_ci 11158c2ecf20Sopenharmony_ci dev->msi_domain = of_msi_get_domain(dev, dev->of_node, 11168c2ecf20Sopenharmony_ci DOMAIN_BUS_TI_SCI_INTA_MSI); 11178c2ecf20Sopenharmony_ci if (!dev->msi_domain) { 11188c2ecf20Sopenharmony_ci dev_err(dev, "Failed to get MSI domain\n"); 11198c2ecf20Sopenharmony_ci return -EPROBE_DEFER; 11208c2ecf20Sopenharmony_ci } 11218c2ecf20Sopenharmony_ci 11228c2ecf20Sopenharmony_ci ret = k3_ringacc_probe_dt(ringacc); 11238c2ecf20Sopenharmony_ci if (ret) 11248c2ecf20Sopenharmony_ci return ret; 11258c2ecf20Sopenharmony_ci 11268c2ecf20Sopenharmony_ci soc = soc_device_match(k3_ringacc_socinfo); 11278c2ecf20Sopenharmony_ci if (soc && soc->data) { 11288c2ecf20Sopenharmony_ci const struct k3_ringacc_soc_data *soc_data = soc->data; 11298c2ecf20Sopenharmony_ci 11308c2ecf20Sopenharmony_ci ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci 11338c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt"); 11348c2ecf20Sopenharmony_ci base_rt = devm_ioremap_resource(dev, res); 11358c2ecf20Sopenharmony_ci if (IS_ERR(base_rt)) 11368c2ecf20Sopenharmony_ci return PTR_ERR(base_rt); 11378c2ecf20Sopenharmony_ci 11388c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "fifos"); 11398c2ecf20Sopenharmony_ci base_fifo = devm_ioremap_resource(dev, res); 11408c2ecf20Sopenharmony_ci if (IS_ERR(base_fifo)) 11418c2ecf20Sopenharmony_ci return PTR_ERR(base_fifo); 11428c2ecf20Sopenharmony_ci 11438c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "proxy_gcfg"); 11448c2ecf20Sopenharmony_ci ringacc->proxy_gcfg = devm_ioremap_resource(dev, res); 11458c2ecf20Sopenharmony_ci if (IS_ERR(ringacc->proxy_gcfg)) 11468c2ecf20Sopenharmony_ci return PTR_ERR(ringacc->proxy_gcfg); 11478c2ecf20Sopenharmony_ci 11488c2ecf20Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 11498c2ecf20Sopenharmony_ci "proxy_target"); 11508c2ecf20Sopenharmony_ci ringacc->proxy_target_base = devm_ioremap_resource(dev, res); 11518c2ecf20Sopenharmony_ci if (IS_ERR(ringacc->proxy_target_base)) 11528c2ecf20Sopenharmony_ci return PTR_ERR(ringacc->proxy_target_base); 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci ringacc->num_proxies = readl(&ringacc->proxy_gcfg->config) & 11558c2ecf20Sopenharmony_ci K3_RINGACC_PROXY_CFG_THREADS_MASK; 11568c2ecf20Sopenharmony_ci 11578c2ecf20Sopenharmony_ci ringacc->rings = devm_kzalloc(dev, 11588c2ecf20Sopenharmony_ci sizeof(*ringacc->rings) * 11598c2ecf20Sopenharmony_ci ringacc->num_rings, 11608c2ecf20Sopenharmony_ci GFP_KERNEL); 11618c2ecf20Sopenharmony_ci ringacc->rings_inuse = devm_kcalloc(dev, 11628c2ecf20Sopenharmony_ci BITS_TO_LONGS(ringacc->num_rings), 11638c2ecf20Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 11648c2ecf20Sopenharmony_ci ringacc->proxy_inuse = devm_kcalloc(dev, 11658c2ecf20Sopenharmony_ci BITS_TO_LONGS(ringacc->num_proxies), 11668c2ecf20Sopenharmony_ci sizeof(unsigned long), GFP_KERNEL); 11678c2ecf20Sopenharmony_ci 11688c2ecf20Sopenharmony_ci if (!ringacc->rings || !ringacc->rings_inuse || !ringacc->proxy_inuse) 11698c2ecf20Sopenharmony_ci return -ENOMEM; 11708c2ecf20Sopenharmony_ci 11718c2ecf20Sopenharmony_ci for (i = 0; i < ringacc->num_rings; i++) { 11728c2ecf20Sopenharmony_ci ringacc->rings[i].rt = base_rt + 11738c2ecf20Sopenharmony_ci K3_RINGACC_RT_REGS_STEP * i; 11748c2ecf20Sopenharmony_ci ringacc->rings[i].fifos = base_fifo + 11758c2ecf20Sopenharmony_ci K3_RINGACC_FIFO_REGS_STEP * i; 11768c2ecf20Sopenharmony_ci ringacc->rings[i].parent = ringacc; 11778c2ecf20Sopenharmony_ci ringacc->rings[i].ring_id = i; 11788c2ecf20Sopenharmony_ci ringacc->rings[i].proxy_id = K3_RINGACC_PROXY_NOT_USED; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops; 11828c2ecf20Sopenharmony_ci 11838c2ecf20Sopenharmony_ci dev_info(dev, "Ring Accelerator probed rings:%u, gp-rings[%u,%u] sci-dev-id:%u\n", 11848c2ecf20Sopenharmony_ci ringacc->num_rings, 11858c2ecf20Sopenharmony_ci ringacc->rm_gp_range->desc[0].start, 11868c2ecf20Sopenharmony_ci ringacc->rm_gp_range->desc[0].num, 11878c2ecf20Sopenharmony_ci ringacc->tisci_dev_id); 11888c2ecf20Sopenharmony_ci dev_info(dev, "dma-ring-reset-quirk: %s\n", 11898c2ecf20Sopenharmony_ci ringacc->dma_ring_reset_quirk ? "enabled" : "disabled"); 11908c2ecf20Sopenharmony_ci dev_info(dev, "RA Proxy rev. %08x, num_proxies:%u\n", 11918c2ecf20Sopenharmony_ci readl(&ringacc->proxy_gcfg->revision), ringacc->num_proxies); 11928c2ecf20Sopenharmony_ci 11938c2ecf20Sopenharmony_ci return 0; 11948c2ecf20Sopenharmony_ci} 11958c2ecf20Sopenharmony_ci 11968c2ecf20Sopenharmony_cistruct ringacc_match_data { 11978c2ecf20Sopenharmony_ci struct k3_ringacc_ops ops; 11988c2ecf20Sopenharmony_ci}; 11998c2ecf20Sopenharmony_ci 12008c2ecf20Sopenharmony_cistatic struct ringacc_match_data k3_ringacc_data = { 12018c2ecf20Sopenharmony_ci .ops = { 12028c2ecf20Sopenharmony_ci .init = k3_ringacc_init, 12038c2ecf20Sopenharmony_ci }, 12048c2ecf20Sopenharmony_ci}; 12058c2ecf20Sopenharmony_ci 12068c2ecf20Sopenharmony_ci/* Match table for of_platform binding */ 12078c2ecf20Sopenharmony_cistatic const struct of_device_id k3_ringacc_of_match[] = { 12088c2ecf20Sopenharmony_ci { .compatible = "ti,am654-navss-ringacc", .data = &k3_ringacc_data, }, 12098c2ecf20Sopenharmony_ci {}, 12108c2ecf20Sopenharmony_ci}; 12118c2ecf20Sopenharmony_ci 12128c2ecf20Sopenharmony_cistatic int k3_ringacc_probe(struct platform_device *pdev) 12138c2ecf20Sopenharmony_ci{ 12148c2ecf20Sopenharmony_ci const struct ringacc_match_data *match_data; 12158c2ecf20Sopenharmony_ci const struct of_device_id *match; 12168c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 12178c2ecf20Sopenharmony_ci struct k3_ringacc *ringacc; 12188c2ecf20Sopenharmony_ci int ret; 12198c2ecf20Sopenharmony_ci 12208c2ecf20Sopenharmony_ci match = of_match_node(k3_ringacc_of_match, dev->of_node); 12218c2ecf20Sopenharmony_ci if (!match) 12228c2ecf20Sopenharmony_ci return -ENODEV; 12238c2ecf20Sopenharmony_ci match_data = match->data; 12248c2ecf20Sopenharmony_ci 12258c2ecf20Sopenharmony_ci ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL); 12268c2ecf20Sopenharmony_ci if (!ringacc) 12278c2ecf20Sopenharmony_ci return -ENOMEM; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci ringacc->dev = dev; 12308c2ecf20Sopenharmony_ci mutex_init(&ringacc->req_lock); 12318c2ecf20Sopenharmony_ci ringacc->ops = &match_data->ops; 12328c2ecf20Sopenharmony_ci 12338c2ecf20Sopenharmony_ci ret = ringacc->ops->init(pdev, ringacc); 12348c2ecf20Sopenharmony_ci if (ret) 12358c2ecf20Sopenharmony_ci return ret; 12368c2ecf20Sopenharmony_ci 12378c2ecf20Sopenharmony_ci dev_set_drvdata(dev, ringacc); 12388c2ecf20Sopenharmony_ci 12398c2ecf20Sopenharmony_ci mutex_lock(&k3_ringacc_list_lock); 12408c2ecf20Sopenharmony_ci list_add_tail(&ringacc->list, &k3_ringacc_list); 12418c2ecf20Sopenharmony_ci mutex_unlock(&k3_ringacc_list_lock); 12428c2ecf20Sopenharmony_ci 12438c2ecf20Sopenharmony_ci return 0; 12448c2ecf20Sopenharmony_ci} 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_cistatic struct platform_driver k3_ringacc_driver = { 12478c2ecf20Sopenharmony_ci .probe = k3_ringacc_probe, 12488c2ecf20Sopenharmony_ci .driver = { 12498c2ecf20Sopenharmony_ci .name = "k3-ringacc", 12508c2ecf20Sopenharmony_ci .of_match_table = k3_ringacc_of_match, 12518c2ecf20Sopenharmony_ci .suppress_bind_attrs = true, 12528c2ecf20Sopenharmony_ci }, 12538c2ecf20Sopenharmony_ci}; 12548c2ecf20Sopenharmony_cibuiltin_platform_driver(k3_ringacc_driver); 1255