mbox series

[v5,0/5] Introduce PRU platform consumer API

Message ID 20230323062451.2925996-1-danishanwar@ti.com
Headers show
Series Introduce PRU platform consumer API | expand

Message

MD Danish Anwar March 23, 2023, 6:24 a.m. UTC
Hi All,
The Programmable Real-Time Unit and Industrial Communication Subsystem (PRU-ICSS
or simply PRUSS) on various TI SoCs consists of dual 32-bit RISC cores
(Programmable Real-Time Units, or PRUs) for program execution.

There are 3 foundation components for TI PRUSS subsystem: the PRUSS platform
driver, the PRUSS INTC driver and the PRUSS remoteproc driver. All of them have
already been merged and can be found under:
1) drivers/soc/ti/pruss.c
   Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
2) drivers/irqchip/irq-pruss-intc.c
   Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
3) drivers/remoteproc/pru_rproc.c
   Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml

The programmable nature of the PRUs provide flexibility to implement custom
peripheral interfaces, fast real-time responses, or specialized data handling.
Example of a PRU consumer drivers will be: 
  - Software UART over PRUSS
  - PRU-ICSS Ethernet EMAC

In order to make usage of common PRU resources and allow the consumer drivers 
to configure the PRU hardware for specific usage the PRU API is introduced.

This is the v5 of the old patch series[1]. This doesn't have any functional 
changes, the old series has been rebased on linux-next.

Changes from v4 [1] to v5:
*) Addressed Roger's comment to change function argument in API 
pruss_cfg_xfr_enable(). Instead of asking user to calcualte mask, now user
will just provide the pru_type and mask will be calcualted inside the API.
*) Moved enum pru_type from pru_rproc.c to include/linux/remoteproc/pruss.h
in patch 4 / 5.
*) Moved enum pruss_gpi_mode from patch 3/5 to patch 4/5 to introduce this
enum in same patch as the API using it.
*) Moved enum pruss_gp_mux_sel from patch 3/5 to patch 5/5 to introduce this
enum in same patch as the API using it.
*) Created new headefile drivers/soc/ti/pruss.h, private to PRUSS as asked by
Roger. Moved all private definitions and pruss_cfg_read () / update ()
APIs to this newly added headerfile.
*) Renamed include/linux/pruss_driver.h to include/linux/pruss_internal.h as
suggested by Andrew and Roger.

Changes from v3 [2] to v4:
*) Added my SoB tags in all patches as earlier SoB tags were missing in few
patches.
*) Added Roger's RB tags in 3 patches.
*) Addressed Roger's comment in patch 4/5 of this series. Added check for 
   invalid GPI mode in pruss_cfg_gpimode() API.
*) Removed patch [5] from this series as that patch is no longer required.
*) Made pruss_cfg_read() and pruss_cfg_update() APIs internal to pruss.c by
   removing EXPORT_SYMBOL_GPL and making them static. Now these APIs are 
   internal to pruss.c and PRUSS CFG space is not exposed.
*) Moved APIs pruss_cfg_gpimode(), pruss_cfg_miirt_enable(), 
   pruss_cfg_xfr_enable(), pruss_cfg_get_gpmux(), pruss_cfg_set_gpmux() to
   pruss.c file as they are using APIs pruss_cfg_read / update. 
   Defined these APIs in pruss.h file as other drivers use these APIs to 
   perform respective operations.

Changes from v2 to v3:
*) No functional changes, the old series has been rebased on linux-next (tag:
next-20230306).

This series depends on another series which is already merged in the remoteproc
tree [3] and is part of v6.3-rc1. This series and the remoteproc series form 
the PRUSS consumer API which can be used by consumer drivers to utilize the 
PRUs.

One example of the consumer driver is the PRU-ICSSG ethernet driver [4],which 
depends on this series and the remoteproc series [3].

[1] https://lore.kernel.org/all/20230313111127.1229187-1-danishanwar@ti.com/
[2] https://lore.kernel.org/all/20230306110934.2736465-1-danishanwar@ti.com/
[3] https://lore.kernel.org/all/20230106121046.886863-1-danishanwar@ti.com/#t
[4] https://lore.kernel.org/all/20230210114957.2667963-1-danishanwar@ti.com/
[5] https://lore.kernel.org/all/20230306110934.2736465-6-danishanwar@ti.com/

Thanks and Regards,
Md Danish Anwar

Andrew F. Davis (1):
  soc: ti: pruss: Add pruss_{request,release}_mem_region() API

Suman Anna (2):
  soc: ti: pruss: Add pruss_cfg_read()/update() API
  soc: ti: pruss: Add helper functions to set GPI mode, MII_RT_event and
    XFR

