diff mbox series

[15/16] remoteproc/pru: add support for parsing pru interrupt mapping from DT

Message ID 1543218769-5507-16-git-send-email-rogerq@ti.com (mailing list archive)
State New, archived
Headers show
Series remoteproc: Add support for TI PRU | expand

Commit Message

Roger Quadros Nov. 26, 2018, 7:52 a.m. UTC
From: Tero Kristo <t-kristo@ti.com>

PRU interrupt mapping can now be parsed from devicetree also, from
ti,pru-interrupt-map property. This is an alternative configuration
method in addition to the legacy resource table config. If both are
provided, the config in DT takes precedence.

Signed-off-by: Tero Kristo <t-kristo@ti.com>
[s-anna@ti.com: various fixes and cleanups]
Signed-off-by: Suman Anna <s-anna@ti.com>
Signed-off-by: Roger Quadros <rogerq@ti.com>
---
 drivers/remoteproc/pru_rproc.c | 109 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 106 insertions(+), 3 deletions(-)
diff mbox series

Patch

diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index 84f006b..540cce3 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -63,6 +63,7 @@  enum pru_mem {
  * @irq_ring: IRQ number to use for processing vring buffers
  * @irq_kick: IRQ number to use to perform virtio kick
  * @mem_regions: data for each of the PRU memory regions
+ * @intc_config: PRU INTC configuration data
  * @dram0: PRUSS DRAM0 region
  * @dram1: PRUSS DRAM1 region
  * @shrdram: PRUSS SHARED RAM region
@@ -73,6 +74,7 @@  enum pru_mem {
  * @shrdram_da: device address of shared Data RAM
  * @fw_name: name of firmware image used during loading
  * @gpmux_save: saved value for gpmux config
+ * @dt_irqs: number of irqs configured from DT
  * @lock: mutex to protect client usage
  * @dbg_single_step: debug state variable to set PRU into single step mode
  * @dbg_continuous: debug state variable to restore PRU execution mode
@@ -87,6 +89,7 @@  struct pru_rproc {
 	int irq_vring;
 	int irq_kick;
 	struct pruss_mem_region mem_regions[PRU_MEM_MAX];
+	struct pruss_intc_config intc_config;
 	struct pruss_mem_region dram0;
 	struct pruss_mem_region dram1;
 	struct pruss_mem_region shrdram;
@@ -97,6 +100,7 @@  struct pru_rproc {
 	u32 shrdram_da;
 	const char *fw_name;
 	u8 gpmux_save;
+	int dt_irqs;
 	struct mutex lock; /* client access lock */
 	u32 dbg_single_step;
 	u32 dbg_continuous;
@@ -180,6 +184,87 @@  static struct rproc *__pru_rproc_get(struct device_node *np, int index)
 	return rproc;
 }
 
+static int pru_get_intc_dt_config(struct device *dev, const char *propname,
+				  int index,
+				  struct pruss_intc_config *intc_config)
+{
+	struct device_node *np = dev->of_node;
+	struct property *prop;
+	int ret = 0, entries, i;
+	int dt_irqs = 0;
+	u32 *arr;
+	int max_system_events, max_pru_channels, max_pru_host_ints;
+
+	max_system_events = MAX_PRU_SYS_EVENTS;
+	max_pru_channels = MAX_PRU_CHANNELS;
+	max_pru_host_ints = MAX_PRU_CHANNELS;
+
+	prop = of_find_property(np, propname, NULL);
+	if (!prop)
+		return 0;
+
+	entries = of_property_count_u32_elems(np, propname);
+	if (entries <= 0 || entries % 4)
+		return -EINVAL;
+
+	arr = kmalloc_array(entries, sizeof(u32), GFP_KERNEL);
+	if (!arr)
+		return -ENOMEM;
+
+	ret = of_property_read_u32_array(np, propname, arr, entries);
+	if (ret)
+		return -EINVAL;
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->sysev_to_ch); i++)
+		intc_config->sysev_to_ch[i] = -1;
+
+	for (i = 0; i < ARRAY_SIZE(intc_config->ch_to_host); i++)
+		intc_config->ch_to_host[i] = -1;
+
+	for (i = 0; i < entries; i += 4) {
+		if (arr[i] != index)
+			continue;
+
+		if (arr[i + 1] < 0 ||
+		    arr[i + 1] >= max_system_events) {
+			dev_dbg(dev, "bad sys event %d\n", arr[i + 1]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 2] < 0 ||
+		    arr[i + 2] >= max_pru_channels) {
+			dev_dbg(dev, "bad channel %d\n", arr[i + 2]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (arr[i + 3] < 0 ||
+		    arr[i + 3] >= max_pru_host_ints) {
+			dev_dbg(dev, "bad irq %d\n", arr[i + 3]);
+			ret = -EINVAL;
+			goto err;
+		}
+
+		intc_config->sysev_to_ch[arr[i + 1]] = arr[i + 2];
+		dev_dbg(dev, "sysevt-to-ch[%d] -> %d\n", arr[i + 1],
+			arr[i + 2]);
+
+		intc_config->ch_to_host[arr[i + 2]] = arr[i + 3];
+		dev_dbg(dev, "chnl-to-host[%d] -> %d\n", arr[i + 2],
+			arr[i + 3]);
+
+		dt_irqs++;
+	}
+
+	kfree(arr);
+	return dt_irqs;
+
+err:
+	kfree(arr);
+	return ret;
+}
+
 /**
  * pru_rproc_get() - get the PRU rproc instance from a device node
  * @np: the user/client device node
@@ -251,6 +336,15 @@  struct rproc *pru_rproc_get(struct device_node *np, int index)
 		}
 	}
 
+	ret = pru_get_intc_dt_config(dev, "ti,pru-interrupt-map",
+				     index, &pru->intc_config);
+	if (ret < 0) {
+		dev_err(dev, "error getting DT interrupt map: %d\n", ret);
+		goto err;
+	}
+
+	pru->dt_irqs = ret;
+
 	return rproc;
 
 err:
@@ -568,7 +662,13 @@  static int pru_rproc_start(struct rproc *rproc)
 	dev_dbg(dev, "starting PRU%d: entry-point = 0x%x\n",
 		pru->id, (rproc->bootaddr >> 2));
 
-	/* TODO: INTC setup */
+	if (pru->dt_irqs) {
+		ret = pruss_intc_configure(pru->pruss, &pru->intc_config);
+		if (ret) {
+			dev_err(dev, "failed to configure intc %d\n", ret);
+			return ret;
+		}
+	}
 
 	if (!list_empty(&pru->rproc->rvdevs)) {
 		if (!pru->mbox && (pru->irq_vring <= 0 || pru->irq_kick <= 0)) {
@@ -596,7 +696,8 @@  static int pru_rproc_start(struct rproc *rproc)
 	return 0;
 
 fail:
-	/* TODO: INTC cleanup */
+	if (pru->dt_irqs)
+		pruss_intc_unconfigure(pru->pruss, &pru->intc_config);
 
 	return ret;
 }
@@ -618,7 +719,9 @@  static int pru_rproc_stop(struct rproc *rproc)
 	    !pru->mbox && pru->irq_vring > 0)
 		free_irq(pru->irq_vring, pru);
 
-	/* TODO: INTC cleanup */
+	/* undo INTC config */
+	if (pru->dt_irqs)
+		pruss_intc_unconfigure(pru->pruss, &pru->intc_config);
 
 	return 0;
 }