soc: ti: k3-navss-ringacc: Add AM64 ringacc support

AM64 dual mode rings are modeled as pair of Rings objects which has common
configuration and memory buffer, but separate real-time control register
sets for each direction mem2dev (forward) and dev2mem (reverse).

AM64 rings must be requested only using k3_ringacc_request_rings_pair(),
and forward ring must always be initialized/configured. After this any
other Ringacc APIs can be used without any callers changes.

Signed-off-by: Vignesh Raghavendra <vigneshr@ti.com>
This commit is contained in:
Vignesh Raghavendra 2021-05-10 20:06:03 +05:30 committed by Lokesh Vutla
parent 91f1e792fe
commit c409b4932d
2 changed files with 283 additions and 5 deletions

View File

@ -23,6 +23,7 @@
#include <linux/err.h>
#include <linux/soc/ti/k3-navss-ringacc.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/soc/ti/cppi5.h>
#define set_bit(bit, bitmap) __set_bit(bit, bitmap)
#define clear_bit(bit, bitmap) __clear_bit(bit, bitmap)
@ -56,6 +57,7 @@ static u32 ringacc_readl(void __iomem *reg)
}
#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
@ -71,6 +73,13 @@ struct k3_nav_ring_rt_regs {
};
#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
@ -173,6 +182,7 @@ struct k3_nav_ring {
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;
@ -200,6 +210,7 @@ struct k3_nav_ringacc_ops {
* @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 udevice *dev;
@ -220,8 +231,24 @@ struct k3_nav_ringacc {
u32 tisci_dev_id;
const struct k3_nav_ringacc_ops *ops;
bool dual_ring;
};
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 long k3_nav_ringacc_ring_get_fifo_pos(struct k3_nav_ring *ring)
{
return KNAV_RINGACC_FIFO_WINDOW_SIZE_BYTES -
@ -235,12 +262,23 @@ static void *k3_nav_ringacc_get_elm_addr(struct k3_nav_ring *ring, u32 idx)
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,
};
static int k3_nav_ringacc_ring_push_io(struct k3_nav_ring *ring, void *elem);
static int k3_nav_ringacc_ring_pop_io(struct k3_nav_ring *ring, void *elem);
static int k3_nav_ringacc_ring_push_head_io(struct k3_nav_ring *ring,
@ -328,6 +366,27 @@ 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,
@ -338,6 +397,10 @@ int k3_nav_ringacc_request_rings_pair(struct k3_nav_ringacc *ringacc,
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, 0);
if (!(*fwd_ring))
return -ENODEV;
@ -493,6 +556,13 @@ int k3_nav_ringacc_ring_free(struct k3_nav_ring *ring)
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))
@ -562,6 +632,76 @@ static int k3_nav_ringacc_ring_cfg_sci(struct k3_nav_ring *ring)
return ret;
}
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(ring->size * (4 << ring->elm_size),
(unsigned long *)&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->size * (4 << ring->elm_size),
ring->ring_mem_virt,
ring->ring_mem_dma);
err_free_ops:
ring->ops = NULL;
ring->proxy = NULL;
return ret;
}
int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring,
struct k3_nav_ring_cfg *cfg)
{
@ -570,6 +710,10 @@ int k3_nav_ringacc_ring_cfg(struct k3_nav_ring *ring,
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 ||
@ -839,6 +983,63 @@ static int k3_nav_ringacc_ring_pop_tail_io(struct k3_nav_ring *ring, void *elem)
ring, elem, K3_RINGACC_ACCESS_MODE_POP_HEAD);
}
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);
invalidate_dcache_range((unsigned long)ring->ring_mem_virt,
ALIGN((unsigned long)ring->ring_mem_virt +
ring->size * (4 << ring->elm_size),
ARCH_DMA_MINALIGN));
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) {
invalidate_dcache_range((unsigned long)ring->ring_mem_virt,
ALIGN((unsigned long)ring->ring_mem_virt +
ring->size * (4 << ring->elm_size),
ARCH_DMA_MINALIGN));
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_dbg(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;
@ -930,7 +1131,7 @@ int k3_nav_ringacc_ring_pop(struct k3_nav_ring *ring, void *elem)
return -EINVAL;
if (!ring->state.occ)
ring->state.occ = k3_nav_ringacc_ring_get_occ(ring);
k3_nav_ringacc_ring_update_occ(ring);
pr_debug("ring_pop%d: occ%d index%d\n",
ring->ring_id, ring->state.occ, ring->state.rindex);
@ -952,7 +1153,7 @@ int k3_nav_ringacc_ring_pop_tail(struct k3_nav_ring *ring, void *elem)
return -EINVAL;
if (!ring->state.occ)
ring->state.occ = k3_nav_ringacc_ring_get_occ(ring);
k3_nav_ringacc_ring_update_occ(ring);
pr_debug("ring_pop_tail: occ%d index%d\n",
ring->state.occ, ring->state.rindex);
@ -969,6 +1170,7 @@ int k3_nav_ringacc_ring_pop_tail(struct k3_nav_ring *ring, void *elem)
static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc)
{
struct udevice *dev = ringacc->dev;
struct udevice *devp = dev;
struct udevice *tisci_dev = NULL;
int ret;
@ -981,7 +1183,7 @@ static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc)
ringacc->dma_ring_reset_quirk =
dev_read_bool(dev, "ti,dma-ring-reset-quirk");
ret = uclass_get_device_by_phandle(UCLASS_FIRMWARE, dev,
ret = uclass_get_device_by_phandle(UCLASS_FIRMWARE, devp,
"ti,sci", &tisci_dev);
if (ret) {
pr_debug("TISCI RA RM get failed (%d)\n", ret);
@ -991,14 +1193,14 @@ static int k3_nav_ringacc_probe_dt(struct k3_nav_ringacc *ringacc)
ringacc->tisci = (struct ti_sci_handle *)
(ti_sci_get_handle_from_sysfw(tisci_dev));
ret = dev_read_u32_default(dev, "ti,sci", 0);
ret = dev_read_u32_default(devp, "ti,sci", 0);
if (!ret) {
dev_err(dev, "TISCI RA RM disabled\n");
ringacc->tisci = NULL;
return ret;
}
ret = dev_read_u32(dev, "ti,sci-dev-id", &ringacc->tisci_dev_id);
ret = dev_read_u32(devp, "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;
@ -1089,6 +1291,67 @@ static int k3_nav_ringacc_init(struct udevice *dev, struct k3_nav_ringacc *ringa
return 0;
}
struct k3_nav_ringacc *k3_ringacc_dmarings_init(struct udevice *dev,
struct k3_ringacc_init_data *data)
{
struct k3_nav_ringacc *ringacc;
void __iomem *base_rt;
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 = (uint32_t *)devfdt_get_addr_name(dev, "ringrt");
if (IS_ERR(base_rt))
return base_rt;
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->rt = base_rt + K3_DMARING_RING_RT_REGS_STEP * i;
ring->parent = ringacc;
ring->ring_id = i;
ring->proxy_id = K3_RINGACC_PROXY_NOT_USED;
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->proxy_id = K3_RINGACC_PROXY_NOT_USED;
ring->flags = K3_NAV_RING_FLAG_REVERSE;
}
ringacc->tisci_ring_ops = &ringacc->tisci->ops.rm_ring_ops;
dev_info(dev, "k3_dmaring Ring probed rings:%u, sci-dev-id:%u\n",
ringacc->num_rings,
ringacc->tisci_dev_id);
dev_info(dev, "dma-ring-reset-quirk: %s\n",
ringacc->dma_ring_reset_quirk ? "enabled" : "disabled");
return ringacc;
}
struct ringacc_match_data {
struct k3_nav_ringacc_ops ops;
};

View File

@ -238,4 +238,19 @@ int k3_nav_ringacc_ring_push_head(struct k3_nav_ring *ring, void *elem);
*/
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 udevice *dev,
struct k3_ringacc_init_data *data);
#endif /* __SOC_TI_K3_NAVSS_RINGACC_API_H_ */