linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Bjorn Andersson <bjorn.andersson@linaro.org>
To: Tero Kristo <t-kristo@ti.com>
Cc: ohad@wizery.com, linux-remoteproc@vger.kernel.org,
	linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org,
	s-anna@ti.com
Subject: Re: [PATCH 12/17] remoteproc/omap: Request a timer(s) for remoteproc usage
Date: Mon, 11 Nov 2019 20:13:51 -0800	[thread overview]
Message-ID: <20191112041351.GN3108315@builder> (raw)
In-Reply-To: <20191028124238.19224-13-t-kristo@ti.com>

On Mon 28 Oct 05:42 PDT 2019, Tero Kristo wrote:

> From: Suman Anna <s-anna@ti.com>
> 
> The remote processors in OMAP4+ SoCs are equipped with internal
> timers, like the internal SysTick timer in a Cortex M3/M4 NVIC or
> the CTM timer within Unicache in IPU & DSP. However, these timers
> are gated when the processor subsystem clock is gated, making
> them rather difficult to use as OS tick sources. They will not
> be able to wakeup the processor from any processor-sleep induced
> clock-gating states.
> 
> This can be avoided by using an external timer as the tick source,
> which can be controlled independently by the OMAP remoteproc
> driver code, but still allowing the processor subsystem clock to
> be auto-gated when the remoteproc cores are idle.
> 
> This patch adds the support for OMAP remote processors to request
> timer(s) to be used by the remoteproc. The timers are enabled and
> disabled in line with the enabling/disabling of the remoteproc.
> The timer data is not mandatory if the advanced device management
> features are not required.
> 
> The core timer functionality is provided by the OMAP DMTimer
> clocksource driver, which does not export any API. The logic is
> implemented through the timer device's platform data ops. The OMAP
> remoteproc driver mainly requires ops to request/free a dmtimer,
> and to start/stop a timer. The split ops helps in controlling the
> timer state without having to request and release a timer everytime
> it needs to use the timer.
> 
> NOTE: If the gptimer is already in use by the time IPU and/or
> DSP are loaded, the processors will fail to boot.
> 
> Signed-off-by: Suman Anna <s-anna@ti.com>
> Signed-off-by: Tero Kristo <t-kristo@ti.com>
> ---
>  drivers/remoteproc/omap_remoteproc.c | 258 +++++++++++++++++++++++++++
>  1 file changed, 258 insertions(+)
> 
> diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
> index 016d5beda195..8450dd79d391 100644
> --- a/drivers/remoteproc/omap_remoteproc.c
> +++ b/drivers/remoteproc/omap_remoteproc.c
> @@ -27,6 +27,9 @@
>  #include <linux/regmap.h>
>  #include <linux/mfd/syscon.h>
>  #include <linux/reset.h>
> +#include <clocksource/timer-ti-dm.h>
> +
> +#include <linux/platform_data/dmtimer-omap.h>
>  
>  #include "omap_remoteproc.h"
>  #include "remoteproc_internal.h"
> @@ -61,6 +64,16 @@ struct omap_rproc_mem {
>  	size_t size;
>  };
>  
> +/**
> + * struct omap_rproc_timer - data structure for a timer used by a omap rproc
> + * @odt: timer pointer
> + * @timer_ops: OMAP dmtimer ops for @odt timer
> + */
> +struct omap_rproc_timer {
> +	struct omap_dm_timer *odt;
> +	const struct omap_dm_timer_ops *timer_ops;
> +};
> +
>  /**
>   * struct omap_rproc - omap remote processor state
>   * @mbox: mailbox channel handle
> @@ -68,6 +81,8 @@ struct omap_rproc_mem {
>   * @boot_data: boot data structure for setting processor boot address
>   * @mem: internal memory regions data
>   * @num_mems: number of internal memory regions
> + * @num_timers: number of rproc timer(s)
> + * @timers: timer(s) info used by rproc
>   * @rproc: rproc handle
>   * @reset: reset handle
>   */
> @@ -77,6 +92,8 @@ struct omap_rproc {
>  	struct omap_rproc_boot_data *boot_data;
>  	struct omap_rproc_mem *mem;
>  	int num_mems;
> +	int num_timers;
> +	struct omap_rproc_timer *timers;
>  	struct rproc *rproc;
>  	struct reset_control *reset;
>  };
> @@ -91,6 +108,212 @@ struct omap_rproc_dev_data {
>  	const char *fw_name;
>  };
>  
> +/**
> + * omap_rproc_request_timer - request a timer for a remoteproc

Add parenthesis on functions in kerneldoc.

> + * @np: device node pointer to the desired timer
> + * @timer: handle to a struct omap_rproc_timer to return the timer handle
> + *
> + * This helper function is used primarily to request a timer associated with
> + * a remoteproc. The returned handle is stored in the .odt field of the
> + * @timer structure passed in, and is used to invoke other timer specific
> + * ops (like starting a timer either during device initialization or during
> + * a resume operation, or for stopping/freeing a timer).
> + *
> + * Returns 0 on success, otherwise an appropriate failure
> + */
> +static int omap_rproc_request_timer(struct device_node *np,
> +				    struct omap_rproc_timer *timer)
> +{
> +	int ret = 0;
> +
> +	timer->odt = timer->timer_ops->request_by_node(np);
> +	if (!timer->odt) {
> +		pr_err("request for timer node %p failed\n", np);
> +		return -EBUSY;
> +	}
> +
> +	ret = timer->timer_ops->set_source(timer->odt, OMAP_TIMER_SRC_SYS_CLK);
> +	if (ret) {
> +		pr_err("error setting OMAP_TIMER_SRC_SYS_CLK as source for timer node %p\n",
> +		       np);

You could easily pass a struct device * from omap_rproc_enable_timers()
to make this a more useful dev_err()

> +		timer->timer_ops->free(timer->odt);
> +		return ret;
> +	}
> +
> +	/* clean counter, remoteproc code will set the value */
> +	timer->timer_ops->set_load(timer->odt, 0, 0);
> +
> +	return ret;

ret is 0 here, so return 0;

> +}
> +
> +/**
> + * omap_rproc_start_timer - start a timer for a remoteproc
> + * @timer: handle to a OMAP rproc timer
> + *
> + * This helper function is used to start a timer associated with a remoteproc,
> + * obtained using the request_timer ops. The helper function needs to be
> + * invoked by the driver to start the timer (during device initialization)
> + * or to just resume the timer.
> + *
> + * Returns 0 on success, otherwise a failure as returned by DMTimer ops
> + */
> +static inline int omap_rproc_start_timer(struct omap_rproc_timer *timer)
> +{
> +	return timer->timer_ops->start(timer->odt);
> +}
> +
> +/**
> + * omap_rproc_stop_timer - stop a timer for a remoteproc
> + * @timer: handle to a OMAP rproc timer
> + *
> + * This helper function is used to disable a timer associated with a
> + * remoteproc, and needs to be called either during a device shutdown
> + * or suspend operation. The separate helper function allows the driver
> + * to just stop a timer without having to release the timer during a
> + * suspend operation.
> + *
> + * Returns 0 on success, otherwise a failure as returned by DMTimer ops
> + */
> +static inline int omap_rproc_stop_timer(struct omap_rproc_timer *timer)
> +{
> +	return timer->timer_ops->stop(timer->odt);
> +}
> +
> +/**
> + * omap_rproc_release_timer - release a timer for a remoteproc
> + * @timer: handle to a OMAP rproc timer
> + *
> + * This helper function is used primarily to release a timer associated
> + * with a remoteproc. The dmtimer will be available for other clients to
> + * use once released.
> + *
> + * Returns 0 on success, otherwise a failure as returned by DMTimer ops
> + */
> +static inline int omap_rproc_release_timer(struct omap_rproc_timer *timer)
> +{
> +	return timer->timer_ops->free(timer->odt);
> +}
> +
> +/**
> + * omap_rproc_enable_timers - enable the timers for a remoteproc
> + * @rproc: handle of a remote processor
> + * @configure: boolean flag used to acquire and configure the timer handle
> + *
> + * This function is used primarily to enable the timers associated with
> + * a remoteproc. The configure flag is provided to allow the driver to
> + * to either acquire and start a timer (during device initialization) or
> + * to just start a timer (during a resume operation).
> + */
> +static int omap_rproc_enable_timers(struct rproc *rproc, bool configure)
> +{
> +	int i;
> +	int ret = 0;
> +	struct platform_device *tpdev;
> +	struct dmtimer_platform_data *tpdata;
> +	const struct omap_dm_timer_ops *timer_ops;
> +	struct omap_rproc *oproc = rproc->priv;
> +	struct omap_rproc_timer *timers = oproc->timers;
> +	struct device *dev = rproc->dev.parent;
> +	struct device_node *np = NULL;
> +
> +	if (oproc->num_timers <= 0)
> +		return 0;
> +
> +	if (!configure)
> +		goto start_timers;
> +
> +	for (i = 0; i < oproc->num_timers; i++) {
> +		np = of_parse_phandle(dev->of_node, "timers", i);
> +		if (!np) {
> +			ret = -ENXIO;
> +			dev_err(dev, "device node lookup for timer at index %d failed: %d\n",
> +				i, ret);
> +			goto free_timers;
> +		}
> +
> +		tpdev = of_find_device_by_node(np);
> +		if (!tpdev) {
> +			ret = -ENODEV;
> +			dev_err(dev, "could not get timer platform device\n");
> +			goto put_node;
> +		}
> +
> +		tpdata = dev_get_platdata(&tpdev->dev);
> +		put_device(&tpdev->dev);
> +		if (!tpdata) {
> +			ret = -EINVAL;
> +			dev_err(dev, "dmtimer pdata structure NULL\n");
> +			goto put_node;
> +		}
> +
> +		timer_ops = tpdata->timer_ops;
> +		if (!timer_ops || !timer_ops->request_by_node ||
> +		    !timer_ops->set_source || !timer_ops->set_load ||
> +		    !timer_ops->free || !timer_ops->start ||
> +		    !timer_ops->stop) {
> +			ret = -EINVAL;
> +			dev_err(dev, "device does not have required timer ops\n");
> +			goto put_node;
> +		}
> +
> +		timers[i].timer_ops = timer_ops;
> +		ret = omap_rproc_request_timer(np, &timers[i]);
> +		if (ret) {
> +			dev_err(dev, "request for timer %p failed: %d\n", np,
> +				ret);
> +			goto put_node;
> +		}
> +		of_node_put(np);
> +	}
> +
> +start_timers:
> +	for (i = 0; i < oproc->num_timers; i++)
> +		omap_rproc_start_timer(&timers[i]);
> +	return 0;
> +
> +put_node:
> +	of_node_put(np);
> +free_timers:
> +	while (i--) {
> +		omap_rproc_release_timer(&timers[i]);
> +		timers[i].odt = NULL;
> +		timers[i].timer_ops = NULL;
> +	}
> +
> +	return ret;
> +}
> +
> +/**
> + * omap_rproc_disable_timers - disable the timers for a remoteproc
> + * @rproc: handle of a remote processor
> + * @configure: boolean flag used to release the timer handle
> + *
> + * This function is used primarily to disable the timers associated with
> + * a remoteproc. The configure flag is provided to allow the driver to
> + * to either stop and release a timer (during device shutdown) or to just
> + * stop a timer (during a suspend operation).
> + */
> +static int omap_rproc_disable_timers(struct rproc *rproc, bool configure)
> +{
> +	int i;
> +	struct omap_rproc *oproc = rproc->priv;
> +	struct omap_rproc_timer *timers = oproc->timers;
> +
> +	if (oproc->num_timers <= 0)
> +		return 0;
> +
> +	for (i = 0; i < oproc->num_timers; i++) {
> +		omap_rproc_stop_timer(&timers[i]);
> +		if (configure) {
> +			omap_rproc_release_timer(&timers[i]);
> +			timers[i].odt = NULL;
> +			timers[i].timer_ops = NULL;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  /**
>   * omap_rproc_mbox_callback() - inbound mailbox message handler
>   * @client: mailbox client pointer used for requesting the mailbox channel
> @@ -226,6 +449,12 @@ static int omap_rproc_start(struct rproc *rproc)
>  		goto put_mbox;
>  	}
>  
> +	ret = omap_rproc_enable_timers(rproc, true);
> +	if (ret) {
> +		dev_err(dev, "omap_rproc_enable_timers failed: %d\n", ret);
> +		goto put_mbox;
> +	}
> +
>  	reset_control_deassert(oproc->reset);
>  
>  	return 0;
> @@ -239,9 +468,14 @@ static int omap_rproc_start(struct rproc *rproc)
>  static int omap_rproc_stop(struct rproc *rproc)
>  {
>  	struct omap_rproc *oproc = rproc->priv;
> +	int ret;
>  
>  	reset_control_assert(oproc->reset);
>  
> +	ret = omap_rproc_disable_timers(rproc, true);
> +	if (ret)
> +		return ret;
> +
>  	mbox_free_channel(oproc->mbox);
>  
>  	return 0;
> @@ -548,6 +782,30 @@ static int omap_rproc_probe(struct platform_device *pdev)
>  	if (ret)
>  		goto free_rproc;
>  
> +	/*
> +	 * Timer nodes are directly used in client nodes as phandles, so
> +	 * retrieve the count using appropriate size
> +	 */
> +	oproc->num_timers = of_property_count_elems_of_size(np, "timers",

Didn't this get a ti, prefix?

And I think you should use of_count_phandle_with_args() instead.

Regards,
Bjorn

> +							    sizeof(phandle));
> +	if (oproc->num_timers <= 0) {
> +		dev_dbg(&pdev->dev, "device does not have timers, status = %d\n",
> +			oproc->num_timers);
> +		oproc->num_timers = 0;
> +	}
> +
> +	if (oproc->num_timers) {
> +		oproc->timers = devm_kzalloc(&pdev->dev, sizeof(*oproc->timers)
> +					     * oproc->num_timers, GFP_KERNEL);
> +		if (!oproc->timers) {
> +			ret = -ENOMEM;
> +			goto free_rproc;
> +		}
> +
> +		dev_dbg(&pdev->dev, "device has %d tick timers\n",
> +			oproc->num_timers);
> +	}
> +
>  	ret = of_reserved_mem_device_init(&pdev->dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "device does not have specific CMA pool\n");
> -- 
> 2.17.1
> 
> --
> Texas Instruments Finland Oy, Porkkalankatu 22, 00180 Helsinki. Y-tunnus/Business ID: 0615521-4. Kotipaikka/Domicile: Helsinki

  reply	other threads:[~2019-11-12  4:13 UTC|newest]

Thread overview: 51+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-10-28 12:42 [PATCH 00/17] remoteproc: omap changes on top of v5.4-rc1 Tero Kristo
2019-10-28 12:42 ` [PATCH 01/17] dt-bindings: remoteproc: Add OMAP remoteproc bindings Tero Kristo
2019-11-06  3:27   ` Rob Herring
2019-11-06 12:44     ` Tero Kristo
2019-11-06 13:27       ` Rob Herring
2019-11-06 13:50         ` Tero Kristo
2019-11-07 14:05   ` [PATCHv2 " Tero Kristo
2019-11-13 14:25     ` Rob Herring
2019-10-28 12:42 ` [PATCH 02/17] remoteproc/omap: Switch to SPDX license identifiers Tero Kristo
2019-11-09  1:03   ` Bjorn Andersson
2019-11-12  8:16     ` Tero Kristo
2019-12-20  3:30       ` Suman Anna
2019-10-28 12:42 ` [PATCH 03/17] remoteproc/omap: Add device tree support Tero Kristo
2019-11-11 23:16   ` Bjorn Andersson
2019-11-12  8:14     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 04/17] remoteproc/omap: Add a sanity check for DSP boot address alignment Tero Kristo
2019-11-11 23:18   ` Bjorn Andersson
2019-10-28 12:42 ` [PATCH 05/17] remoteproc/omap: Add support to parse internal memories from DT Tero Kristo
2019-11-11 23:21   ` Bjorn Andersson
2019-11-12  8:21     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 06/17] remoteproc/omap: Add the rproc ops .da_to_va() implementation Tero Kristo
2019-11-11 23:22   ` Bjorn Andersson
2019-11-12  8:22     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 07/17] remoteproc/omap: Initialize and assign reserved memory node Tero Kristo
2019-11-11 23:23   ` Bjorn Andersson
2019-10-28 12:42 ` [PATCH 08/17] remoteproc/omap: Add support for DRA7xx remote processors Tero Kristo
2019-11-11 23:37   ` Bjorn Andersson
2019-11-12  8:37     ` Tero Kristo
2019-11-12 18:13       ` Bjorn Andersson
2019-11-13  8:08         ` Tero Kristo
2019-10-28 12:42 ` [PATCH 09/17] remoteproc/omap: Remove the unused fields from platform data Tero Kristo
2019-11-11 23:37   ` Bjorn Andersson
2019-10-28 12:42 ` [PATCH 10/17] remoteproc/omap: Remove the omap_rproc_reserve_cma declaration Tero Kristo
2019-11-11 23:37   ` Bjorn Andersson
2019-10-28 12:42 ` [PATCH 11/17] remoteproc/omap: Check for undefined mailbox messages Tero Kristo
2019-11-11 23:39   ` Bjorn Andersson
2019-11-12  8:38     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 12/17] remoteproc/omap: Request a timer(s) for remoteproc usage Tero Kristo
2019-11-12  4:13   ` Bjorn Andersson [this message]
2019-11-12  8:42     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 13/17] remoteproc/omap: add support for system suspend/resume Tero Kristo
2019-11-12  6:15   ` Bjorn Andersson
2019-11-12  8:45     ` Tero Kristo
2019-11-12 18:06       ` Bjorn Andersson
2019-10-28 12:42 ` [PATCH 14/17] remoteproc/omap: add support for runtime auto-suspend/resume Tero Kristo
2019-10-28 12:42 ` [PATCH 15/17] remoteproc/omap: report device exceptions and trigger recovery Tero Kristo
2019-11-12  6:26   ` Bjorn Andersson
2019-11-12  8:46     ` Tero Kristo
2019-10-28 12:42 ` [PATCH 16/17] remoteproc/omap: add watchdog functionality for remote processors Tero Kristo
2019-10-28 12:42 ` [PATCH 17/17] remoteproc/omap: fix auto-suspend failure warning during crashed state Tero Kristo
2019-11-12  6:28   ` Bjorn Andersson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20191112041351.GN3108315@builder \
    --to=bjorn.andersson@linaro.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=linux-remoteproc@vger.kernel.org \
    --cc=ohad@wizery.com \
    --cc=s-anna@ti.com \
    --cc=t-kristo@ti.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).