From: Tero Kristo <t-kristo@xxxxxx> 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@xxxxxx> [s-anna@xxxxxx: various fixes and cleanups] Signed-off-by: Suman Anna <s-anna@xxxxxx> Signed-off-by: Roger Quadros <rogerq@xxxxxx> --- drivers/remoteproc/pru_rproc.c | 109 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 106 insertions(+), 3 deletions(-) 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; } -- Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki