Re: [PATCH 3/6] remoteproc/pru: Add support for PRU specific interrupt configuration

2020-11-19 Thread Grzegorz Jaszczyk
Hi Suman,

On Thu, 19 Nov 2020 at 00:04, Suman Anna  wrote:
>
> Hi Greg,
>
> On 11/18/20 9:27 AM, Grzegorz Jaszczyk wrote:
> > Hi Suman,
> >
> > On Tue, 17 Nov 2020 at 21:40, Suman Anna  wrote:
> >>
> >> Hi Greg,
> >>
> >> On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote:
> >>> The firmware blob can contain optional ELF sections: .resource_table
> >>> section and .pru_irq_map one. The second one contains the PRUSS
> >>> interrupt mapping description, which needs to be setup before powering
> >>> on the PRU core. To avoid RAM wastage this ELF section is not mapped to
> >>> any ELF segment (by the firmware linker) and therefore is not loaded to
> >>> PRU memory.
> >>>
> >>> The PRU interrupt configuration is handled within the PRUSS INTC irqchip
> >>> driver and leverages the system events to interrupt channels and host
> >>> interrupts mapping configuration. Relevant irq routing information is
> >>> passed through a special .pru_irq_map ELF section (for interrupts routed
> >>> to and used by PRU cores) or via the PRU application's device tree node
> >>> (for interrupts routed to and used by the main CPU). The mappings are
> >>> currently programmed during the booting/shutdown of the PRU.
> >>>
> >>> The interrupt configuration passed through .pru_irq_map ELF section is
> >>> optional. It varies on specific firmware functionality and therefore
> >>> have to be unwinded during PRU stop and performed again during
> >>> PRU start.
> >>>
> >>> Co-developed-by: Suman Anna 
> >>> Signed-off-by: Suman Anna 
> >>> Signed-off-by: Grzegorz Jaszczyk 
> >>> ---
> >>>  drivers/remoteproc/pru_rproc.c | 191 -
> >>>  drivers/remoteproc/pru_rproc.h |  46 
> >>>  2 files changed, 236 insertions(+), 1 deletion(-)
> >>>  create mode 100644 drivers/remoteproc/pru_rproc.h
> >>>
> >>> diff --git a/drivers/remoteproc/pru_rproc.c 
> >>> b/drivers/remoteproc/pru_rproc.c
> >>> index c94c8e965c21..825e9c7e081b 100644
> >>> --- a/drivers/remoteproc/pru_rproc.c
> >>> +++ b/drivers/remoteproc/pru_rproc.c
> >>> @@ -11,13 +11,16 @@
> >>>   */
> >>>
> >>>  #include 
> >>> +#include 
> >>>  #include 
> >>>  #include 
> >>> +#include 
> >>>  #include 
> >>>  #include 
> >>>
> >>>  #include "remoteproc_internal.h"
> >>>  #include "remoteproc_elf_helpers.h"
> >>> +#include "pru_rproc.h"
> >>>
> >>>  /* PRU_ICSS_PRU_CTRL registers */
> >>>  #define PRU_CTRL_CTRL0x
> >>> @@ -41,6 +44,8 @@
> >>>  #define PRU_SDRAM_DA 0x2000  /* Secondary Data RAM */
> >>>  #define PRU_SHRDRAM_DA   0x1 /* Shared Data RAM */
> >>>
> >>> +#define MAX_PRU_SYS_EVENTS 160
> >>> +
> >>>  /**
> >>>   * enum pru_iomem - PRU core memory/register range identifiers
> >>>   *
> >>> @@ -64,6 +69,10 @@ enum pru_iomem {
> >>>   * @rproc: remoteproc pointer for this PRU core
> >>>   * @mem_regions: data for each of the PRU memory regions
> >>>   * @fw_name: name of firmware image used during loading
> >>> + * @mapped_irq: virtual interrupt numbers of created fw specific mapping
> >>> + * @pru_interrupt_map: pointer to interrupt mapping description 
> >>> (firmware)
> >>> + * @pru_interrupt_map_sz: pru_interrupt_map size
> >>> + * @evt_count: number of mapped events
> >>>   */
> >>>  struct pru_rproc {
> >>>   int id;
> >>> @@ -72,6 +81,10 @@ struct pru_rproc {
> >>>   struct rproc *rproc;
> >>>   struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
> >>>   const char *fw_name;
> >>> + int *mapped_irq;
> >>> + struct pru_irq_rsc *pru_interrupt_map;
> >>> + size_t pru_interrupt_map_sz;
> >>> + ssize_t evt_count;
> >>
> >> Do you really need this to be ssize_t type?
> >
> > You are right, it is not needed. I will use size_t type instead and
> > modify relevant while loop.
>
> Hmm, size_t is ok, but perhaps the same type you used struct pru_irq_rsc is 
> better.

Ok.

>
> >
> >>
> >>>  };
> >>>
> >>>  static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned 
> >>> int reg)
> >>> @@ -85,15 +98,107 @@ void pru_control_write_reg(struct pru_rproc *pru, 
> >>> unsigned int reg, u32 val)
> >>>   writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
> >>>  }
> >>>
> >>> +static void pru_dispose_irq_mapping(struct pru_rproc *pru)
> >>> +{
> >>> + while (--pru->evt_count >= 0) {
> >>> + if (pru->mapped_irq[pru->evt_count] > 0)
> >>> + 
> >>> irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
> >>> + }
> >>> +
> >>> + kfree(pru->mapped_irq);
> >>> +}
> >>> +
> >>> +/*
> >>> + * Parse the custom PRU interrupt map resource and configure the INTC
> >>> + * appropriately.
> >>> + */
> >>> +static int pru_handle_intrmap(struct rproc *rproc)
> >>> +{
> >>> + struct device *dev = rproc->dev.parent;
> >>> + struct pru_rproc *pru = rproc->priv;
> >>> + struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
> >>> + struct irq_fwspec fwspec;
> >>> + struct device_node *irq_parent;
> >>> + int i, ret = 0;
> >>> +
> >>> + 

Re: [PATCH 3/6] remoteproc/pru: Add support for PRU specific interrupt configuration

2020-11-18 Thread Suman Anna
Hi Greg,

On 11/18/20 9:27 AM, Grzegorz Jaszczyk wrote:
> Hi Suman,
> 
> On Tue, 17 Nov 2020 at 21:40, Suman Anna  wrote:
>>
>> Hi Greg,
>>
>> On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote:
>>> The firmware blob can contain optional ELF sections: .resource_table
>>> section and .pru_irq_map one. The second one contains the PRUSS
>>> interrupt mapping description, which needs to be setup before powering
>>> on the PRU core. To avoid RAM wastage this ELF section is not mapped to
>>> any ELF segment (by the firmware linker) and therefore is not loaded to
>>> PRU memory.
>>>
>>> The PRU interrupt configuration is handled within the PRUSS INTC irqchip
>>> driver and leverages the system events to interrupt channels and host
>>> interrupts mapping configuration. Relevant irq routing information is
>>> passed through a special .pru_irq_map ELF section (for interrupts routed
>>> to and used by PRU cores) or via the PRU application's device tree node
>>> (for interrupts routed to and used by the main CPU). The mappings are
>>> currently programmed during the booting/shutdown of the PRU.
>>>
>>> The interrupt configuration passed through .pru_irq_map ELF section is
>>> optional. It varies on specific firmware functionality and therefore
>>> have to be unwinded during PRU stop and performed again during
>>> PRU start.
>>>
>>> Co-developed-by: Suman Anna 
>>> Signed-off-by: Suman Anna 
>>> Signed-off-by: Grzegorz Jaszczyk 
>>> ---
>>>  drivers/remoteproc/pru_rproc.c | 191 -
>>>  drivers/remoteproc/pru_rproc.h |  46 
>>>  2 files changed, 236 insertions(+), 1 deletion(-)
>>>  create mode 100644 drivers/remoteproc/pru_rproc.h
>>>
>>> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
>>> index c94c8e965c21..825e9c7e081b 100644
>>> --- a/drivers/remoteproc/pru_rproc.c
>>> +++ b/drivers/remoteproc/pru_rproc.c
>>> @@ -11,13 +11,16 @@
>>>   */
>>>
>>>  #include 
>>> +#include 
>>>  #include 
>>>  #include 
>>> +#include 
>>>  #include 
>>>  #include 
>>>
>>>  #include "remoteproc_internal.h"
>>>  #include "remoteproc_elf_helpers.h"
>>> +#include "pru_rproc.h"
>>>
>>>  /* PRU_ICSS_PRU_CTRL registers */
>>>  #define PRU_CTRL_CTRL0x
>>> @@ -41,6 +44,8 @@
>>>  #define PRU_SDRAM_DA 0x2000  /* Secondary Data RAM */
>>>  #define PRU_SHRDRAM_DA   0x1 /* Shared Data RAM */
>>>
>>> +#define MAX_PRU_SYS_EVENTS 160
>>> +
>>>  /**
>>>   * enum pru_iomem - PRU core memory/register range identifiers
>>>   *
>>> @@ -64,6 +69,10 @@ enum pru_iomem {
>>>   * @rproc: remoteproc pointer for this PRU core
>>>   * @mem_regions: data for each of the PRU memory regions
>>>   * @fw_name: name of firmware image used during loading
>>> + * @mapped_irq: virtual interrupt numbers of created fw specific mapping
>>> + * @pru_interrupt_map: pointer to interrupt mapping description (firmware)
>>> + * @pru_interrupt_map_sz: pru_interrupt_map size
>>> + * @evt_count: number of mapped events
>>>   */
>>>  struct pru_rproc {
>>>   int id;
>>> @@ -72,6 +81,10 @@ struct pru_rproc {
>>>   struct rproc *rproc;
>>>   struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
>>>   const char *fw_name;
>>> + int *mapped_irq;
>>> + struct pru_irq_rsc *pru_interrupt_map;
>>> + size_t pru_interrupt_map_sz;
>>> + ssize_t evt_count;
>>
>> Do you really need this to be ssize_t type?
> 
> You are right, it is not needed. I will use size_t type instead and
> modify relevant while loop.

Hmm, size_t is ok, but perhaps the same type you used struct pru_irq_rsc is 
better.

> 
>>
>>>  };
>>>
>>>  static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int 
>>> reg)
>>> @@ -85,15 +98,107 @@ void pru_control_write_reg(struct pru_rproc *pru, 
>>> unsigned int reg, u32 val)
>>>   writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
>>>  }
>>>
>>> +static void pru_dispose_irq_mapping(struct pru_rproc *pru)
>>> +{
>>> + while (--pru->evt_count >= 0) {
>>> + if (pru->mapped_irq[pru->evt_count] > 0)
>>> + irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
>>> + }
>>> +
>>> + kfree(pru->mapped_irq);
>>> +}
>>> +
>>> +/*
>>> + * Parse the custom PRU interrupt map resource and configure the INTC
>>> + * appropriately.
>>> + */
>>> +static int pru_handle_intrmap(struct rproc *rproc)
>>> +{
>>> + struct device *dev = rproc->dev.parent;
>>> + struct pru_rproc *pru = rproc->priv;
>>> + struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
>>> + struct irq_fwspec fwspec;
>>> + struct device_node *irq_parent;
>>> + int i, ret = 0;
>>> +
>>> + /* not having pru_interrupt_map is not an error */
>>> + if (!rsc)
>>> + return 0;
>>> +
>>> + /* currently supporting only type 0 */
>>> + if (rsc->type != 0) {
>>> + dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
>>> + return -EINVAL;
>>> + }
>>> +
>>> + if (rsc->num_evts < 0 

Re: [PATCH 3/6] remoteproc/pru: Add support for PRU specific interrupt configuration

2020-11-18 Thread Grzegorz Jaszczyk
Hi Suman,

On Tue, 17 Nov 2020 at 21:40, Suman Anna  wrote:
>
> Hi Greg,
>
> On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote:
> > The firmware blob can contain optional ELF sections: .resource_table
> > section and .pru_irq_map one. The second one contains the PRUSS
> > interrupt mapping description, which needs to be setup before powering
> > on the PRU core. To avoid RAM wastage this ELF section is not mapped to
> > any ELF segment (by the firmware linker) and therefore is not loaded to
> > PRU memory.
> >
> > The PRU interrupt configuration is handled within the PRUSS INTC irqchip
> > driver and leverages the system events to interrupt channels and host
> > interrupts mapping configuration. Relevant irq routing information is
> > passed through a special .pru_irq_map ELF section (for interrupts routed
> > to and used by PRU cores) or via the PRU application's device tree node
> > (for interrupts routed to and used by the main CPU). The mappings are
> > currently programmed during the booting/shutdown of the PRU.
> >
> > The interrupt configuration passed through .pru_irq_map ELF section is
> > optional. It varies on specific firmware functionality and therefore
> > have to be unwinded during PRU stop and performed again during
> > PRU start.
> >
> > Co-developed-by: Suman Anna 
> > Signed-off-by: Suman Anna 
> > Signed-off-by: Grzegorz Jaszczyk 
> > ---
> >  drivers/remoteproc/pru_rproc.c | 191 -
> >  drivers/remoteproc/pru_rproc.h |  46 
> >  2 files changed, 236 insertions(+), 1 deletion(-)
> >  create mode 100644 drivers/remoteproc/pru_rproc.h
> >
> > diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
> > index c94c8e965c21..825e9c7e081b 100644
> > --- a/drivers/remoteproc/pru_rproc.c
> > +++ b/drivers/remoteproc/pru_rproc.c
> > @@ -11,13 +11,16 @@
> >   */
> >
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> > +#include 
> >  #include 
> >  #include 
> >
> >  #include "remoteproc_internal.h"
> >  #include "remoteproc_elf_helpers.h"
> > +#include "pru_rproc.h"
> >
> >  /* PRU_ICSS_PRU_CTRL registers */
> >  #define PRU_CTRL_CTRL0x
> > @@ -41,6 +44,8 @@
> >  #define PRU_SDRAM_DA 0x2000  /* Secondary Data RAM */
> >  #define PRU_SHRDRAM_DA   0x1 /* Shared Data RAM */
> >
> > +#define MAX_PRU_SYS_EVENTS 160
> > +
> >  /**
> >   * enum pru_iomem - PRU core memory/register range identifiers
> >   *
> > @@ -64,6 +69,10 @@ enum pru_iomem {
> >   * @rproc: remoteproc pointer for this PRU core
> >   * @mem_regions: data for each of the PRU memory regions
> >   * @fw_name: name of firmware image used during loading
> > + * @mapped_irq: virtual interrupt numbers of created fw specific mapping
> > + * @pru_interrupt_map: pointer to interrupt mapping description (firmware)
> > + * @pru_interrupt_map_sz: pru_interrupt_map size
> > + * @evt_count: number of mapped events
> >   */
> >  struct pru_rproc {
> >   int id;
> > @@ -72,6 +81,10 @@ struct pru_rproc {
> >   struct rproc *rproc;
> >   struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
> >   const char *fw_name;
> > + int *mapped_irq;
> > + struct pru_irq_rsc *pru_interrupt_map;
> > + size_t pru_interrupt_map_sz;
> > + ssize_t evt_count;
>
> Do you really need this to be ssize_t type?

You are right, it is not needed. I will use size_t type instead and
modify relevant while loop.

>
> >  };
> >
> >  static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int 
> > reg)
> > @@ -85,15 +98,107 @@ void pru_control_write_reg(struct pru_rproc *pru, 
> > unsigned int reg, u32 val)
> >   writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
> >  }
> >
> > +static void pru_dispose_irq_mapping(struct pru_rproc *pru)
> > +{
> > + while (--pru->evt_count >= 0) {
> > + if (pru->mapped_irq[pru->evt_count] > 0)
> > + irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
> > + }
> > +
> > + kfree(pru->mapped_irq);
> > +}
> > +
> > +/*
> > + * Parse the custom PRU interrupt map resource and configure the INTC
> > + * appropriately.
> > + */
> > +static int pru_handle_intrmap(struct rproc *rproc)
> > +{
> > + struct device *dev = rproc->dev.parent;
> > + struct pru_rproc *pru = rproc->priv;
> > + struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
> > + struct irq_fwspec fwspec;
> > + struct device_node *irq_parent;
> > + int i, ret = 0;
> > +
> > + /* not having pru_interrupt_map is not an error */
> > + if (!rsc)
> > + return 0;
> > +
> > + /* currently supporting only type 0 */
> > + if (rsc->type != 0) {
> > + dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
> > + return -EINVAL;
> > + }
> > +
> > + if (rsc->num_evts < 0 || rsc->num_evts > MAX_PRU_SYS_EVENTS)
> > + return -EINVAL;
> > +
> > + if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) !=
> > +   

Re: [PATCH 3/6] remoteproc/pru: Add support for PRU specific interrupt configuration

2020-11-17 Thread Suman Anna
Hi Greg,

On 11/14/20 2:46 AM, Grzegorz Jaszczyk wrote:
> The firmware blob can contain optional ELF sections: .resource_table
> section and .pru_irq_map one. The second one contains the PRUSS
> interrupt mapping description, which needs to be setup before powering
> on the PRU core. To avoid RAM wastage this ELF section is not mapped to
> any ELF segment (by the firmware linker) and therefore is not loaded to
> PRU memory.
> 
> The PRU interrupt configuration is handled within the PRUSS INTC irqchip
> driver and leverages the system events to interrupt channels and host
> interrupts mapping configuration. Relevant irq routing information is
> passed through a special .pru_irq_map ELF section (for interrupts routed
> to and used by PRU cores) or via the PRU application's device tree node
> (for interrupts routed to and used by the main CPU). The mappings are
> currently programmed during the booting/shutdown of the PRU.
> 
> The interrupt configuration passed through .pru_irq_map ELF section is
> optional. It varies on specific firmware functionality and therefore
> have to be unwinded during PRU stop and performed again during
> PRU start.
> 
> Co-developed-by: Suman Anna 
> Signed-off-by: Suman Anna 
> Signed-off-by: Grzegorz Jaszczyk 
> ---
>  drivers/remoteproc/pru_rproc.c | 191 -
>  drivers/remoteproc/pru_rproc.h |  46 
>  2 files changed, 236 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/remoteproc/pru_rproc.h
> 
> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
> index c94c8e965c21..825e9c7e081b 100644
> --- a/drivers/remoteproc/pru_rproc.c
> +++ b/drivers/remoteproc/pru_rproc.c
> @@ -11,13 +11,16 @@
>   */
>  
>  #include 
> +#include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  
>  #include "remoteproc_internal.h"
>  #include "remoteproc_elf_helpers.h"
> +#include "pru_rproc.h"
>  
>  /* PRU_ICSS_PRU_CTRL registers */
>  #define PRU_CTRL_CTRL0x
> @@ -41,6 +44,8 @@
>  #define PRU_SDRAM_DA 0x2000  /* Secondary Data RAM */
>  #define PRU_SHRDRAM_DA   0x1 /* Shared Data RAM */
>  
> +#define MAX_PRU_SYS_EVENTS 160
> +
>  /**
>   * enum pru_iomem - PRU core memory/register range identifiers
>   *
> @@ -64,6 +69,10 @@ enum pru_iomem {
>   * @rproc: remoteproc pointer for this PRU core
>   * @mem_regions: data for each of the PRU memory regions
>   * @fw_name: name of firmware image used during loading
> + * @mapped_irq: virtual interrupt numbers of created fw specific mapping
> + * @pru_interrupt_map: pointer to interrupt mapping description (firmware)
> + * @pru_interrupt_map_sz: pru_interrupt_map size
> + * @evt_count: number of mapped events
>   */
>  struct pru_rproc {
>   int id;
> @@ -72,6 +81,10 @@ struct pru_rproc {
>   struct rproc *rproc;
>   struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
>   const char *fw_name;
> + int *mapped_irq;
> + struct pru_irq_rsc *pru_interrupt_map;
> + size_t pru_interrupt_map_sz;
> + ssize_t evt_count;

Do you really need this to be ssize_t type?

>  };
>  
>  static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int 
> reg)
> @@ -85,15 +98,107 @@ void pru_control_write_reg(struct pru_rproc *pru, 
> unsigned int reg, u32 val)
>   writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
>  }
>  
> +static void pru_dispose_irq_mapping(struct pru_rproc *pru)
> +{
> + while (--pru->evt_count >= 0) {
> + if (pru->mapped_irq[pru->evt_count] > 0)
> + irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
> + }
> +
> + kfree(pru->mapped_irq);
> +}
> +
> +/*
> + * Parse the custom PRU interrupt map resource and configure the INTC
> + * appropriately.
> + */
> +static int pru_handle_intrmap(struct rproc *rproc)
> +{
> + struct device *dev = rproc->dev.parent;
> + struct pru_rproc *pru = rproc->priv;
> + struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
> + struct irq_fwspec fwspec;
> + struct device_node *irq_parent;
> + int i, ret = 0;
> +
> + /* not having pru_interrupt_map is not an error */
> + if (!rsc)
> + return 0;
> +
> + /* currently supporting only type 0 */
> + if (rsc->type != 0) {
> + dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
> + return -EINVAL;
> + }
> +
> + if (rsc->num_evts < 0 || rsc->num_evts > MAX_PRU_SYS_EVENTS)
> + return -EINVAL;
> +
> + if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) !=
> + pru->pru_interrupt_map_sz)
> + return -EINVAL;
> +
> + pru->evt_count = rsc->num_evts;
> + pru->mapped_irq = kcalloc(pru->evt_count, sizeof(int), GFP_KERNEL);
> + if (!pru->mapped_irq)
> + return -ENOMEM;
> +
> + /*
> +  * parse and fill in system event to interrupt channel and
> +  * channel-to-host mapping
> +  */
> + irq_parent = 