Tero Kristo (2):
  soc: ti: pruss: Add pruss_get()/put() API
  soc: ti: pruss: Add helper functions to get/set PRUSS_CFG_GPMUX

 drivers/remoteproc/pru_rproc.c                |  17 +-
 drivers/soc/ti/pruss.c                        | 256 +++++++++++++++++-
 drivers/soc/ti/pruss.h                        | 112 ++++++++
 .../{pruss_driver.h => pruss_internal.h}      |  34 +--
 include/linux/remoteproc/pruss.h              | 139 ++++++++++
 5 files changed, 516 insertions(+), 42 deletions(-)
 create mode 100644 drivers/soc/ti/pruss.h
 rename include/linux/{pruss_driver.h => pruss_internal.h} (58%)

Comments

Anwar, Md Danish March 24, 2023, 7:13 a.m. UTC | #1
Hi Mathieu,

On 23/03/23 11:54, MD Danish Anwar wrote:
> Hi All,
> The Programmable Real-Time Unit and Industrial Communication Subsystem (PRU-ICSS
> or simply PRUSS) on various TI SoCs consists of dual 32-bit RISC cores
> (Programmable Real-Time Units, or PRUs) for program execution.
> 
> There are 3 foundation components for TI PRUSS subsystem: the PRUSS platform
> driver, the PRUSS INTC driver and the PRUSS remoteproc driver. All of them have
> already been merged and can be found under:
> 1) drivers/soc/ti/pruss.c
>    Documentation/devicetree/bindings/soc/ti/ti,pruss.yaml
> 2) drivers/irqchip/irq-pruss-intc.c
>    Documentation/devicetree/bindings/interrupt-controller/ti,pruss-intc.yaml
> 3) drivers/remoteproc/pru_rproc.c
>    Documentation/devicetree/bindings/remoteproc/ti,pru-consumer.yaml
> 
> The programmable nature of the PRUs provide flexibility to implement custom
> peripheral interfaces, fast real-time responses, or specialized data handling.
> Example of a PRU consumer drivers will be: 
>   - Software UART over PRUSS
>   - PRU-ICSS Ethernet EMAC
> 
> In order to make usage of common PRU resources and allow the consumer drivers 
> to configure the PRU hardware for specific usage the PRU API is introduced.
>
Roger has given his RBs for all the patches in this series. Tony has also given
his RB.

Can you please have a look at this series.
Mathieu Poirier March 27, 2023, 8:58 p.m. UTC | #2
Hi Danish

