[PATCH 3/7] ARM: K3: add navss-ringacc driver

Sascha Hauer s.hauer at pengutronix.de
Fri Nov 8 05:15:01 PST 2024


>From the commit message adding the ringacc driver to Linux:

> The Ring Accelerator (RINGACC or RA) provides hardware acceleration to
> enable straightforward passing of work between a producer and a consumer.
> There is one RINGACC module per NAVSS on TI AM65x SoCs.
>
> The RINGACC converts constant-address read and write accesses to equivalent
> read or write accesses to a circular data structure in memory. The RINGACC
> eliminates the need for each DMA controller which needs to access ring
> elements from having to know the current state of the ring (base address,
> current offset). The DMA controller performs a read or write access to a
> specific address range (which maps to the source interface on the RINGACC)
> and the RINGACC replaces the address for the transaction with a new address
> which corresponds to the head or tail element of the ring (head for reads,
> tail for writes). Since the RINGACC maintains the state, multiple DMA
> controllers or channels are allowed to coherently share the same rings as
> applicable. The RINGACC is able to place data which is destined towards
> software into cached memory directly.

This adds support for this driver based on the U-Boot driver from U-Boot
v2025.01-rc1.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
---
 drivers/soc/Makefile              |    1 +
 drivers/soc/ti/Makefile           |    1 +
 drivers/soc/ti/k3-navss-ringacc.c | 1163 +++++++++++++++++++++++++++++++++++++
 include/soc/ti/k3-navss-ringacc.h |  252 ++++++++
 4 files changed, 1417 insertions(+)

diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile
index 9bff737b78..5b6ebe53c3 100644
--- a/drivers/soc/Makefile
+++ b/drivers/soc/Makefile
@@ -5,3 +5,4 @@ obj-$(CONFIG_KVX)		+= kvx/
 obj-$(CONFIG_ARCH_ROCKCHIP)	+= rockchip/
 obj-$(CONFIG_CPU_SIFIVE)	+= sifive/
 obj-$(CONFIG_SOC_STARFIVE)	+= starfive/