[PATCH 3/6] remoteproc/pru: Add support for PRU specific interrupt configuration

2020-11-14 Thread Grzegorz Jaszczyk
The firmware blob can contain optional ELF sections: .resource_table
section and .pru_irq_map one. The second one contains the PRUSS
interrupt mapping description, which needs to be setup before powering
on the PRU core. To avoid RAM wastage this ELF section is not mapped to
any ELF segment (by the firmware linker) and therefore is not loaded to
PRU memory.

The PRU interrupt configuration is handled within the PRUSS INTC irqchip
driver and leverages the system events to interrupt channels and host
interrupts mapping configuration. Relevant irq routing information is
passed through a special .pru_irq_map ELF section (for interrupts routed
to and used by PRU cores) or via the PRU application's device tree node
(for interrupts routed to and used by the main CPU). The mappings are
currently programmed during the booting/shutdown of the PRU.

The interrupt configuration passed through .pru_irq_map ELF section is
optional. It varies on specific firmware functionality and therefore
have to be unwinded during PRU stop and performed again during
PRU start.

Co-developed-by: Suman Anna 
Signed-off-by: Suman Anna 
Signed-off-by: Grzegorz Jaszczyk 
---
 drivers/remoteproc/pru_rproc.c | 191 -
 drivers/remoteproc/pru_rproc.h |  46 
 2 files changed, 236 insertions(+), 1 deletion(-)
 create mode 100644 drivers/remoteproc/pru_rproc.h

diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
index c94c8e965c21..825e9c7e081b 100644
--- a/drivers/remoteproc/pru_rproc.c
+++ b/drivers/remoteproc/pru_rproc.c
@@ -11,13 +11,16 @@
  */
 
 #include 
+#include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #include "remoteproc_internal.h"
 #include "remoteproc_elf_helpers.h"
+#include "pru_rproc.h"
 
 /* PRU_ICSS_PRU_CTRL registers */
 #define PRU_CTRL_CTRL  0x
@@ -41,6 +44,8 @@
 #define PRU_SDRAM_DA   0x2000  /* Secondary Data RAM */
 #define PRU_SHRDRAM_DA 0x1 /* Shared Data RAM */
 
+#define MAX_PRU_SYS_EVENTS 160
+
 /**
  * enum pru_iomem - PRU core memory/register range identifiers
  *
@@ -64,6 +69,10 @@ enum pru_iomem {
  * @rproc: remoteproc pointer for this PRU core
  * @mem_regions: data for each of the PRU memory regions
  * @fw_name: name of firmware image used during loading
+ * @mapped_irq: virtual interrupt numbers of created fw specific mapping
+ * @pru_interrupt_map: pointer to interrupt mapping description (firmware)
+ * @pru_interrupt_map_sz: pru_interrupt_map size
+ * @evt_count: number of mapped events
  */
 struct pru_rproc {
int id;
@@ -72,6 +81,10 @@ struct pru_rproc {
struct rproc *rproc;
struct pruss_mem_region mem_regions[PRU_IOMEM_MAX];
const char *fw_name;
+   int *mapped_irq;
+   struct pru_irq_rsc *pru_interrupt_map;
+   size_t pru_interrupt_map_sz;
+   ssize_t evt_count;
 };
 
 static inline u32 pru_control_read_reg(struct pru_rproc *pru, unsigned int reg)
@@ -85,15 +98,107 @@ void pru_control_write_reg(struct pru_rproc *pru, unsigned 
int reg, u32 val)
writel_relaxed(val, pru->mem_regions[PRU_IOMEM_CTRL].va + reg);
 }
 