On Thu, Mar 23, 2023 at 11:54:47AM +0530, MD Danish Anwar wrote:
> From: Tero Kristo <t-kristo@ti.com>
> 
> Add two new get and put API, pruss_get() and pruss_put() to the
> PRUSS platform driver to allow client drivers to request a handle
> to a PRUSS device. This handle will be used by client drivers to
> request various operations of the PRUSS platform driver through
> additional API that will be added in the following patches.
> 
> The pruss_get() function returns the pruss handle corresponding
> to a PRUSS device referenced by a PRU remoteproc instance. The
> pruss_put() is the complimentary function to pruss_get().
> 
> Co-developed-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> Co-developed-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
> Signed-off-by: Puranjay Mohan <p-mohan@ti.com>
> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
> Reviewed-by: Roger Quadros <rogerq@kernel.org>
> ---
>  drivers/remoteproc/pru_rproc.c                |  2 +-
>  drivers/soc/ti/pruss.c                        | 60 ++++++++++++++++++-
>  .../{pruss_driver.h => pruss_internal.h}      |  7 ++-
>  include/linux/remoteproc/pruss.h              | 19 ++++++
>  4 files changed, 83 insertions(+), 5 deletions(-)
>  rename include/linux/{pruss_driver.h => pruss_internal.h} (90%)
> 
> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
> index b76db7fa693d..4ddd5854d56e 100644
> --- a/drivers/remoteproc/pru_rproc.c
> +++ b/drivers/remoteproc/pru_rproc.c
> @@ -19,7 +19,7 @@
>  #include <linux/of_device.h>
>  #include <linux/of_irq.h>
>  #include <linux/remoteproc/pruss.h>
> -#include <linux/pruss_driver.h>
> +#include <linux/pruss_internal.h>
>  #include <linux/remoteproc.h>
>  
>  #include "remoteproc_internal.h"
> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
> index 6882c86b3ce5..6c2bb02a521d 100644
> --- a/drivers/soc/ti/pruss.c
> +++ b/drivers/soc/ti/pruss.c
> @@ -6,6 +6,7 @@
>   * Author(s):
>   *	Suman Anna <s-anna@ti.com>
>   *	Andrew F. Davis <afd@ti.com>
> + *	Tero Kristo <t-kristo@ti.com>
>   */
>  
>  #include <linux/clk-provider.h>
> @@ -16,8 +17,9 @@
>  #include <linux/of_address.h>
>  #include <linux/of_device.h>
>  #include <linux/pm_runtime.h>
> -#include <linux/pruss_driver.h>
> +#include <linux/pruss_internal.h>
>  #include <linux/regmap.h>
> +#include <linux/remoteproc.h>
>  #include <linux/slab.h>
>  
>  /**
> @@ -30,6 +32,62 @@ struct pruss_private_data {
>  	bool has_core_mux_clock;
>  };
>  
> +/**
> + * pruss_get() - get the pruss for a given PRU remoteproc
> + * @rproc: remoteproc handle of a PRU instance
> + *
> + * Finds the parent pruss device for a PRU given the @rproc handle of the
> + * PRU remote processor. This function increments the pruss device's refcount,
> + * so always use pruss_put() to decrement it back once pruss isn't needed
> + * anymore.
> + *
> + * Return: pruss handle on success, and an ERR_PTR on failure using one
> + * of the following error values
> + *    -EINVAL if invalid parameter
> + *    -ENODEV if PRU device or PRUSS device is not found
> + */
> +struct pruss *pruss_get(struct rproc *rproc)
> +{
> +	struct pruss *pruss;
> +	struct device *dev;
> +	struct platform_device *ppdev;
> +
> +	if (IS_ERR_OR_NULL(rproc))
> +		return ERR_PTR(-EINVAL);
> +

There is no guarantee that @rproc is valid without calling rproc_get_by_handle()
or pru_rproc_get().

> +	dev = &rproc->dev;
> +
> +	/* make sure it is PRU rproc */
> +	if (!dev->parent || !is_pru_rproc(dev->parent))
> +		return ERR_PTR(-ENODEV);
> +
> +	ppdev = to_platform_device(dev->parent->parent);
> +	pruss = platform_get_drvdata(ppdev);
> +	if (!pruss)
> +		return ERR_PTR(-ENODEV);
> +
> +	get_device(pruss->dev);
> +
> +	return pruss;
> +}
> +EXPORT_SYMBOL_GPL(pruss_get);
> +
> +/**
> + * pruss_put() - decrement pruss device's usecount
> + * @pruss: pruss handle
> + *
> + * Complimentary function for pruss_get(). Needs to be called
> + * after the PRUSS is used, and only if the pruss_get() succeeds.
> + */
> +void pruss_put(struct pruss *pruss)
> +{
> +	if (IS_ERR_OR_NULL(pruss))
> +		return;
> +
> +	put_device(pruss->dev);
> +}
> +EXPORT_SYMBOL_GPL(pruss_put);
> +
>  static void pruss_of_free_clk_provider(void *data)
>  {
>  	struct device_node *clk_mux_np = data;
> diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_internal.h
> similarity index 90%
> rename from include/linux/pruss_driver.h
> rename to include/linux/pruss_internal.h
> index ecfded30ed05..8f91cb164054 100644
> --- a/include/linux/pruss_driver.h
> +++ b/include/linux/pruss_internal.h
> @@ -6,9 +6,10 @@
>   *	Suman Anna <s-anna@ti.com>
>   */
>  
> -#ifndef _PRUSS_DRIVER_H_
> -#define _PRUSS_DRIVER_H_
> +#ifndef _PRUSS_INTERNAL_H_
> +#define _PRUSS_INTERNAL_H_
>  
> +#include <linux/remoteproc/pruss.h>
>  #include <linux/types.h>
>  
>  /*
> @@ -51,4 +52,4 @@ struct pruss {
>  	struct clk *iep_clk_mux;
>  };
>  
> -#endif	/* _PRUSS_DRIVER_H_ */
> +#endif	/* _PRUSS_INTERNAL_H_ */
> diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h
> index 039b50d58df2..93a98cac7829 100644
> --- a/include/linux/remoteproc/pruss.h
> +++ b/include/linux/remoteproc/pruss.h
> @@ -4,12 +4,14 @@
>   *
>   * Copyright (C) 2015-2022 Texas Instruments Incorporated - http://www.ti.com
>   *	Suman Anna <s-anna@ti.com>
> + *	Tero Kristo <t-kristo@ti.com>
>   */
>  
>  #ifndef __LINUX_PRUSS_H
>  #define __LINUX_PRUSS_H
>  
>  #include <linux/device.h>
> +#include <linux/err.h>
>  #include <linux/types.h>
>  
>  #define PRU_RPROC_DRVNAME "pru-rproc"
> @@ -44,6 +46,23 @@ enum pru_ctable_idx {
>  
>  struct device_node;
>  struct rproc;
> +struct pruss;
> +
> +#if IS_ENABLED(CONFIG_TI_PRUSS)
> +
> +struct pruss *pruss_get(struct rproc *rproc);
> +void pruss_put(struct pruss *pruss);
> +
> +#else
> +
> +static inline struct pruss *pruss_get(struct rproc *rproc)
> +{
> +	return ERR_PTR(-EOPNOTSUPP);
> +}
> +
> +static inline void pruss_put(struct pruss *pruss) { }
> +
> +#endif /* CONFIG_TI_PRUSS */
>  
>  #if IS_ENABLED(CONFIG_PRU_REMOTEPROC)
>  
> -- 
> 2.25.1
>
Mathieu Poirier March 29, 2023, 6:04 p.m. UTC | #3
On Tue, 28 Mar 2023 at 05:28, Md Danish Anwar <a0501179@ti.com> wrote:
>
>
>
> On 28/03/23 02:34, Mathieu Poirier wrote:
> > On Thu, Mar 23, 2023 at 11:54:51AM +0530, MD Danish Anwar wrote:
> >> From: Tero Kristo <t-kristo@ti.com>
> >>
> >> Add two new helper functions pruss_cfg_get_gpmux() & pruss_cfg_set_gpmux()
> >> to get and set the GP MUX mode for programming the PRUSS internal wrapper
> >> mux functionality as needed by usecases.
> >>
> >> Co-developed-by: Suman Anna <s-anna@ti.com>
> >> Signed-off-by: Suman Anna <s-anna@ti.com>
> >> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> >> Co-developed-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
> >> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
> >> Signed-off-by: Puranjay Mohan <p-mohan@ti.com>
> >> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
> >> Reviewed-by: Roger Quadros <rogerq@kernel.org>
> >> ---
> >>  drivers/soc/ti/pruss.c           | 44 ++++++++++++++++++++++++++++++++
> >>  include/linux/remoteproc/pruss.h | 30 ++++++++++++++++++++++
> >>  2 files changed, 74 insertions(+)
> >>
> >> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
> >> index ac415442e85b..3aa3c38c6c79 100644
> >> --- a/drivers/soc/ti/pruss.c
> >> +++ b/drivers/soc/ti/pruss.c
> >> @@ -239,6 +239,50 @@ int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type,
> >>  }
> >>  EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable);
> >>
> >> +/**
> >> + * pruss_cfg_get_gpmux() - get the current GPMUX value for a PRU device
> >> + * @pruss: pruss instance
> >> + * @pru_id: PRU identifier (0-1)
> >> + * @mux: pointer to store the current mux value into
> >> + *
> >> + * Return: 0 on success, or an error code otherwise
> >> + */
> >> +int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux)
> >> +{
> >> +    int ret = 0;
> >> +    u32 val;
> >> +
> >> +    if (pru_id < 0 || pru_id >= PRUSS_NUM_PRUS)
> >> +            return -EINVAL;
> >> +
> >> +    ret = pruss_cfg_read(pruss, PRUSS_CFG_GPCFG(pru_id), &val);
> >> +    if (!ret)
> >> +            *mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >>
> >> +                        PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
> >
> > What happens if @mux is NULL?
>
> @mux being null may result in some error here. I will add NULL check for mux
> before storing the value in mux.
>

It will result in a kernel panic.

> I will modify the above if condition to have NULL check for mux as well.
> The if condition will look like below.
>
>         if (pru_id < 0 || pru_id >= PRUSS_NUM_PRUS || !mux)
>                 return -EINVAL;
>

That will be fine.

> Please let me know if this looks OK.
>
> >
> > Thanks,
> > Mathieu
> >
> >
> >> +    return ret;
> >> +}
> >> +EXPORT_SYMBOL_GPL(pruss_cfg_get_gpmux);
> >> +
> >> +/**
> >> + * pruss_cfg_set_gpmux() - set the GPMUX value for a PRU device
> >> + * @pruss: pruss instance
> >> + * @pru_id: PRU identifier (0-1)
> >> + * @mux: new mux value for PRU
> >> + *
> >> + * Return: 0 on success, or an error code otherwise
> >> + */
> >> +int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux)
> >> +{
> >> +    if (mux >= PRUSS_GP_MUX_SEL_MAX ||
> >> +        pru_id < 0 || pru_id >= PRUSS_NUM_PRUS)
> >> +            return -EINVAL;
> >> +
> >> +    return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id),
> >> +                            PRUSS_GPCFG_PRU_MUX_SEL_MASK,
> >> +                            (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
> >> +}
> >> +EXPORT_SYMBOL_GPL(pruss_cfg_set_gpmux);
> >> +
> >>  static void pruss_of_free_clk_provider(void *data)
> >>  {
> >>      struct device_node *clk_mux_np = data;
> >> diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h
> >> index bb001f712980..42f1586c62ac 100644
> >> --- a/include/linux/remoteproc/pruss.h
> >> +++ b/include/linux/remoteproc/pruss.h
> >> @@ -16,6 +16,24 @@
> >>
> >>  #define PRU_RPROC_DRVNAME "pru-rproc"
> >>
> >> +/*
> >> + * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the
> >> + * PRUSS_GPCFG0/1 registers
> >> + *
> >> + * NOTE: The below defines are the most common values, but there
> >> + * are some exceptions like on 66AK2G, where the RESERVED and MII2
> >> + * values are interchanged. Also, this bit-field does not exist on
> >> + * AM335x SoCs
> >> + */
> >> +enum pruss_gp_mux_sel {
> >> +    PRUSS_GP_MUX_SEL_GP = 0,
> >> +    PRUSS_GP_MUX_SEL_ENDAT,
> >> +    PRUSS_GP_MUX_SEL_RESERVED,
> >> +    PRUSS_GP_MUX_SEL_SD,
> >> +    PRUSS_GP_MUX_SEL_MII2,
> >> +    PRUSS_GP_MUX_SEL_MAX,
> >> +};
> >> +
> >>  /*
> >>   * enum pruss_gpi_mode - PRUSS GPI configuration modes, used
> >>   *                   to program the PRUSS_GPCFG0/1 registers
> >> @@ -110,6 +128,8 @@ int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id,
> >>  int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable);
> >>  int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type,
> >>                       bool enable);
> >> +int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux);
> >> +int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux);
> >>
> >>  #else
> >>
> >> @@ -152,6 +172,16 @@ static inline int pruss_cfg_xfr_enable(struct pruss *pruss,
> >>      return ERR_PTR(-EOPNOTSUPP);
> >>  }
> >>
> >> +static inline int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux)
> >> +{
> >> +    return ERR_PTR(-EOPNOTSUPP);
> >> +}
> >> +
> >> +static inline int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux)
> >> +{
> >> +    return ERR_PTR(-EOPNOTSUPP);
> >> +}
> >> +
> >>  #endif /* CONFIG_TI_PRUSS */
> >>
> >>  #if IS_ENABLED(CONFIG_PRU_REMOTEPROC)
> >> --
> >> 2.25.1
> >>
>
> --
> Thanks and Regards,
> Danish.
Anwar, Md Danish March 30, 2023, 9:16 a.m. UTC | #4
On 29/03/23 23:29, Mathieu Poirier wrote:
> On Mon, 27 Mar 2023 at 23:42, Md Danish Anwar <a0501179@ti.com> wrote:
>>
>> Hi Mathieu,
>>
>> On 28/03/23 02:28, Mathieu Poirier wrote:
>>> Hi Danish
>>>
>>> On Thu, Mar 23, 2023 at 11:54:47AM +0530, MD Danish Anwar wrote:
>>>> From: Tero Kristo <t-kristo@ti.com>
>>>>
>>>> Add two new get and put API, pruss_get() and pruss_put() to the
>>>> PRUSS platform driver to allow client drivers to request a handle
>>>> to a PRUSS device. This handle will be used by client drivers to
>>>> request various operations of the PRUSS platform driver through
>>>> additional API that will be added in the following patches.
>>>>
>>>> The pruss_get() function returns the pruss handle corresponding
>>>> to a PRUSS device referenced by a PRU remoteproc instance. The
>>>> pruss_put() is the complimentary function to pruss_get().
>>>>
>>>> Co-developed-by: Suman Anna <s-anna@ti.com>
>>>> Signed-off-by: Suman Anna <s-anna@ti.com>
>>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>>> Co-developed-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
>>>> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
>>>> Signed-off-by: Puranjay Mohan <p-mohan@ti.com>
>>>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>>>> Reviewed-by: Roger Quadros <rogerq@kernel.org>
>>>> ---
>>>>  drivers/remoteproc/pru_rproc.c                |  2 +-
>>>>  drivers/soc/ti/pruss.c                        | 60 ++++++++++++++++++-
>>>>  .../{pruss_driver.h => pruss_internal.h}      |  7 ++-
>>>>  include/linux/remoteproc/pruss.h              | 19 ++++++
>>>>  4 files changed, 83 insertions(+), 5 deletions(-)
>>>>  rename include/linux/{pruss_driver.h => pruss_internal.h} (90%)
>>>>
>>>> diff --git a/drivers/remoteproc/pru_rproc.c b/drivers/remoteproc/pru_rproc.c
>>>> index b76db7fa693d..4ddd5854d56e 100644
>>>> --- a/drivers/remoteproc/pru_rproc.c
>>>> +++ b/drivers/remoteproc/pru_rproc.c
>>>> @@ -19,7 +19,7 @@
>>>>  #include <linux/of_device.h>
>>>>  #include <linux/of_irq.h>
>>>>  #include <linux/remoteproc/pruss.h>
>>>> -#include <linux/pruss_driver.h>
>>>> +#include <linux/pruss_internal.h>
>>>>  #include <linux/remoteproc.h>
>>>>
>>>>  #include "remoteproc_internal.h"
>>>> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
>>>> index 6882c86b3ce5..6c2bb02a521d 100644
>>>> --- a/drivers/soc/ti/pruss.c
>>>> +++ b/drivers/soc/ti/pruss.c
>>>> @@ -6,6 +6,7 @@
>>>>   * Author(s):
>>>>   *  Suman Anna <s-anna@ti.com>
>>>>   *  Andrew F. Davis <afd@ti.com>
>>>> + *  Tero Kristo <t-kristo@ti.com>
>>>>   */
>>>>
>>>>  #include <linux/clk-provider.h>
>>>> @@ -16,8 +17,9 @@
>>>>  #include <linux/of_address.h>
>>>>  #include <linux/of_device.h>
>>>>  #include <linux/pm_runtime.h>
>>>> -#include <linux/pruss_driver.h>
>>>> +#include <linux/pruss_internal.h>
>>>>  #include <linux/regmap.h>
>>>> +#include <linux/remoteproc.h>
>>>>  #include <linux/slab.h>
>>>>
>>>>  /**
>>>> @@ -30,6 +32,62 @@ struct pruss_private_data {
>>>>      bool has_core_mux_clock;
>>>>  };
>>>>
>>>> +/**
>>>> + * pruss_get() - get the pruss for a given PRU remoteproc
>>>> + * @rproc: remoteproc handle of a PRU instance
>>>> + *
>>>> + * Finds the parent pruss device for a PRU given the @rproc handle of the
>>>> + * PRU remote processor. This function increments the pruss device's refcount,
>>>> + * so always use pruss_put() to decrement it back once pruss isn't needed
>>>> + * anymore.
>>>> + *
>>>> + * Return: pruss handle on success, and an ERR_PTR on failure using one
>>>> + * of the following error values
>>>> + *    -EINVAL if invalid parameter
>>>> + *    -ENODEV if PRU device or PRUSS device is not found
>>>> + */
>>>> +struct pruss *pruss_get(struct rproc *rproc)
>>>> +{
>>>> +    struct pruss *pruss;
>>>> +    struct device *dev;
>>>> +    struct platform_device *ppdev;
>>>> +
>>>> +    if (IS_ERR_OR_NULL(rproc))
>>>> +            return ERR_PTR(-EINVAL);
>>>> +
>>>
>>> There is no guarantee that @rproc is valid without calling rproc_get_by_handle()
>>> or pru_rproc_get().
>>>
>>
>> Here in this API, we are checking if rproc is NULL or not. Also we are checking
>> is_pru_rproc() to make sure this rproc is pru-rproc only and not some other rproc.
>>
>> This API will be called from driver (icssg_prueth.c) which I'll post once this
>> series is merged.
>>
>> In the driver we are doing,
>>
>>         prueth->pru[slice] = pru_rproc_get(np, pru, &pruss_id);
>>
>>         pruss = pruss_get(prueth->pru[slice]);
>>
>> So, before calling pruss_get() we are in fact calling pru_rproc_get() to make
>> sure it's a valid rproc.
>>
> 
> You are doing the right thing but because pruss_get() is exported
> globally, other people eventually using the interface may not be so
> rigorous.  Add a comment to the pruss_get() function documentation
> clearly mentioning it is expected the caller will have done a
> pru_rproc_get() on @rproc.
> 

Sure, Mathieu. I will add the required comment in pruss_get() documentation.

>> I think in this API, these two checks (NULL check and is_pru_rproc) should be
>> OK as the driver is already calling pru_rproc_get() before this API.
>>
>> The only way to get a "pru-rproc" is by calling pru_rproc_get(), now the check
>> is_pru_rproc() will only be true if it is a "pru-rproc" implying
>> pru_rproc_get() was called before calling this API.
>>
>> Please let me know if this is OK or if any change is required.
>>
>>>> +    dev = &rproc->dev;
>>>> +
>>>> +    /* make sure it is PRU rproc */
>>>> +    if (!dev->parent || !is_pru_rproc(dev->parent))
>>>> +            return ERR_PTR(-ENODEV);
>>>> +
>>>> +    ppdev = to_platform_device(dev->parent->parent);
>>>> +    pruss = platform_get_drvdata(ppdev);
>>>> +    if (!pruss)
>>>> +            return ERR_PTR(-ENODEV);
>>>> +
>>>> +    get_device(pruss->dev);
>>>> +
>>>> +    return pruss;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(pruss_get);
>>>> +
>>>> +/**
>>>> + * pruss_put() - decrement pruss device's usecount
>>>> + * @pruss: pruss handle
>>>> + *
>>>> + * Complimentary function for pruss_get(). Needs to be called
>>>> + * after the PRUSS is used, and only if the pruss_get() succeeds.
>>>> + */
>>>> +void pruss_put(struct pruss *pruss)
>>>> +{
>>>> +    if (IS_ERR_OR_NULL(pruss))
>>>> +            return;
>>>> +
>>>> +    put_device(pruss->dev);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(pruss_put);
>>>> +
>>>>  static void pruss_of_free_clk_provider(void *data)
>>>>  {
>>>>      struct device_node *clk_mux_np = data;
>>>> diff --git a/include/linux/pruss_driver.h b/include/linux/pruss_internal.h
>>>> similarity index 90%
>>>> rename from include/linux/pruss_driver.h
>>>> rename to include/linux/pruss_internal.h
>>>> index ecfded30ed05..8f91cb164054 100644
>>>> --- a/include/linux/pruss_driver.h
>>>> +++ b/include/linux/pruss_internal.h
>>>> @@ -6,9 +6,10 @@
>>>>   *  Suman Anna <s-anna@ti.com>
>>>>   */
>>>>
>>>> -#ifndef _PRUSS_DRIVER_H_
>>>> -#define _PRUSS_DRIVER_H_
>>>> +#ifndef _PRUSS_INTERNAL_H_
>>>> +#define _PRUSS_INTERNAL_H_
>>>>
>>>> +#include <linux/remoteproc/pruss.h>
>>>>  #include <linux/types.h>
>>>>
>>>>  /*
>>>> @@ -51,4 +52,4 @@ struct pruss {
>>>>      struct clk *iep_clk_mux;
>>>>  };
>>>>
>>>> -#endif      /* _PRUSS_DRIVER_H_ */
>>>> +#endif      /* _PRUSS_INTERNAL_H_ */
>>>> diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h
>>>> index 039b50d58df2..93a98cac7829 100644
>>>> --- a/include/linux/remoteproc/pruss.h
>>>> +++ b/include/linux/remoteproc/pruss.h
>>>> @@ -4,12 +4,14 @@
>>>>   *
>>>>   * Copyright (C) 2015-2022 Texas Instruments Incorporated - http://www.ti.com
>>>>   *  Suman Anna <s-anna@ti.com>
>>>> + *  Tero Kristo <t-kristo@ti.com>
>>>>   */
>>>>
>>>>  #ifndef __LINUX_PRUSS_H
>>>>  #define __LINUX_PRUSS_H
>>>>
>>>>  #include <linux/device.h>
>>>> +#include <linux/err.h>
>>>>  #include <linux/types.h>
>>>>
>>>>  #define PRU_RPROC_DRVNAME "pru-rproc"
>>>> @@ -44,6 +46,23 @@ enum pru_ctable_idx {
>>>>
>>>>  struct device_node;
>>>>  struct rproc;
>>>> +struct pruss;
>>>> +
>>>> +#if IS_ENABLED(CONFIG_TI_PRUSS)
>>>> +
>>>> +struct pruss *pruss_get(struct rproc *rproc);
>>>> +void pruss_put(struct pruss *pruss);
>>>> +
>>>> +#else
>>>> +
>>>> +static inline struct pruss *pruss_get(struct rproc *rproc)
>>>> +{
>>>> +    return ERR_PTR(-EOPNOTSUPP);
>>>> +}
>>>> +
>>>> +static inline void pruss_put(struct pruss *pruss) { }
>>>> +
>>>> +#endif /* CONFIG_TI_PRUSS */
>>>>
>>>>  #if IS_ENABLED(CONFIG_PRU_REMOTEPROC)
>>>>
>>>> --
>>>> 2.25.1
>>>>
>>
>> --
>> Thanks and Regards,
>> Danish.
Anwar, Md Danish March 30, 2023, 9:18 a.m. UTC | #5
On 29/03/23 23:34, Mathieu Poirier wrote:
> On Tue, 28 Mar 2023 at 05:28, Md Danish Anwar <a0501179@ti.com> wrote:
>>
>> On 28/03/23 02:34, Mathieu Poirier wrote:
>>> On Thu, Mar 23, 2023 at 11:54:51AM +0530, MD Danish Anwar wrote:
>>>> From: Tero Kristo <t-kristo@ti.com>
>>>>
>>>> Add two new helper functions pruss_cfg_get_gpmux() & pruss_cfg_set_gpmux()
>>>> to get and set the GP MUX mode for programming the PRUSS internal wrapper
>>>> mux functionality as needed by usecases.
>>>>
>>>> Co-developed-by: Suman Anna <s-anna@ti.com>
>>>> Signed-off-by: Suman Anna <s-anna@ti.com>
>>>> Signed-off-by: Tero Kristo <t-kristo@ti.com>
>>>> Co-developed-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
>>>> Signed-off-by: Grzegorz Jaszczyk <grzegorz.jaszczyk@linaro.org>
>>>> Signed-off-by: Puranjay Mohan <p-mohan@ti.com>
>>>> Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
>>>> Reviewed-by: Roger Quadros <rogerq@kernel.org>
>>>> ---
>>>>  drivers/soc/ti/pruss.c           | 44 ++++++++++++++++++++++++++++++++
>>>>  include/linux/remoteproc/pruss.h | 30 ++++++++++++++++++++++
>>>>  2 files changed, 74 insertions(+)
>>>>
>>>> diff --git a/drivers/soc/ti/pruss.c b/drivers/soc/ti/pruss.c
>>>> index ac415442e85b..3aa3c38c6c79 100644
>>>> --- a/drivers/soc/ti/pruss.c
>>>> +++ b/drivers/soc/ti/pruss.c
>>>> @@ -239,6 +239,50 @@ int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type,
>>>>  }
>>>>  EXPORT_SYMBOL_GPL(pruss_cfg_xfr_enable);
>>>>
>>>> +/**
>>>> + * pruss_cfg_get_gpmux() - get the current GPMUX value for a PRU device
>>>> + * @pruss: pruss instance
>>>> + * @pru_id: PRU identifier (0-1)
>>>> + * @mux: pointer to store the current mux value into
>>>> + *
>>>> + * Return: 0 on success, or an error code otherwise
>>>> + */
>>>> +int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux)
>>>> +{
>>>> +    int ret = 0;
>>>> +    u32 val;
>>>> +
>>>> +    if (pru_id < 0 || pru_id >= PRUSS_NUM_PRUS)
>>>> +            return -EINVAL;
>>>> +
>>>> +    ret = pruss_cfg_read(pruss, PRUSS_CFG_GPCFG(pru_id), &val);
>>>> +    if (!ret)
>>>> +            *mux = (u8)((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK) >>
>>>> +                        PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
>>>
>>> What happens if @mux is NULL?
>>
>> @mux being null may result in some error here. I will add NULL check for mux
>> before storing the value in mux.
>>
> 
> It will result in a kernel panic.
> 
>> I will modify the above if condition to have NULL check for mux as well.
>> The if condition will look like below.
>>
>>         if (pru_id < 0 || pru_id >= PRUSS_NUM_PRUS || !mux)
>>                 return -EINVAL;
>>
> 
> That will be fine.>

Sure, I'll go ahead and make this change.

>> Please let me know if this looks OK.
>>
>>>
>>> Thanks,
>>> Mathieu
>>>
>>>
>>>> +    return ret;
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(pruss_cfg_get_gpmux);
>>>> +
>>>> +/**
>>>> + * pruss_cfg_set_gpmux() - set the GPMUX value for a PRU device
>>>> + * @pruss: pruss instance
>>>> + * @pru_id: PRU identifier (0-1)
>>>> + * @mux: new mux value for PRU
>>>> + *
>>>> + * Return: 0 on success, or an error code otherwise
>>>> + */
>>>> +int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux)
>>>> +{
>>>> +    if (mux >= PRUSS_GP_MUX_SEL_MAX ||
>>>> +        pru_id < 0 || pru_id >= PRUSS_NUM_PRUS)
>>>> +            return -EINVAL;
>>>> +
>>>> +    return pruss_cfg_update(pruss, PRUSS_CFG_GPCFG(pru_id),
>>>> +                            PRUSS_GPCFG_PRU_MUX_SEL_MASK,
>>>> +                            (u32)mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT);
>>>> +}
>>>> +EXPORT_SYMBOL_GPL(pruss_cfg_set_gpmux);
>>>> +
>>>>  static void pruss_of_free_clk_provider(void *data)
>>>>  {
>>>>      struct device_node *clk_mux_np = data;
>>>> diff --git a/include/linux/remoteproc/pruss.h b/include/linux/remoteproc/pruss.h
>>>> index bb001f712980..42f1586c62ac 100644
>>>> --- a/include/linux/remoteproc/pruss.h
>>>> +++ b/include/linux/remoteproc/pruss.h
>>>> @@ -16,6 +16,24 @@
>>>>
>>>>  #define PRU_RPROC_DRVNAME "pru-rproc"
>>>>
>>>> +/*
>>>> + * enum pruss_gp_mux_sel - PRUSS GPI/O Mux modes for the
>>>> + * PRUSS_GPCFG0/1 registers
>>>> + *
>>>> + * NOTE: The below defines are the most common values, but there
>>>> + * are some exceptions like on 66AK2G, where the RESERVED and MII2
>>>> + * values are interchanged. Also, this bit-field does not exist on
>>>> + * AM335x SoCs
>>>> + */
>>>> +enum pruss_gp_mux_sel {
>>>> +    PRUSS_GP_MUX_SEL_GP = 0,
>>>> +    PRUSS_GP_MUX_SEL_ENDAT,
>>>> +    PRUSS_GP_MUX_SEL_RESERVED,
>>>> +    PRUSS_GP_MUX_SEL_SD,
>>>> +    PRUSS_GP_MUX_SEL_MII2,
>>>> +    PRUSS_GP_MUX_SEL_MAX,
>>>> +};
>>>> +
>>>>  /*
>>>>   * enum pruss_gpi_mode - PRUSS GPI configuration modes, used
>>>>   *                   to program the PRUSS_GPCFG0/1 registers
>>>> @@ -110,6 +128,8 @@ int pruss_cfg_gpimode(struct pruss *pruss, enum pruss_pru_id pru_id,
>>>>  int pruss_cfg_miirt_enable(struct pruss *pruss, bool enable);
>>>>  int pruss_cfg_xfr_enable(struct pruss *pruss, enum pru_type pru_type,
>>>>                       bool enable);
>>>> +int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux);
>>>> +int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux);
>>>>
>>>>  #else
>>>>
>>>> @@ -152,6 +172,16 @@ static inline int pruss_cfg_xfr_enable(struct pruss *pruss,
>>>>      return ERR_PTR(-EOPNOTSUPP);
>>>>  }
>>>>
>>>> +static inline int pruss_cfg_get_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 *mux)
>>>> +{
>>>> +    return ERR_PTR(-EOPNOTSUPP);
>>>> +}
>>>> +
>>>> +static inline int pruss_cfg_set_gpmux(struct pruss *pruss, enum pruss_pru_id pru_id, u8 mux)
>>>> +{
>>>> +    return ERR_PTR(-EOPNOTSUPP);
>>>> +}
>>>> +
>>>>  #endif /* CONFIG_TI_PRUSS */
>>>>
>>>>  #if IS_ENABLED(CONFIG_PRU_REMOTEPROC)
>>>> --
>>>> 2.25.1
>>>>
>>
>> --
>> Thanks and Regards,
>> Danish.