+obj-$(CONFIG_ARCH_K3)		+= ti/
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
new file mode 100644
index 0000000000..56f6653882
--- /dev/null
+++ b/drivers/soc/ti/Makefile
@@ -0,0 +1 @@
+obj-y += k3-navss-ringacc.o
diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c
new file mode 100644
index 0000000000..d95b2a5d5d
--- /dev/null
+++ b/drivers/soc/ti/k3-navss-ringacc.c
@@ -0,0 +1,1163 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * TI K3 AM65x NAVSS Ring accelerator Manager (RA) subsystem driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#include <driver.h>
+#include <xfuncs.h>
+#include <soc/ti/k3-navss-ringacc.h>
+#include <soc/ti/ti_sci_protocol.h>
+#include <linux/device.h>
+
+static LIST_HEAD(k3_nav_ringacc_list);
+
+static	void ringacc_writel(u32 v, void __iomem *reg)
+{
+	writel(v, reg);
+}
+
+static	u32 ringacc_readl(void __iomem *reg)
+{
+	u32 v;
+
+	v = readl(reg);
+
+	return v;
+}
+
+#define KNAV_RINGACC_CFG_RING_SIZE_ELCNT_MASK		GENMASK(19, 0)
+#define K3_DMARING_RING_CFG_RING_SIZE_ELCNT_MASK		GENMASK(15, 0)
+
+/**
+ * struct k3_nav_ring_rt_regs -  The RA Control/Status Registers region
+ */
+struct k3_nav_ring_rt_regs {
+	u32	resv_16[4];
+	u32	db;		/* RT Ring N Doorbell Register */
+	u32	resv_4[1];
+	u32	occ;		/* RT Ring N Occupancy Register */
+	u32	indx;		/* RT Ring N Current Index Register */
+	u32	hwocc;		/* RT Ring N Hardware Occupancy Register */
+	u32	hwindx;		/* RT Ring N Current Index Register */
+};
+
+#define KNAV_RINGACC_RT_REGS_STEP	0x1000
+#define K3_DMARING_RING_RT_REGS_STEP			0x2000
+#define K3_DMARING_RING_RT_REGS_REVERSE_OFS		0x1000
+#define KNAV_RINGACC_RT_OCC_MASK		GENMASK(20, 0)
+#define K3_DMARING_RING_RT_OCC_TDOWN_COMPLETE		BIT(31)
+#define K3_DMARING_RING_RT_DB_ENTRY_MASK		GENMASK(7, 0)
+#define K3_DMARING_RING_RT_DB_TDOWN_ACK		BIT(31)
+
+/**
+ * struct k3_nav_ring_fifo_regs -  The Ring Accelerator Queues Registers region
+ */
+struct k3_nav_ring_fifo_regs {
+	u32	head_data[128];		/* Ring Head Entry Data Registers */
+	u32	tail_data[128];		/* Ring Tail Entry Data Registers */
+	u32	peek_head_data[128];	/* Ring Peek Head Entry Data Regs */
+	u32	peek_tail_data[128];	/* Ring Peek Tail Entry Data Regs */
+};
+
+#define KNAV_RINGACC_FIFO_WINDOW_SIZE_BYTES  (512U)
+#define KNAV_RINGACC_FIFO_REGS_STEP	0x1000
+#define KNAV_RINGACC_MAX_DB_RING_CNT    (127U)
+
+/**
+ * struct k3_nav_ring_ops -  Ring operations
+ */
+struct k3_nav_ring_ops {
+	int (*push_tail)(struct k3_nav_ring *ring, void *elm);
+	int (*push_head)(struct k3_nav_ring *ring, void *elm);
+	int (*pop_tail)(struct k3_nav_ring *ring, void *elm);
+	int (*pop_head)(struct k3_nav_ring *ring, void *elm);
+};
+
+/**
+ * struct k3_nav_ring_state - Internal state tracking structure
+ *
+ * @free: Number of free entries
+ * @occ: Occupancy
+ * @windex: Write index
+ * @rindex: Read index
+ */
+struct k3_nav_ring_state {
+	u32 free;
+	u32 occ;
+	u32 windex;
+	u32 rindex;
+	u32 tdown_complete:1;
+};
+
+/**
+ * struct k3_nav_ring - RA Ring descriptor
+ *
+ * @cfg - Ring configuration registers
+ * @rt - Ring control/status registers
+ * @fifos - Ring queues registers
+ * @ring_mem_dma - Ring buffer dma address
+ * @ring_mem_virt - Ring buffer virt address
+ * @ops - Ring operations
+ * @size - Ring size in elements
+ * @elm_size - Size of the ring element
+ * @mode - Ring mode
+ * @flags - flags
+ * @ring_id - Ring Id
+ * @parent - Pointer on struct @k3_nav_ringacc
+ * @use_count - Use count for shared rings
+ */
+struct k3_nav_ring {
+	struct k3_nav_ring_cfg_regs __iomem *cfg;
+	struct k3_nav_ring_rt_regs __iomem *rt;
+	struct k3_nav_ring_fifo_regs __iomem *fifos;
+	dma_addr_t	ring_mem_dma;
+	void		*ring_mem_virt;
+	struct k3_nav_ring_ops *ops;
+	u32		size;
+	enum k3_nav_ring_size elm_size;
+	enum k3_nav_ring_mode mode;
+	u32		flags;
+#define KNAV_RING_FLAG_BUSY	BIT(1)
+#define K3_NAV_RING_FLAG_SHARED	BIT(2)
+#define K3_NAV_RING_FLAG_REVERSE BIT(3)
+	struct k3_nav_ring_state state;
+	u32		ring_id;
+	struct k3_nav_ringacc	*parent;
+	u32		use_count;
+};
+
+struct k3_nav_ringacc_ops {
+	int (*init)(struct device *dev, struct k3_nav_ringacc *ringacc);
+};
+
+/**
+ * struct k3_nav_ringacc - Rings accelerator descriptor
+ *
+ * @dev - pointer on RA device
+ * @num_rings - number of ring in RA
+ * @rm_gp_range - general purpose rings range from tisci
+ * @dma_ring_reset_quirk - DMA reset w/a enable
+ * @num_proxies - number of RA proxies
+ * @rings - array of rings descriptors (struct @k3_nav_ring)
+ * @list - list of RAs in the system
+ * @tisci - pointer ti-sci handle
+ * @tisci_ring_ops - ti-sci rings ops
+ * @tisci_dev_id - ti-sci device id
+ * @ops: SoC specific ringacc operation
+ * @dual_ring: indicate k3_dmaring dual ring support
+ */
+struct k3_nav_ringacc {
+	struct device *dev;
+	u32 num_rings; /* number of rings in Ringacc module */
+	unsigned long *rings_inuse;
+	struct ti_sci_resource *rm_gp_range;
+	bool dma_ring_reset_quirk;
+	u32 num_proxies;
+
+	struct k3_nav_ring *rings;
+	struct list_head list;
+
+	const struct ti_sci_handle *tisci;
+	const struct ti_sci_rm_ringacc_ops *tisci_ring_ops;
+	u32  tisci_dev_id;
+
+	const struct k3_nav_ringacc_ops *ops;
+	bool dual_ring;
+};
+
+struct k3_nav_ring_cfg_regs {
+	u32	resv_64[16];
+	u32	ba_lo;		/* Ring Base Address Lo Register */
+	u32	ba_hi;		/* Ring Base Address Hi Register */
+	u32	size;		/* Ring Size Register */
+	u32	event;		/* Ring Event Register */
+	u32	orderid;	/* Ring OrderID Register */
+};
+
+#define KNAV_RINGACC_CFG_REGS_STEP	0x100
+
+#define KNAV_RINGACC_CFG_RING_BA_HI_ADDR_HI_MASK	GENMASK(15, 0)
+
+#define KNAV_RINGACC_CFG_RING_SIZE_QMODE_MASK		GENMASK(31, 30)
+#define KNAV_RINGACC_CFG_RING_SIZE_QMODE_SHIFT		(30)
+
+#define KNAV_RINGACC_CFG_RING_SIZE_ELSIZE_MASK		GENMASK(26, 24)
+#define KNAV_RINGACC_CFG_RING_SIZE_ELSIZE_SHIFT		(24)
+
+#define KNAV_RINGACC_CFG_RING_SIZE_MASK			GENMASK(19, 0)
+
+static void k3_ringacc_ring_reset_raw(struct k3_nav_ring *ring)
+{
+	u32 reg;
+
+	reg = readl(&ring->cfg->size);
+	reg &= ~KNAV_RINGACC_CFG_RING_SIZE_MASK;
+	reg |= ring->size;
+	writel(reg, &ring->cfg->size);
+}
+
+static void k3_ringacc_ring_reconfig_qmode_raw(struct k3_nav_ring *ring, enum k3_nav_ring_mode mode)
+{
+	u32 val;
+
+	val = readl(&ring->cfg->size);
+	val &= ~KNAV_RINGACC_CFG_RING_SIZE_QMODE_MASK;
+	val |= mode << KNAV_RINGACC_CFG_RING_SIZE_QMODE_SHIFT;
+	writel(val, &ring->cfg->size);
+}
+
+static void k3_ringacc_ring_free_raw(struct k3_nav_ring *ring)
+{
+	writel(0, &ring->cfg->ba_hi);
+	writel(0, &ring->cfg->ba_lo);
+	writel(0, &ring->cfg->size);
+}
+
+static void k3_nav_ringacc_ring_cfg_raw(struct k3_nav_ring *ring)
+{
+	u32 val;
+
+	writel(lower_32_bits(ring->ring_mem_dma), &ring->cfg->ba_lo);
+	writel(upper_32_bits(ring->ring_mem_dma), &ring->cfg->ba_hi);
+
+	val = ring->mode << KNAV_RINGACC_CFG_RING_SIZE_QMODE_SHIFT |
+	      ring->elm_size << KNAV_RINGACC_CFG_RING_SIZE_ELSIZE_SHIFT |
+	      ring->size;
+	writel(val, &ring->cfg->size);
+}
+
+static int k3_nav_ringacc_ring_read_occ(struct k3_nav_ring *ring)
+{
+	return readl(&ring->rt->occ) & KNAV_RINGACC_RT_OCC_MASK;
+}
+
+static void k3_nav_ringacc_ring_update_occ(struct k3_nav_ring *ring)
+{
+	u32 val;
+
+	val = readl(&ring->rt->occ);
+
+	ring->state.occ = val & KNAV_RINGACC_RT_OCC_MASK;
+	ring->state.tdown_complete = !!(val & K3_DMARING_RING_RT_OCC_TDOWN_COMPLETE);
+}
+
+static void *k3_nav_ringacc_get_elm_addr(struct k3_nav_ring *ring, u32 idx)
+{
+	return (idx * (4 << ring->elm_size) + ring->ring_mem_virt);
+}
+
+static int k3_nav_ringacc_ring_push_mem(struct k3_nav_ring *ring, void *elem);
+static int k3_nav_ringacc_ring_pop_mem(struct k3_nav_ring *ring, void *elem);
+static int k3_dmaring_ring_fwd_pop_mem(struct k3_nav_ring *ring, void *elem);
+static int k3_dmaring_ring_reverse_pop_mem(struct k3_nav_ring *ring, void *elem);
+
+static struct k3_nav_ring_ops k3_nav_mode_ring_ops = {
+		.push_tail = k3_nav_ringacc_ring_push_mem,
+		.pop_head = k3_nav_ringacc_ring_pop_mem,
+};
+
+static struct k3_nav_ring_ops k3_dmaring_fwd_ring_ops = {
+		.push_tail = k3_nav_ringacc_ring_push_mem,
+		.pop_head = k3_dmaring_ring_fwd_pop_mem,
+};
+
+static struct k3_nav_ring_ops k3_dmaring_reverse_ring_ops = {
+		.pop_head = k3_dmaring_ring_reverse_pop_mem,
+};
+
+struct device *k3_nav_ringacc_get_dev(struct k3_nav_ringacc *ringacc)
+{
+	return ringacc->dev;
+}
+
+struct k3_nav_ring *k3_nav_ringacc_request_ring(struct k3_nav_ringacc *ringacc,
+						int id)
+{
+	if (id == K3_NAV_RINGACC_RING_ID_ANY) {
+		/* Request for any general purpose ring */
+		struct ti_sci_resource_desc *gp_rings =
+					&ringacc->rm_gp_range->desc[0];
+		unsigned long size;
+
+		size = gp_rings->start + gp_rings->num;
+		id = find_next_zero_bit(ringacc->rings_inuse,
+					size, gp_rings->start);
+		if (id == size)
+			goto error;
+	} else if (id < 0) {
+		goto error;
+	}
+
+	if (test_bit(id, ringacc->rings_inuse) &&
+	    !(ringacc->rings[id].flags & K3_NAV_RING_FLAG_SHARED))
+		goto error;
+	else if (ringacc->rings[id].flags & K3_NAV_RING_FLAG_SHARED)
+		goto out;
+
+	dev_dbg(ringacc->dev, "Giving ring#%d\n", id);
+
+	set_bit(id, ringacc->rings_inuse);
+out:
+	ringacc->rings[id].use_count++;
+	return &ringacc->rings[id];
+
+error:
+	return NULL;
+}
+
+static int k3_dmaring_ring_request_rings_pair(struct k3_nav_ringacc *ringacc,
+					      int fwd_id, int compl_id,
+					      struct k3_nav_ring **fwd_ring,
+					      struct k3_nav_ring **compl_ring)
+{
+	/* k3_dmaring: fwd_id == compl_id, so we ignore compl_id */
+	if (fwd_id < 0)
+		return -EINVAL;
+
+	if (test_bit(fwd_id, ringacc->rings_inuse))
+		return -EBUSY;
+
+	*fwd_ring = &ringacc->rings[fwd_id];
+	*compl_ring = &ringacc->rings[fwd_id + ringacc->num_rings];
+	set_bit(fwd_id, ringacc->rings_inuse);
+	ringacc->rings[fwd_id].use_count++;
+	dev_dbg(ringacc->dev, "Giving ring#%d\n", fwd_id);
+
+	return 0;
+}
+
+int k3_nav_ringacc_request_rings_pair(struct k3_nav_ringacc *ringacc,
+				      int fwd_id, int compl_id,
+				      struct k3_nav_ring **fwd_ring,
+				      struct k3_nav_ring **compl_ring)
+{
+	int ret = 0;
+
+	if (!fwd_ring || !compl_ring)
+		return -EINVAL;
+
+	if (ringacc->dual_ring)
+		return k3_dmaring_ring_request_rings_pair(ringacc, fwd_id, compl_id,
+						    fwd_ring, compl_ring);
+
+	*fwd_ring = k3_nav_ringacc_request_ring(ringacc, fwd_id);
+	if (!(*fwd_ring))
+		return -ENODEV;
+
+	*compl_ring = k3_nav_ringacc_request_ring(ringacc, compl_id);
+	if (!(*compl_ring)) {
+		k3_nav_ringacc_ring_free(*fwd_ring);
+		ret = -ENODEV;
+	}
+
+	return ret;
+}
+
+static void k3_ringacc_ring_reset_sci(struct k3_nav_ring *ring)
+{
+	struct k3_nav_ringacc *ringacc = ring->parent;
+	int ret;
+
+	if (IS_ENABLED(CONFIG_K3_DM_FW))
+		return k3_ringacc_ring_reset_raw(ring);
+
+	ret = ringacc->tisci_ring_ops->config(
+			ringacc->tisci,
+			TI_SCI_MSG_VALUE_RM_RING_COUNT_VALID,
+			ringacc->tisci_dev_id,
+			ring->ring_id,
+			0,
+			0,
+			ring->size,
+			0,
+			0,
+			0);
+	if (ret)
+		dev_err(ringacc->dev, "TISCI reset ring fail (%d) ring_idx %d\n",
+			ret, ring->ring_id);
+}
+
+void k3_nav_ringacc_ring_reset(struct k3_nav_ring *ring)
+{
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return;
+
+	memset(&ring->state, 0, sizeof(ring->state));
+
+	k3_ringacc_ring_reset_sci(ring);
+}
+
+static void k3_ringacc_ring_reconfig_qmode_sci(struct k3_nav_ring *ring,
+					       enum k3_nav_ring_mode mode)
+{
+	struct k3_nav_ringacc *ringacc = ring->parent;
+	int ret;
+
+	if (IS_ENABLED(CONFIG_K3_DM_FW))
+		return k3_ringacc_ring_reconfig_qmode_raw(ring, mode);
+
+	ret = ringacc->tisci_ring_ops->config(
+			ringacc->tisci,
+			TI_SCI_MSG_VALUE_RM_RING_MODE_VALID,
+			ringacc->tisci_dev_id,
+			ring->ring_id,
+			0,
+			0,
+			0,
+			mode,
+			0,
+			0);
+	if (ret)
+		dev_err(ringacc->dev, "TISCI reconf qmode fail (%d) ring_idx %d\n",
+			ret, ring->ring_id);
+}
+
+void k3_nav_ringacc_ring_reset_dma(struct k3_nav_ring *ring, u32 occ)
+{
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return;
+
+	if (!ring->parent->dma_ring_reset_quirk) {
+		k3_nav_ringacc_ring_reset(ring);
+		return;
+	}
+
+	if (!occ)
+		occ = ringacc_readl(&ring->rt->occ);
+
+	if (occ) {
+		u32 db_ring_cnt, db_ring_cnt_cur;
+
+		pr_debug("%s %u occ: %u\n", __func__,
+			 ring->ring_id, occ);
+		/* 2. Reset the ring */
+		k3_ringacc_ring_reset_sci(ring);
+
+		/*
+		 * 3. Setup the ring in ring/doorbell mode
+		 * (if not already in this mode)
+		 */
+		if (ring->mode != K3_NAV_RINGACC_RING_MODE_RING)
+			k3_ringacc_ring_reconfig_qmode_sci(
+					ring, K3_NAV_RINGACC_RING_MODE_RING);
+		/*
+		 * 4. Ring the doorbell 2**22 - ringOcc times.
+		 * This will wrap the internal UDMAP ring state occupancy
+		 * counter (which is 21-bits wide) to 0.
+		 */
+		db_ring_cnt = (1U << 22) - occ;
+
+		while (db_ring_cnt != 0) {
+			/*
+			 * Ring the doorbell with the maximum count each
+			 * iteration if possible to minimize the total
+			 * of writes
+			 */
+			if (db_ring_cnt > KNAV_RINGACC_MAX_DB_RING_CNT)
+				db_ring_cnt_cur = KNAV_RINGACC_MAX_DB_RING_CNT;
+			else
+				db_ring_cnt_cur = db_ring_cnt;
+
+			writel(db_ring_cnt_cur, &ring->rt->db);
+			db_ring_cnt -= db_ring_cnt_cur;
+		}
+
+		/* 5. Restore the original ring mode (if not ring mode) */
+		if (ring->mode != K3_NAV_RINGACC_RING_MODE_RING)
+			k3_ringacc_ring_reconfig_qmode_sci(ring, ring->mode);
+	}
+
+	/* 2. Reset the ring */
+	k3_nav_ringacc_ring_reset(ring);
+}
+
+static void k3_ringacc_ring_free_sci(struct k3_nav_ring *ring)
+{
+	struct k3_nav_ringacc *ringacc = ring->parent;
+	int ret;
+
+	if (IS_ENABLED(CONFIG_K3_DM_FW))
+		return k3_ringacc_ring_free_raw(ring);
+
+	ret = ringacc->tisci_ring_ops->config(
+			ringacc->tisci,
+			TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER,
+			ringacc->tisci_dev_id,
+			ring->ring_id,
+			0,
+			0,
+			0,
+			0,
+			0,
+			0);
+	if (ret)
+		dev_err(ringacc->dev, "TISCI ring free fail (%d) ring_idx %d\n",
+			ret, ring->ring_id);
+}
+
+int k3_nav_ringacc_ring_free(struct k3_nav_ring *ring)
+{
+	struct k3_nav_ringacc *ringacc;
+
+	if (!ring)
+		return -EINVAL;
+
+	ringacc = ring->parent;
+
+	/*
+	 * k3_dmaring: rings shared memory and configuration, only forward ring is
+	 * configured and reverse ring considered as slave.
+	 */
+	if (ringacc->dual_ring && (ring->flags & K3_NAV_RING_FLAG_REVERSE))
+		return 0;
+
+	pr_debug("%s flags: 0x%08x\n", __func__, ring->flags);
+
+	if (!test_bit(ring->ring_id, ringacc->rings_inuse))
+		return -EINVAL;
+
+	if (--ring->use_count)
+		goto out;
+
+	if (!(ring->flags & KNAV_RING_FLAG_BUSY))
+		goto no_init;
+
+	k3_ringacc_ring_free_sci(ring);
+
+	dma_free_coherent(ringacc->dev,
+			  ring->ring_mem_virt, ring->ring_mem_dma,
+			  ring->size * (4 << ring->elm_size));
+	ring->flags &= ~KNAV_RING_FLAG_BUSY;
+	ring->ops = NULL;
+
+no_init:
+	clear_bit(ring->ring_id, ringacc->rings_inuse);
+
+out:
+	return 0;
+}
+
+u32 k3_nav_ringacc_get_ring_id(struct k3_nav_ring *ring)
+{
+	if (!ring)
+		return -EINVAL;
+
+	return ring->ring_id;
+}
+
+static int k3_nav_ringacc_ring_cfg_sci(struct k3_nav_ring *ring)
+{
+	struct k3_nav_ringacc *ringacc = ring->parent;
+	u32 ring_idx;
+	int ret;
+
+	if (!ringacc->tisci)
+		return -EINVAL;
+
+	ring_idx = ring->ring_id;
+	ret = ringacc->tisci_ring_ops->config(
+			ringacc->tisci,
+			TI_SCI_MSG_VALUE_RM_ALL_NO_ORDER,
+			ringacc->tisci_dev_id,
+			ring_idx,
+			lower_32_bits(ring->ring_mem_dma),
+			upper_32_bits(ring->ring_mem_dma),
+			ring->size,
+			ring->mode,
+			ring->elm_size,
+			0);
+	if (ret) {
+		dev_err(ringacc->dev, "TISCI config ring fail (%d) ring_idx %d\n",
+			ret, ring_idx);
+		return ret;
+	}
+
+	/*
+	 * Above TI SCI call handles firewall configuration, cfg
+	 * register configuration still has to be done locally in
+	 * absence of RM services.
+	 */
+	if (IS_ENABLED(CONFIG_K3_DM_FW))
+		k3_nav_ringacc_ring_cfg_raw(ring);
+
+	return 0;
+}
+
+static int k3_dmaring_ring_cfg(struct k3_nav_ring *ring, struct k3_nav_ring_cfg *cfg)
+{
+	struct k3_nav_ringacc *ringacc;
+	struct k3_nav_ring *reverse_ring;
+	int ret = 0;
+
+	if (cfg->elm_size != K3_NAV_RINGACC_RING_ELSIZE_8 ||
+	    cfg->mode != K3_NAV_RINGACC_RING_MODE_RING ||
+	    cfg->size & ~K3_DMARING_RING_CFG_RING_SIZE_ELCNT_MASK)
+		return -EINVAL;
+
+	ringacc = ring->parent;
+
+	/*
+	 * k3_dmaring: rings shared memory and configuration, only forward ring is
+	 * configured and reverse ring considered as slave.
+	 */
+	if (ringacc->dual_ring && (ring->flags & K3_NAV_RING_FLAG_REVERSE))
+		return 0;
+
+	if (!test_bit(ring->ring_id, ringacc->rings_inuse))
+		return -EINVAL;
+
+	ring->size = cfg->size;
+	ring->elm_size = cfg->elm_size;
+	ring->mode = cfg->mode;
+	memset(&ring->state, 0, sizeof(ring->state));
+
+	ring->ops = &k3_dmaring_fwd_ring_ops;
+
+	ring->ring_mem_virt =
+		dma_alloc_coherent(ringacc->dev, ring->size * (4 << ring->elm_size),
+				   &ring->ring_mem_dma);
+	if (!ring->ring_mem_virt) {
+		dev_err(ringacc->dev, "Failed to alloc ring mem\n");
+		ret = -ENOMEM;
+		goto err_free_ops;
+	}
+
+	ret = k3_nav_ringacc_ring_cfg_sci(ring);
+	if (ret)
+		goto err_free_mem;
+
+	ring->flags |= KNAV_RING_FLAG_BUSY;
+
+	/* k3_dmaring: configure reverse ring */
+	reverse_ring = &ringacc->rings[ring->ring_id + ringacc->num_rings];
+	reverse_ring->size = cfg->size;
+	reverse_ring->elm_size = cfg->elm_size;
+	reverse_ring->mode = cfg->mode;
+	memset(&reverse_ring->state, 0, sizeof(reverse_ring->state));
+	reverse_ring->ops = &k3_dmaring_reverse_ring_ops;
+
+	reverse_ring->ring_mem_virt = ring->ring_mem_virt;
+	reverse_ring->ring_mem_dma = ring->ring_mem_dma;
+	reverse_ring->flags |= KNAV_RING_FLAG_BUSY;
+
+	return 0;
+
+err_free_mem:
+	dma_free_coherent(ringacc->dev,
+			  ring->ring_mem_virt, ring->ring_mem_dma,
+			  ring->size * (4 << ring->elm_size));
+err_free_ops:
+	ring->ops = NULL;
+	return ret;
+}
+
+int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring,
+			    struct k3_nav_ring_cfg *cfg)
+{
+	struct k3_nav_ringacc *ringacc = ring->parent;
+	int ret = 0;
+
+	if (!ring || !cfg)
+		return -EINVAL;
+
+	if (ringacc->dual_ring)
+		return k3_dmaring_ring_cfg(ring, cfg);
+
+	if (cfg->elm_size > K3_NAV_RINGACC_RING_ELSIZE_256 ||
+	    cfg->mode > K3_NAV_RINGACC_RING_MODE_QM ||
+	    cfg->size & ~KNAV_RINGACC_CFG_RING_SIZE_ELCNT_MASK ||
+	    !test_bit(ring->ring_id, ringacc->rings_inuse))
+		return -EINVAL;
+
+	if (ring->use_count != 1)
+		return 0;
+
+	ring->size = cfg->size;
+	ring->elm_size = cfg->elm_size;
+	ring->mode = cfg->mode;
+	memset(&ring->state, 0, sizeof(ring->state));
+
+	switch (ring->mode) {
+	case K3_NAV_RINGACC_RING_MODE_RING:
+		ring->ops = &k3_nav_mode_ring_ops;
+		break;
+	default:
+		ring->ops = NULL;
+		ret = -EINVAL;
+		goto err_free_ops;
+	};
+
+	ring->ring_mem_virt =
+			dma_alloc_coherent(ringacc->dev,
+					   ring->size * (4 << ring->elm_size),
+					   &ring->ring_mem_dma);
+	if (!ring->ring_mem_virt) {
+		dev_err(ringacc->dev, "Failed to alloc ring mem\n");
+		ret = -ENOMEM;
+		goto err_free_ops;
+	}
+
+	ret = k3_nav_ringacc_ring_cfg_sci(ring);
+
+	if (ret)
+		goto err_free_mem;
+
+	ring->flags |= KNAV_RING_FLAG_BUSY;
+	ring->flags |= (cfg->flags & K3_NAV_RINGACC_RING_SHARED) ?
+			K3_NAV_RING_FLAG_SHARED : 0;
+
+	return 0;
+
+err_free_mem:
+	dma_free_coherent(ringacc->dev,
+			  ring->ring_mem_virt, ring->ring_mem_dma,
+			  ring->size * (4 << ring->elm_size));
+err_free_ops:
+	ring->ops = NULL;
+	return ret;
+}
+
+u32 k3_nav_ringacc_ring_get_size(struct k3_nav_ring *ring)
+{
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	return ring->size;
+}
+
+u32 k3_nav_ringacc_ring_get_free(struct k3_nav_ring *ring)
+{
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	if (!ring->state.free)
+		ring->state.free = ring->size - ringacc_readl(&ring->rt->occ);
+
+	return ring->state.free;
+}
+
+u32 k3_nav_ringacc_ring_get_occ(struct k3_nav_ring *ring)
+{
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	return ringacc_readl(&ring->rt->occ);
+}
+
+u32 k3_nav_ringacc_ring_is_full(struct k3_nav_ring *ring)
+{
+	return !k3_nav_ringacc_ring_get_free(ring);
+}
+
+enum k3_ringacc_access_mode {
+	K3_RINGACC_ACCESS_MODE_PUSH_HEAD,
+	K3_RINGACC_ACCESS_MODE_POP_HEAD,
+	K3_RINGACC_ACCESS_MODE_PUSH_TAIL,
+	K3_RINGACC_ACCESS_MODE_POP_TAIL,
+	K3_RINGACC_ACCESS_MODE_PEEK_HEAD,
+	K3_RINGACC_ACCESS_MODE_PEEK_TAIL,
+};
+
+static int k3_dmaring_ring_fwd_pop_mem(struct k3_nav_ring *ring, void *elem)
+{
+	void *elem_ptr;
+	u32 elem_idx;
+
+	/*
+	 * k3_dmaring: forward ring is always tied DMA channel and HW does not
+	 * maintain any state data required for POP operation and its unknown
+	 * how much elements were consumed by HW. So, to actually
+	 * do POP, the read pointer has to be recalculated every time.
+	 */
+	ring->state.occ = k3_nav_ringacc_ring_read_occ(ring);
+	if (ring->state.windex >= ring->state.occ)
+		elem_idx = ring->state.windex - ring->state.occ;
+	else
+		elem_idx = ring->size - (ring->state.occ - ring->state.windex);
+
+	elem_ptr = k3_nav_ringacc_get_elm_addr(ring, elem_idx);
+
+	memcpy(elem, elem_ptr, (4 << ring->elm_size));
+
+	ring->state.occ--;
+	writel(-1, &ring->rt->db);
+
+	dev_dbg(ring->parent->dev, "%s: occ%d Windex%d Rindex%d pos_ptr%px\n",
+		__func__, ring->state.occ, ring->state.windex, elem_idx,
+		elem_ptr);
+	return 0;
+}
+
+static int k3_dmaring_ring_reverse_pop_mem(struct k3_nav_ring *ring, void *elem)
+{
+	void *elem_ptr;
+
+	elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->state.rindex);
+
+	if (ring->state.occ) {
+		memcpy(elem, elem_ptr, (4 << ring->elm_size));
+		ring->state.rindex = (ring->state.rindex + 1) % ring->size;
+		ring->state.occ--;
+		writel(-1 & K3_DMARING_RING_RT_DB_ENTRY_MASK, &ring->rt->db);
+	}
+
+	dev_vdbg(ring->parent->dev, "%s: occ%d index%d pos_ptr%px\n",
+		__func__, ring->state.occ, ring->state.rindex, elem_ptr);
+	return 0;
+}
+
+static int k3_nav_ringacc_ring_push_mem(struct k3_nav_ring *ring, void *elem)
+{
+	void *elem_ptr;
+
+	elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->state.windex);
+
+	memcpy(elem_ptr, elem, (4 << ring->elm_size));
+
+	ring->state.windex = (ring->state.windex + 1) % ring->size;
+	ring->state.free--;
+	ringacc_writel(1, &ring->rt->db);
+
+	dev_vdbg(ring->parent->dev, "ring_push_mem: free%d index%d\n",
+		 ring->state.free, ring->state.windex);
+
+	return 0;
+}
+
+static int k3_nav_ringacc_ring_pop_mem(struct k3_nav_ring *ring, void *elem)
+{
+	void *elem_ptr;
+
+	elem_ptr = k3_nav_ringacc_get_elm_addr(ring, ring->state.rindex);
+
+	memcpy(elem, elem_ptr, (4 << ring->elm_size));
+
+	ring->state.rindex = (ring->state.rindex + 1) % ring->size;
+	ring->state.occ--;
+	ringacc_writel(-1, &ring->rt->db);
+
+	dev_vdbg(ring->parent->dev, "ring_pop_mem: occ%d index%d pos_ptr%p\n",
+		 ring->state.occ, ring->state.rindex, elem_ptr);
+	return 0;
+}
+
+int k3_nav_ringacc_ring_push(struct k3_nav_ring *ring, void *elem)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	dev_vdbg(ring->parent->dev, "ring_push%d: free%d index%d\n",
+		 ring->ring_id, ring->state.free, ring->state.windex);
+
+	if (k3_nav_ringacc_ring_is_full(ring))
+		return -ENOMEM;
+
+	if (ring->ops && ring->ops->push_tail)
+		ret = ring->ops->push_tail(ring, elem);
+
+	return ret;
+}
+
+int k3_nav_ringacc_ring_push_head(struct k3_nav_ring *ring, void *elem)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	dev_vdbg(ring->parent->dev, "ring_push_head: free%d index%d\n",
+		 ring->state.free, ring->state.windex);
+
+	if (k3_nav_ringacc_ring_is_full(ring))
+		return -ENOMEM;
+
+	if (ring->ops && ring->ops->push_head)
+		ret = ring->ops->push_head(ring, elem);
+
+	return ret;
+}
+
+int k3_nav_ringacc_ring_pop(struct k3_nav_ring *ring, void *elem)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	if (!ring->state.occ)
+		k3_nav_ringacc_ring_update_occ(ring);
+
+	dev_vdbg(ring->parent->dev, "ring_pop%d: occ%d index%d\n",
+		 ring->ring_id, ring->state.occ, ring->state.rindex);
+
+	if (!ring->state.occ && !ring->state.tdown_complete)
+		return -ENODATA;
+
+	if (ring->ops && ring->ops->pop_head)
+		ret = ring->ops->pop_head(ring, elem);
+
+	return ret;
+}
+
+int k3_nav_ringacc_ring_pop_tail(struct k3_nav_ring *ring, void *elem)
+{
+	int ret = -EOPNOTSUPP;
+
+	if (!ring || !(ring->flags & KNAV_RING_FLAG_BUSY))
+		return -EINVAL;
+
+	if (!ring->state.occ)
+		k3_nav_ringacc_ring_update_occ(ring);
+
+	dev_vdbg(ring->parent->dev, "ring_pop_tail: occ%d index%d\n",
+		 ring->state.occ, ring->state.rindex);
+
+	if (!ring->state.occ)
+		return -ENODATA;
+
+	if (ring->ops && ring->ops->pop_tail)
+		ret = ring->ops->pop_tail(ring, elem);
+
+	return ret;
+}
+
+static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc)
+{
+	struct device *dev = ringacc->dev;
+	int ret;
+	u32 val;
+
+	ret = of_property_read_u32(dev->of_node, "ti,num-rings", &ringacc->num_rings);
+	if (ret) {
+		dev_err(dev, "ti,num-rings read failure %d\n", ret);
+		return -EINVAL;
+	}
+
+	ringacc->dma_ring_reset_quirk =
+			of_property_read_bool(dev->of_node, "ti,dma-ring-reset-quirk");
+
+	ringacc->tisci = ti_sci_get_by_phandle(dev, "ti,sci");
+
+	ret = of_property_read_u32(dev->of_node, "ti,sci", &val);
+	if (!ret && !val) {
+		dev_err(dev, "TISCI RA RM disabled\n");
+		ringacc->tisci = NULL;
+		return ret;
+	}
+
+	ret = of_property_read_u32(dev->of_node, "ti,sci-dev-id", &ringacc->tisci_dev_id);
+	if (ret) {
+		dev_err(dev, "ti,sci-dev-id read failure %d\n", ret);
+		ringacc->tisci = NULL;
+		return ret;
+	}
+
+	ringacc->rm_gp_range = devm_ti_sci_get_of_resource(
+					ringacc->tisci, dev,
+					ringacc->tisci_dev_id,
+					"ti,sci-rm-range-gp-rings");
+	if (IS_ERR(ringacc->rm_gp_range))
+		ret = PTR_ERR(ringacc->rm_gp_range);
+
+	return 0;
+}
+
+static int k3_nav_ringacc_init(struct device *dev, struct k3_nav_ringacc *ringacc)
+{
+	void __iomem *base_cfg, *base_rt;
+	int ret, i;
+
+	ret = k3_nav_ringacc_probe_dt(ringacc);
+	if (ret)
+		return ret;
+
+	base_cfg = dev_request_mem_region_by_name(dev, "cfg");
+	dev_dbg(dev, "cfg %p\n", base_cfg);
+	if (!base_cfg)
+		return -EINVAL;
+
+	base_rt = dev_request_mem_region_by_name(dev, "rt");
+	dev_dbg(dev, "rt %p\n", base_rt);
+	if (!base_rt)
+		return -EINVAL;
+
+	ringacc->rings = devm_kzalloc(dev,
+				      sizeof(*ringacc->rings) *
+				      ringacc->num_rings,
+				      GFP_KERNEL);
+	ringacc->rings_inuse = devm_kcalloc(dev,
+					    BITS_TO_LONGS(ringacc->num_rings),
+					    sizeof(unsigned long), GFP_KERNEL);
+
+	if (!ringacc->rings || !ringacc->rings_inuse)
+		return -ENOMEM;
+
+	for (i = 0; i < ringacc->num_rings; i++) {
+		ringacc->rings[i].cfg = base_cfg +
+					KNAV_RINGACC_CFG_REGS_STEP * i;
+		ringacc->rings[i].rt = base_rt +
+				       KNAV_RINGACC_RT_REGS_STEP * i;
+		ringacc->rings[i].parent = ringacc;
+		ringacc->rings[i].ring_id = i;
+	}
+
+	ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops;
+
+	list_add_tail(&ringacc->list, &k3_nav_ringacc_list);
+
+	dev_info(dev, "Ring Accelerator probed rings:%u, gp-rings[%u,%u] sci-dev-id:%u\n",
+		 ringacc->num_rings,
+		 ringacc->rm_gp_range->desc[0].start,
+		 ringacc->rm_gp_range->desc[0].num,
+		 ringacc->tisci_dev_id);
+	dev_info(dev, "dma-ring-reset-quirk: %s\n",
+		 ringacc->dma_ring_reset_quirk ? "enabled" : "disabled");
+	return 0;
+}
+
+struct k3_nav_ringacc *k3_ringacc_dmarings_init(struct device *dev,
+						struct k3_ringacc_init_data *data)
+{
+	void __iomem *base_rt, *base_cfg;
+	struct k3_nav_ringacc *ringacc;
+	int i;
+
+	ringacc = devm_kzalloc(dev, sizeof(*ringacc), GFP_KERNEL);
+	if (!ringacc)
+		return ERR_PTR(-ENOMEM);
+
+	ringacc->dual_ring = true;
+
+	ringacc->dev = dev;
+	ringacc->num_rings = data->num_rings;
+	ringacc->tisci = data->tisci;
+	ringacc->tisci_dev_id = data->tisci_dev_id;
+
+	base_rt = dev_request_mem_region_by_name(dev, "ringrt");
+	if (!base_rt)
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * Since register property is defined as "ring" for PKTDMA and
+	 * "cfg" for UDMA, configure base address of ring configuration
+	 * register accordingly.
+	 */
+	base_cfg = dev_request_mem_region_by_name(dev, "ring");
+	dev_dbg(dev, "ring %p\n", base_cfg);
+	if (!base_cfg) {
+		base_cfg = dev_request_mem_region_by_name(dev, "cfg");
+		dev_dbg(dev, "cfg %p\n", base_cfg);
+		if (!base_cfg)
+			return ERR_PTR(-EINVAL);
+	}
+
+	ringacc->rings = devm_kzalloc(dev,
+				      sizeof(*ringacc->rings) *
+				      ringacc->num_rings * 2,
+				      GFP_KERNEL);
+	ringacc->rings_inuse = devm_kcalloc(dev,
+					    BITS_TO_LONGS(ringacc->num_rings),
+					    sizeof(unsigned long), GFP_KERNEL);
+
+	if (!ringacc->rings || !ringacc->rings_inuse)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; i < ringacc->num_rings; i++) {
+		struct k3_nav_ring *ring = &ringacc->rings[i];
+
+		ring->cfg = base_cfg + KNAV_RINGACC_CFG_REGS_STEP * i;
+		ring->rt = base_rt + K3_DMARING_RING_RT_REGS_STEP * i;
+		ring->parent = ringacc;
+		ring->ring_id = i;
+
+		ring = &ringacc->rings[ringacc->num_rings + i];
+		ring->rt = base_rt + K3_DMARING_RING_RT_REGS_STEP * i +
+			   K3_DMARING_RING_RT_REGS_REVERSE_OFS;
+		ring->parent = ringacc;
+		ring->ring_id = i;
+		ring->flags = K3_NAV_RING_FLAG_REVERSE;
+	}
+
+	ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops;
+
+	dev_dbg(dev, "k3_dmaring Ring probed rings:%u, sci-dev-id:%u\n",
+		 ringacc->num_rings,
+		 ringacc->tisci_dev_id);
+	dev_dbg(dev, "dma-ring-reset-quirk: %s\n",
+		 ringacc->dma_ring_reset_quirk ? "enabled" : "disabled");
+
+	return ringacc;
+}
+
+struct k3_nav_ringacc *k3_navss_ringacc_get_by_phandle(struct device *dev, const char *property)
+{
+	struct k3_nav_ringacc *ringacc = NULL, *entry;
+	struct device_node *np;
+
+	np = of_parse_phandle(dev->of_node, property, 0);
+	if (!np)
+		return ERR_PTR(-ENODEV);
+
+	of_device_ensure_probed(np);
+
+	list_for_each_entry(entry, &k3_nav_ringacc_list, list)
+		if (dev_of_node(entry->dev) == np) {
+			ringacc = entry;
+			break;
+		}
+
+	if (!ringacc)
+		return ERR_PTR(-ENODEV);
+
+	return ringacc;
+}
+
+struct ringacc_match_data {
+	struct k3_nav_ringacc_ops ops;
+};
+
+static struct ringacc_match_data k3_nav_ringacc_data = {
+	.ops = {
+		.init = k3_nav_ringacc_init,
+	},
+};
+
+static const struct of_device_id knav_ringacc_ids[] = {
+	{
+		.compatible = "ti,am654-navss-ringacc",
+		.data = &k3_nav_ringacc_data,
+	}, {
+		/* sentinel */
+	},
+};
+
+static int k3_nav_ringacc_probe(struct device *dev)
+{
+	struct k3_nav_ringacc *ringacc;
+	int ret;
+	const struct ringacc_match_data *match_data;
+
+	match_data = device_get_match_data(dev);
+
+	ringacc = xzalloc(sizeof(*ringacc));
+
+	ringacc->dev = dev;
+	ringacc->ops = &match_data->ops;
+	ret = ringacc->ops->init(dev, ringacc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+
+static struct driver k3_navss_ringacc = {
+	.probe  = k3_nav_ringacc_probe,
+	.name   = "k3-navss-ringacc",
+	.of_compatible = knav_ringacc_ids,
+};
+
+core_platform_driver(k3_navss_ringacc);
diff --git a/include/soc/ti/k3-navss-ringacc.h b/include/soc/ti/k3-navss-ringacc.h
new file mode 100644
index 0000000000..b9e19a65e8
--- /dev/null
+++ b/include/soc/ti/k3-navss-ringacc.h
@@ -0,0 +1,252 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * TI K3 AM65x NAVSS Ring accelerator Manager (RA) subsystem driver
+ *
+ * Copyright (C) 2018 Texas Instruments Incorporated - https://www.ti.com
+ */
+
+#ifndef __SOC_TI_K3_NAVSS_RINGACC_API_H_
+#define __SOC_TI_K3_NAVSS_RINGACC_API_H_
+
+#include <linux/bitops.h>
+
+/**
+ * enum k3_nav_ring_mode - &struct k3_nav_ring_cfg mode
+ *
+ * RA ring operational modes
+ *
+ * @K3_NAV_RINGACC_RING_MODE_RING: Exposed Ring mode for SW direct access
+ * @K3_NAV_RINGACC_RING_MODE_MESSAGE: Messaging mode. Messaging mode requires
+ *	that all accesses to the queue must go through this IP so that all
+ *	accesses to the memory are controlled and ordered. This IP then
+ *	controls the entire state of the queue, and SW has no directly control,
+ *	such as through doorbells and cannot access the storage memory directly.
+ *	This is particularly useful when more than one SW or HW entity can be
+ *	the producer and/or consumer at the same time
+ * @K3_NAV_RINGACC_RING_MODE_CREDENTIALS: Credentials mode is message mode plus
+ *	stores credentials with each message, requiring the element size to be
+ *	doubled to fit the credentials. Any exposed memory should be protected
+ *	by a firewall from unwanted access
+ * @K3_NAV_RINGACC_RING_MODE_QM:  Queue manager mode. This takes the credentials
+ *	mode and adds packet length per element, along with additional read only
+ *	fields for element count and accumulated queue length. The QM mode only
+ *	operates with an 8 byte element size (any other element size is
+ *	illegal), and like in credentials mode each operation uses 2 element
+ *	slots to store the credentials and length fields
+ */
+enum k3_nav_ring_mode {
+	K3_NAV_RINGACC_RING_MODE_RING = 0,
+	K3_NAV_RINGACC_RING_MODE_MESSAGE,
+	K3_NAV_RINGACC_RING_MODE_CREDENTIALS,
+	K3_NAV_RINGACC_RING_MODE_QM,
+	k3_NAV_RINGACC_RING_MODE_INVALID
+};
+
+/**
+ * enum k3_nav_ring_size - &struct k3_nav_ring_cfg elm_size
+ *
+ * RA ring element's sizes in bytes.
+ */
+enum k3_nav_ring_size {
+	K3_NAV_RINGACC_RING_ELSIZE_4 = 0,
+	K3_NAV_RINGACC_RING_ELSIZE_8,
+	K3_NAV_RINGACC_RING_ELSIZE_16,
+	K3_NAV_RINGACC_RING_ELSIZE_32,
+	K3_NAV_RINGACC_RING_ELSIZE_64,
+	K3_NAV_RINGACC_RING_ELSIZE_128,
+	K3_NAV_RINGACC_RING_ELSIZE_256,
+	K3_NAV_RINGACC_RING_ELSIZE_INVALID
+};
+
+struct k3_nav_ringacc;
+struct k3_nav_ring;
+
+/**
+ * enum k3_nav_ring_cfg - RA ring configuration structure
+ *
+ * @size: Ring size, number of elements
+ * @elm_size: Ring element size
+ * @mode: Ring operational mode
+ * @flags: Ring configuration flags. Possible values:
+ *	 @K3_NAV_RINGACC_RING_SHARED: when set allows to request the same ring
+ *	 few times. It's usable when the same ring is used as Free Host PD ring
+ *	 for different flows, for example.
+ *	 Note: Locking should be done by consumer if required
+ */
+struct k3_nav_ring_cfg {
+	u32 size;
+	enum k3_nav_ring_size elm_size;
+	enum k3_nav_ring_mode mode;
+#define K3_NAV_RINGACC_RING_SHARED BIT(1)
+	u32 flags;
+};
+
+#define K3_NAV_RINGACC_RING_ID_ANY (-1)
+
+/**
+ * k3_nav_ringacc_request_ring - request ring from ringacc
+ * @ringacc: pointer on ringacc
+ * @id: ring id or K3_NAV_RINGACC_RING_ID_ANY for any general purpose ring
+ *
+ * Returns pointer on the Ring - struct k3_nav_ring
+ * or NULL in case of failure.
+ */
+struct k3_nav_ring *k3_nav_ringacc_request_ring(struct k3_nav_ringacc *ringacc,
+						int id);
+
+int k3_nav_ringacc_request_rings_pair(struct k3_nav_ringacc *ringacc,
+				      int fwd_id, int compl_id,
+				      struct k3_nav_ring **fwd_ring,
+				      struct k3_nav_ring **compl_ring);
+/**
+ * k3_nav_ringacc_get_dev - get pointer on RA device
+ * @ringacc: pointer on RA
+ *
+ * Returns device pointer
+ */
+struct device *k3_nav_ringacc_get_dev(struct k3_nav_ringacc *ringacc);
+
+/**
+ * k3_nav_ringacc_ring_reset - ring reset
+ * @ring: pointer on Ring
+ *
+ * Resets ring internal state ((hw)occ, (hw)idx).
+ * TODO_GS: ? Ring can be reused without reconfiguration
+ */
+void k3_nav_ringacc_ring_reset(struct k3_nav_ring *ring);
+/**
+ * k3_nav_ringacc_ring_reset - ring reset for DMA rings
+ * @ring: pointer on Ring
+ *
+ * Resets ring internal state ((hw)occ, (hw)idx). Should be used for rings
+ * which are read by K3 UDMA, like TX or Free Host PD rings.
+ */
+void k3_nav_ringacc_ring_reset_dma(struct k3_nav_ring *ring, u32 occ);
+
+/**
+ * k3_nav_ringacc_ring_free - ring free
+ * @ring: pointer on Ring
+ *
+ * Resets ring and free all alocated resources.
+ */
+int k3_nav_ringacc_ring_free(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_get_ring_id - Get the Ring ID
+ * @ring: pointer on ring
+ *
+ * Returns the Ring ID
+ */
+u32 k3_nav_ringacc_get_ring_id(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_ring_cfg - ring configure
+ * @ring: pointer on ring
+ * @cfg: Ring configuration parameters (see &struct k3_nav_ring_cfg)
+ *
+ * Configures ring, including ring memory allocation.
+ * Returns 0 on success, errno otherwise.
+ */
+int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring,
+			    struct k3_nav_ring_cfg *cfg);
+
+/**
+ * k3_nav_ringacc_ring_get_size - get ring size
+ * @ring: pointer on ring
+ *
+ * Returns ring size in number of elements.
+ */
+u32 k3_nav_ringacc_ring_get_size(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_ring_get_free - get free elements
+ * @ring: pointer on ring
+ *
+ * Returns number of free elements in the ring.
+ */
+u32 k3_nav_ringacc_ring_get_free(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_ring_get_occ - get ring occupancy
+ * @ring: pointer on ring
+ *
+ * Returns total number of valid entries on the ring
+ */
+u32 k3_nav_ringacc_ring_get_occ(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_ring_is_full - checks if ring is full
+ * @ring: pointer on ring
+ *
+ * Returns true if the ring is full
+ */
+u32 k3_nav_ringacc_ring_is_full(struct k3_nav_ring *ring);
+
+/**
+ * k3_nav_ringacc_ring_push - push element to the ring tail
+ * @ring: pointer on ring
+ * @elem: pointer on ring element buffer
+ *
+ * Push one ring element to the ring tail. Size of the ring element is
+ * determined by ring configuration &struct k3_nav_ring_cfg elm_size.
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int k3_nav_ringacc_ring_push(struct k3_nav_ring *ring, void *elem);
+
+/**
+ * k3_nav_ringacc_ring_pop - pop element from the ring head
+ * @ring: pointer on ring
+ * @elem: pointer on ring element buffer
+ *
+ * Push one ring element from the ring head. Size of the ring element is
+ * determined by ring configuration &struct k3_nav_ring_cfg elm_size..
+ *
+ * Returns 0 on success, errno otherwise.
+ */
+int k3_nav_ringacc_ring_pop(struct k3_nav_ring *ring, void *elem);
+
+/**
+ * k3_nav_ringacc_ring_push_head - push element to the ring head
+ * @ring: pointer on ring
+ * @elem: pointer on ring element buffer
+ *
+ * Push one ring element to the ring head. Size of the ring element is
+ * determined by ring configuration &struct k3_nav_ring_cfg elm_size.
+ *
+ * Returns 0 on success, errno otherwise.
+ * Not Supported by ring modes: K3_NAV_RINGACC_RING_MODE_RING
+ */
+int k3_nav_ringacc_ring_push_head(struct k3_nav_ring *ring, void *elem);
+
+/**
+ * k3_nav_ringacc_ring_pop_tail - pop element from the ring tail
+ * @ring: pointer on ring
+ * @elem: pointer on ring element buffer
+ *
+ * Push one ring element from the ring tail. Size of the ring element is
+ * determined by ring configuration &struct k3_nav_ring_cfg elm_size.
+ *
+ * Returns 0 on success, errno otherwise.
+ * Not Supported by ring modes: K3_NAV_RINGACC_RING_MODE_RING
+ */
+int k3_nav_ringacc_ring_pop_tail(struct k3_nav_ring *ring, void *elem);
+
+/* DMA ring support */
+struct ti_sci_handle;
+
+/**
+ * struct struct k3_ringacc_init_data - Initialization data for DMA rings
+ */
+struct k3_ringacc_init_data {
+	const struct ti_sci_handle *tisci;
+	u32 tisci_dev_id;
+	u32 num_rings;
+};
+
+struct k3_nav_ringacc *k3_ringacc_dmarings_init(struct device *dev,
+						struct k3_ringacc_init_data *data);
+
+struct k3_nav_ringacc *k3_navss_ringacc_get_by_phandle(struct device *dev, const char *property);
+
+#endif /* __SOC_TI_K3_NAVSS_RINGACC_API_H_ */

-- 
2.39.5




More information about the barebox mailing list