+static void pru_dispose_irq_mapping(struct pru_rproc *pru)
+{
+   while (--pru->evt_count >= 0) {
+   if (pru->mapped_irq[pru->evt_count] > 0)
+   irq_dispose_mapping(pru->mapped_irq[pru->evt_count]);
+   }
+
+   kfree(pru->mapped_irq);
+}
+
+/*
+ * Parse the custom PRU interrupt map resource and configure the INTC
+ * appropriately.
+ */
+static int pru_handle_intrmap(struct rproc *rproc)
+{
+   struct device *dev = rproc->dev.parent;
+   struct pru_rproc *pru = rproc->priv;
+   struct pru_irq_rsc *rsc = pru->pru_interrupt_map;
+   struct irq_fwspec fwspec;
+   struct device_node *irq_parent;
+   int i, ret = 0;
+
+   /* not having pru_interrupt_map is not an error */
+   if (!rsc)
+   return 0;
+
+   /* currently supporting only type 0 */
+   if (rsc->type != 0) {
+   dev_err(dev, "unsupported rsc type: %d\n", rsc->type);
+   return -EINVAL;
+   }
+
+   if (rsc->num_evts < 0 || rsc->num_evts > MAX_PRU_SYS_EVENTS)
+   return -EINVAL;
+
+   if (sizeof(*rsc) + rsc->num_evts * sizeof(struct pruss_int_map) !=
+   pru->pru_interrupt_map_sz)
+   return -EINVAL;
+
+   pru->evt_count = rsc->num_evts;
+   pru->mapped_irq = kcalloc(pru->evt_count, sizeof(int), GFP_KERNEL);
+   if (!pru->mapped_irq)
+   return -ENOMEM;
+
+   /*
+* parse and fill in system event to interrupt channel and
+* channel-to-host mapping
+*/
+   irq_parent = of_irq_find_parent(pru->dev->of_node);
+   if (!irq_parent) {
+   kfree(pru->mapped_irq);
+   return -ENODEV;
+   }
+
+   fwspec.fwnode = of_node_to_fwnode(irq_parent);
+   fwspec.param_count = 3;
+   for (i = 0; i < pru->evt_count; i++) {
+