From c409b4932dba6403a706f9453d627abfb5d93e20 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Mon, 10 May 2021 20:06:03 +0530 Subject: [PATCH] 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 --- drivers/soc/ti/k3-navss-ringacc.c | 273 +++++++++++++++++++++++- include/linux/soc/ti/k3-navss-ringacc.h | 15 ++ 2 files changed, 283 insertions(+), 5 deletions(-) diff --git a/drivers/soc/ti/k3-navss-ringacc.c b/drivers/soc/ti/k3-navss-ringacc.c index c5099ad084..10ef6be720 100644 --- a/drivers/soc/ti/k3-navss-ringacc.c +++ b/drivers/soc/ti/k3-navss-ringacc.c @@ -23,6 +23,7 @@ #include #include #include +#include #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; }; diff --git a/include/linux/soc/ti/k3-navss-ringacc.h b/include/linux/soc/ti/k3-navss-ringacc.h index 9176277ff0..1e9b7d9125 100644 --- a/include/linux/soc/ti/k3-navss-ringacc.h +++ b/include/linux/soc/ti/k3-navss-ringacc.h @@ -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_ */