]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
soc: ti: k3-navss-ringacc: Add AM64 ringacc support
authorVignesh Raghavendra <vigneshr@ti.com>
Mon, 10 May 2021 14:36:03 +0000 (20:06 +0530)
committerLokesh Vutla <lokeshvutla@ti.com>
Wed, 12 May 2021 11:06:38 +0000 (16:36 +0530)
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>
drivers/soc/ti/k3-navss-ringacc.c
include/linux/soc/ti/k3-navss-ringacc.h

index c5099ad084d59c093cf51ea2aa48674f9251cf29..10ef6be7205e31e3b4572cfbd65f7d42f987b811 100644 (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;
 };
index 9176277ff0bcc8cb98dc969ad67c7f65439ab83b..1e9b7d912584e7a948a699527bcef6ccbacef549 100644 (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_ */