Commit c54fc865 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'rproc-v4.19' of git://github.com/andersson/remoteproc

Pull remoteproc updates from Bjorn Andersson:
 "This adds support for pre-start and post-shutdown hooks for remoteproc
  subdevices, refactors the Qualcomm Hexagon support to allow reuse
  between several drivers, makes authentication in the MDT file loader
  optional, migrates a few format strings to use %pK and migrates the
  Davinci driver to use the reset framework"

* tag 'rproc-v4.19' of git://github.com/andersson/remoteproc:
  remoteproc/davinci: use the reset framework
  remoteproc/davinci: Mark error recovery as disabled
  remoteproc: st_slim: replace "%p" with "%pK"
  remoteproc: replace "%p" with "%pK"
  remoteproc: qcom: fix Q6V5_WCSS dependencies
  remoteproc: Reset table_ptr in rproc_start() failure paths
  remoteproc: qcom: q6v5-pil: fix modem hang on SDM845 after axis2 clk unvote
  remoteproc: qcom q6v5: fix modular build
  remoteproc: Introduce prepare and unprepare for subdevices
  remoteproc: rename subdev probe and remove functions
  remoteproc: Make client initialize ops in rproc_subdev
  remoteproc: Make start and stop in subdev optional
  remoteproc: Rename subdev functions to start/stop
  remoteproc: qcom: Introduce Hexagon V5 based WCSS driver
  remoteproc: qcom: q6v5-pil: Use common q6v5 helpers
  remoteproc: qcom: adsp: Use common q6v5 helpers
  remoteproc: q6v5: Extract common resource handling
  remoteproc: qcom: mdt_loader: Make the firmware authentication optional
parents 6eaac34f b2201ee5
......@@ -8,6 +8,7 @@ on the Qualcomm Hexagon core.
Value type: <string>
Definition: must be one of:
"qcom,q6v5-pil",
"qcom,ipq8074-wcss-pil"
"qcom,msm8916-mss-pil",
"qcom,msm8974-mss-pil"
"qcom,msm8996-mss-pil"
......@@ -50,11 +51,15 @@ on the Qualcomm Hexagon core.
Usage: required
Value type: <phandle>
Definition: reference to the reset-controller for the modem sub-system
reference to the list of 3 reset-controllers for the
wcss sub-system
- reset-names:
Usage: required
Value type: <stringlist>
Definition: must be "mss_restart"
Definition: must be "mss_restart" for the modem sub-system
Definition: must be "wcss_aon_reset", "wcss_reset", "wcss_q6_reset"
for the wcss syb-system
- cx-supply:
- mss-supply:
......
......@@ -93,6 +93,7 @@ config QCOM_ADSP_PIL
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
help
......@@ -102,6 +103,11 @@ config QCOM_ADSP_PIL
config QCOM_RPROC_COMMON
tristate
config QCOM_Q6V5_COMMON
tristate
depends on ARCH_QCOM
depends on QCOM_SMEM
config QCOM_Q6V5_PIL
tristate "Qualcomm Hexagon V5 Peripherial Image Loader"
depends on OF && ARCH_QCOM
......@@ -110,12 +116,29 @@ config QCOM_Q6V5_PIL
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
help
Say y here to support the Qualcomm Peripherial Image Loader for the
Hexagon V5 based remote processors.
config QCOM_Q6V5_WCSS
tristate "Qualcomm Hexagon based WCSS Peripheral Image Loader"
depends on OF && ARCH_QCOM
depends on QCOM_SMEM
depends on RPMSG_QCOM_SMD || (COMPILE_TEST && RPMSG_QCOM_SMD=n)
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
select QCOM_MDT_LOADER
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
help
Say y here to support the Qualcomm Peripheral Image Loader for the
Hexagon V5 based WCSS remote processors.
config QCOM_SYSMON
tristate "Qualcomm sysmon driver"
depends on RPMSG
......
......@@ -16,7 +16,9 @@ obj-$(CONFIG_DA8XX_REMOTEPROC) += da8xx_remoteproc.o
obj-$(CONFIG_KEYSTONE_REMOTEPROC) += keystone_remoteproc.o
obj-$(CONFIG_QCOM_ADSP_PIL) += qcom_adsp_pil.o
obj-$(CONFIG_QCOM_RPROC_COMMON) += qcom_common.o
obj-$(CONFIG_QCOM_Q6V5_COMMON) += qcom_q6v5.o
obj-$(CONFIG_QCOM_Q6V5_PIL) += qcom_q6v5_pil.o
obj-$(CONFIG_QCOM_Q6V5_WCSS) += qcom_q6v5_wcss.o
obj-$(CONFIG_QCOM_SYSMON) += qcom_sysmon.o
obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o
qcom_wcnss_pil-y += qcom_wcnss.o
......
......@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/reset.h>
#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/io.h>
......@@ -20,8 +21,6 @@
#include <linux/platform_device.h>
#include <linux/remoteproc.h>
#include <mach/clock.h> /* for davinci_clk_reset_assert/deassert() */
#include "remoteproc_internal.h"
static char *da8xx_fw_name;
......@@ -72,6 +71,7 @@ struct da8xx_rproc {
struct da8xx_rproc_mem *mem;
int num_mems;
struct clk *dsp_clk;
struct reset_control *dsp_reset;
void (*ack_fxn)(struct irq_data *data);
struct irq_data *irq_data;
void __iomem *chipsig;
......@@ -138,6 +138,7 @@ static int da8xx_rproc_start(struct rproc *rproc)
struct device *dev = rproc->dev.parent;
struct da8xx_rproc *drproc = (struct da8xx_rproc *)rproc->priv;
struct clk *dsp_clk = drproc->dsp_clk;
struct reset_control *dsp_reset = drproc->dsp_reset;
int ret;
/* hw requires the start (boot) address be on 1KB boundary */
......@@ -155,7 +156,12 @@ static int da8xx_rproc_start(struct rproc *rproc)
return ret;
}
davinci_clk_reset_deassert(dsp_clk);
ret = reset_control_deassert(dsp_reset);
if (ret) {
dev_err(dev, "reset_control_deassert() failed: %d\n", ret);
clk_disable_unprepare(dsp_clk);
return ret;
}
return 0;
}
......@@ -163,8 +169,15 @@ static int da8xx_rproc_start(struct rproc *rproc)
static int da8xx_rproc_stop(struct rproc *rproc)
{
struct da8xx_rproc *drproc = rproc->priv;
struct device *dev = rproc->dev.parent;
int ret;
ret = reset_control_assert(drproc->dsp_reset);
if (ret) {
dev_err(dev, "reset_control_assert() failed: %d\n", ret);
return ret;
}
davinci_clk_reset_assert(drproc->dsp_clk);
clk_disable_unprepare(drproc->dsp_clk);
return 0;
......@@ -232,6 +245,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
struct resource *bootreg_res;
struct resource *chipsig_res;
struct clk *dsp_clk;
struct reset_control *dsp_reset;
void __iomem *chipsig;
void __iomem *bootreg;
int irq;
......@@ -268,6 +282,15 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
return PTR_ERR(dsp_clk);
}
dsp_reset = devm_reset_control_get_exclusive(dev, NULL);
if (IS_ERR(dsp_reset)) {
if (PTR_ERR(dsp_reset) != -EPROBE_DEFER)
dev_err(dev, "unable to get reset control: %ld\n",
PTR_ERR(dsp_reset));
return PTR_ERR(dsp_reset);
}
if (dev->of_node) {
ret = of_reserved_mem_device_init(dev);
if (ret) {
......@@ -284,9 +307,13 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
goto free_mem;
}
/* error recovery is not supported at present */
rproc->recovery_disabled = true;
drproc = rproc->priv;
drproc->rproc = rproc;
drproc->dsp_clk = dsp_clk;
drproc->dsp_reset = dsp_reset;
rproc->has_iommu = false;
ret = da8xx_rproc_get_internal_memories(pdev, drproc);
......@@ -309,7 +336,7 @@ static int da8xx_rproc_probe(struct platform_device *pdev)
* *not* in reset, but da8xx_rproc_start() needs the DSP to be
* held in reset at the time it is called.
*/
ret = davinci_clk_reset_assert(drproc->dsp_clk);
ret = reset_control_assert(dsp_reset);
if (ret)
goto free_rproc;
......
......@@ -31,6 +31,7 @@
#include <linux/soc/qcom/smem_state.h>
#include "qcom_common.h"
#include "qcom_q6v5.h"
#include "remoteproc_internal.h"
struct adsp_data {
......@@ -48,14 +49,7 @@ struct qcom_adsp {
struct device *dev;
struct rproc *rproc;
int wdog_irq;
int fatal_irq;
int ready_irq;
int handover_irq;
int stop_ack_irq;
struct qcom_smem_state *state;
unsigned stop_bit;
struct qcom_q6v5 q6v5;
struct clk *xo;
struct clk *aggre2_clk;
......@@ -96,6 +90,8 @@ static int adsp_start(struct rproc *rproc)
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
int ret;
qcom_q6v5_prepare(&adsp->q6v5);
ret = clk_prepare_enable(adsp->xo);
if (ret)
return ret;
......@@ -119,16 +115,14 @@ static int adsp_start(struct rproc *rproc)
goto disable_px_supply;
}
ret = wait_for_completion_timeout(&adsp->start_done,
msecs_to_jiffies(5000));
if (!ret) {
ret = qcom_q6v5_wait_for_start(&adsp->q6v5, msecs_to_jiffies(5000));
if (ret == -ETIMEDOUT) {
dev_err(adsp->dev, "start timed out\n");
qcom_scm_pas_shutdown(adsp->pas_id);
ret = -ETIMEDOUT;
goto disable_px_supply;
}
ret = 0;
return 0;
disable_px_supply:
regulator_disable(adsp->px_supply);
......@@ -142,28 +136,34 @@ static int adsp_start(struct rproc *rproc)
return ret;
}
static void qcom_pas_handover(struct qcom_q6v5 *q6v5)
{
struct qcom_adsp *adsp = container_of(q6v5, struct qcom_adsp, q6v5);
regulator_disable(adsp->px_supply);
regulator_disable(adsp->cx_supply);
clk_disable_unprepare(adsp->aggre2_clk);
clk_disable_unprepare(adsp->xo);
}
static int adsp_stop(struct rproc *rproc)
{
struct qcom_adsp *adsp = (struct qcom_adsp *)rproc->priv;
int handover;
int ret;
qcom_smem_state_update_bits(adsp->state,
BIT(adsp->stop_bit),
BIT(adsp->stop_bit));
ret = wait_for_completion_timeout(&adsp->stop_done,
msecs_to_jiffies(5000));
if (ret == 0)
ret = qcom_q6v5_request_stop(&adsp->q6v5);
if (ret == -ETIMEDOUT)
dev_err(adsp->dev, "timed out on wait\n");
qcom_smem_state_update_bits(adsp->state,
BIT(adsp->stop_bit),
0);
ret = qcom_scm_pas_shutdown(adsp->pas_id);
if (ret)
dev_err(adsp->dev, "failed to shutdown: %d\n", ret);
handover = qcom_q6v5_unprepare(&adsp->q6v5);
if (handover)
qcom_pas_handover(&adsp->q6v5);
return ret;
}
......@@ -187,53 +187,6 @@ static const struct rproc_ops adsp_ops = {
.load = adsp_load,
};
static irqreturn_t adsp_wdog_interrupt(int irq, void *dev)
{
struct qcom_adsp *adsp = dev;
rproc_report_crash(adsp->rproc, RPROC_WATCHDOG);
return IRQ_HANDLED;
}
static irqreturn_t adsp_fatal_interrupt(int irq, void *dev)
{
struct qcom_adsp *adsp = dev;
size_t len;
char *msg;
msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, adsp->crash_reason_smem, &len);
if (!IS_ERR(msg) && len > 0 && msg[0])
dev_err(adsp->dev, "fatal error received: %s\n", msg);
rproc_report_crash(adsp->rproc, RPROC_FATAL_ERROR);
return IRQ_HANDLED;
}
static irqreturn_t adsp_ready_interrupt(int irq, void *dev)
{
return IRQ_HANDLED;
}
static irqreturn_t adsp_handover_interrupt(int irq, void *dev)
{
struct qcom_adsp *adsp = dev;
complete(&adsp->start_done);
return IRQ_HANDLED;
}
static irqreturn_t adsp_stop_ack_interrupt(int irq, void *dev)
{
struct qcom_adsp *adsp = dev;
complete(&adsp->stop_done);
return IRQ_HANDLED;
}
static int adsp_init_clock(struct qcom_adsp *adsp)
{
int ret;
......@@ -272,29 +225,6 @@ static int adsp_init_regulator(struct qcom_adsp *adsp)
return PTR_ERR_OR_ZERO(adsp->px_supply);
}
static int adsp_request_irq(struct qcom_adsp *adsp,
struct platform_device *pdev,
const char *name,
irq_handler_t thread_fn)
{
int ret;
ret = platform_get_irq_byname(pdev, name);
if (ret < 0) {
dev_err(&pdev->dev, "no %s IRQ defined\n", name);
return ret;
}
ret = devm_request_threaded_irq(&pdev->dev, ret,
NULL, thread_fn,
IRQF_ONESHOT,
"adsp", adsp);
if (ret)
dev_err(&pdev->dev, "request %s IRQ failed\n", name);
return ret;
}
static int adsp_alloc_memory_region(struct qcom_adsp *adsp)
{
struct device_node *node;
......@@ -348,13 +278,9 @@ static int adsp_probe(struct platform_device *pdev)
adsp->dev = &pdev->dev;
adsp->rproc = rproc;
adsp->pas_id = desc->pas_id;
adsp->crash_reason_smem = desc->crash_reason_smem;
adsp->has_aggre2_clk = desc->has_aggre2_clk;
platform_set_drvdata(pdev, adsp);
init_completion(&adsp->start_done);
init_completion(&adsp->stop_done);
ret = adsp_alloc_memory_region(adsp);
if (ret)
goto free_rproc;
......@@ -367,37 +293,10 @@ static int adsp_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;
ret = adsp_request_irq(adsp, pdev, "wdog", adsp_wdog_interrupt);
if (ret < 0)
goto free_rproc;
adsp->wdog_irq = ret;
ret = adsp_request_irq(adsp, pdev, "fatal", adsp_fatal_interrupt);
if (ret < 0)
goto free_rproc;
adsp->fatal_irq = ret;
ret = adsp_request_irq(adsp, pdev, "ready", adsp_ready_interrupt);
if (ret < 0)
goto free_rproc;
adsp->ready_irq = ret;
ret = adsp_request_irq(adsp, pdev, "handover", adsp_handover_interrupt);
if (ret < 0)
goto free_rproc;
adsp->handover_irq = ret;
ret = adsp_request_irq(adsp, pdev, "stop-ack", adsp_stop_ack_interrupt);
if (ret < 0)
goto free_rproc;
adsp->stop_ack_irq = ret;
adsp->state = qcom_smem_state_get(&pdev->dev, "stop",
&adsp->stop_bit);
if (IS_ERR(adsp->state)) {
ret = PTR_ERR(adsp->state);
ret = qcom_q6v5_init(&adsp->q6v5, pdev, rproc, desc->crash_reason_smem,
qcom_pas_handover);
if (ret)
goto free_rproc;
}
qcom_add_glink_subdev(rproc, &adsp->glink_subdev);
qcom_add_smd_subdev(rproc, &adsp->smd_subdev);
......@@ -422,7 +321,6 @@ static int adsp_remove(struct platform_device *pdev)
{
struct qcom_adsp *adsp = platform_get_drvdata(pdev);
qcom_smem_state_put(adsp->state);
rproc_del(adsp->rproc);
qcom_remove_glink_subdev(adsp->rproc, &adsp->glink_subdev);
......
......@@ -33,7 +33,7 @@
static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
static int glink_subdev_probe(struct rproc_subdev *subdev)
static int glink_subdev_start(struct rproc_subdev *subdev)
{
struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
......@@ -42,7 +42,7 @@ static int glink_subdev_probe(struct rproc_subdev *subdev)
return PTR_ERR_OR_ZERO(glink->edge);
}
static void glink_subdev_remove(struct rproc_subdev *subdev, bool crashed)
static void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed)
{
struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
......@@ -64,7 +64,10 @@ void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
return;
glink->dev = dev;
rproc_add_subdev(rproc, &glink->subdev, glink_subdev_probe, glink_subdev_remove);
glink->subdev.start = glink_subdev_start;
glink->subdev.stop = glink_subdev_stop;
rproc_add_subdev(rproc, &glink->subdev);
}
EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
......@@ -126,7 +129,7 @@ int qcom_register_dump_segments(struct rproc *rproc,
}
EXPORT_SYMBOL_GPL(qcom_register_dump_segments);
static int smd_subdev_probe(struct rproc_subdev *subdev)
static int smd_subdev_start(struct rproc_subdev *subdev)
{
struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
......@@ -135,7 +138,7 @@ static int smd_subdev_probe(struct rproc_subdev *subdev)
return PTR_ERR_OR_ZERO(smd->edge);
}
static void smd_subdev_remove(struct rproc_subdev *subdev, bool crashed)
static void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed)
{
struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
......@@ -157,7 +160,10 @@ void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
return;
smd->dev = dev;
rproc_add_subdev(rproc, &smd->subdev, smd_subdev_probe, smd_subdev_remove);
smd->subdev.start = smd_subdev_start;
smd->subdev.stop = smd_subdev_stop;
rproc_add_subdev(rproc, &smd->subdev);
}
EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
......@@ -202,11 +208,6 @@ void qcom_unregister_ssr_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
static int ssr_notify_start(struct rproc_subdev *subdev)
{
return 0;
}
static void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed)
{
struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
......@@ -227,8 +228,9 @@ void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
const char *ssr_name)
{
ssr->name = ssr_name;
ssr->subdev.stop = ssr_notify_stop;
rproc_add_subdev(rproc, &ssr->subdev, ssr_notify_start, ssr_notify_stop);
rproc_add_subdev(rproc, &ssr->subdev);
}
EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
......
// SPDX-License-Identifier: GPL-2.0
/*
* Qualcomm Peripheral Image Loader for Q6V5
*
* Copyright (C) 2016-2018 Linaro Ltd.
* Copyright (C) 2014 Sony Mobile Communications AB
* Copyright (c) 2012-2013, The Linux Foundation. All rights reserved.
*/
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/soc/qcom/smem.h>
#include <linux/soc/qcom/smem_state.h>
#include <linux/remoteproc.h>
#include "qcom_q6v5.h"
/**
* qcom_q6v5_prepare() - reinitialize the qcom_q6v5 context before start
* @q6v5: reference to qcom_q6v5 context to be reinitialized
*
* Return: 0 on success, negative errno on failure
*/
int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
{
reinit_completion(&q6v5->start_done);
reinit_completion(&q6v5->stop_done);
q6v5->running = true;
q6v5->handover_issued = false;
enable_irq(q6v5->handover_irq);
return 0;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_prepare);
/**
* qcom_q6v5_unprepare() - unprepare the qcom_q6v5 context after stop
* @q6v5: reference to qcom_q6v5 context to be unprepared
*
* Return: 0 on success, 1 if handover hasn't yet been called
*/
int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5)
{
disable_irq(q6v5->handover_irq);
return !q6v5->handover_issued;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_unprepare);
static irqreturn_t q6v5_wdog_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
size_t len;
char *msg;
/* Sometimes the stop triggers a watchdog rather than a stop-ack */
if (!q6v5->running) {
complete(&q6v5->stop_done);
return IRQ_HANDLED;
}
msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
if (!IS_ERR(msg) && len > 0 && msg[0])
dev_err(q6v5->dev, "watchdog received: %s\n", msg);
else
dev_err(q6v5->dev, "watchdog without message\n");
rproc_report_crash(q6v5->rproc, RPROC_WATCHDOG);
return IRQ_HANDLED;
}
static irqreturn_t q6v5_fatal_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
size_t len;
char *msg;
msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len);
if (!IS_ERR(msg) && len > 0 && msg[0])
dev_err(q6v5->dev, "fatal error received: %s\n", msg);
else
dev_err(q6v5->dev, "fatal error without message\n");
rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR);
return IRQ_HANDLED;
}
static irqreturn_t q6v5_ready_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
complete(&q6v5->start_done);
return IRQ_HANDLED;
}
/**
* qcom_q6v5_wait_for_start() - wait for remote processor start signal
* @q6v5: reference to qcom_q6v5 context
* @timeout: timeout to wait for the event, in jiffies
*
* qcom_q6v5_unprepare() should not be called when this function fails.
*
* Return: 0 on success, -ETIMEDOUT on timeout
*/
int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout)
{
int ret;
ret = wait_for_completion_timeout(&q6v5->start_done, timeout);
if (!ret)
disable_irq(q6v5->handover_irq);
return !ret ? -ETIMEDOUT : 0;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
if (q6v5->handover)
q6v5->handover(q6v5);
q6v5->handover_issued = true;
return IRQ_HANDLED;
}
static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
complete(&q6v5->stop_done);
return IRQ_HANDLED;
}
/**
* qcom_q6v5_request_stop() - request the remote processor to stop
* @q6v5: reference to qcom_q6v5 context
*
* Return: 0 on success, negative errno on failure
*/
int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5)
{
int ret;
q6v5->running = false;
qcom_smem_state_update_bits(q6v5->state,
BIT(q6v5->stop_bit), BIT(q6v5->stop_bit));
ret = wait_for_completion_timeout(&q6v5->stop_done, 5 * HZ);
qcom_smem_state_update_bits(q6v5->state, BIT(q6v5->stop_bit), 0);
return ret == 0 ? -ETIMEDOUT : 0;
}
EXPORT_SYMBOL_GPL(qcom_q6v5_request_stop);
/**
* qcom_q6v5_init() - initializer of the q6v5 common struct
* @q6v5: handle to be initialized
* @pdev: platform_device reference for acquiring resources
* @rproc: associated remoteproc instance
* @crash_reason: SMEM id for crash reason string, or 0 if none
* @handover: function to be called when proxy resources should be released
*
* Return: 0 on success, negative errno on failure
*/
int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
struct rproc *rproc, int crash_reason,
void (*handover)(struct qcom_q6v5 *q6v5))
{
int ret;
q6v5->rproc = rproc;
q6v5->dev = &pdev->dev;
q6v5->crash_reason = crash_reason;
q6v5->handover = handover;
init_completion(&q6v5->start_done);
init_completion(&q6v5->stop_done);
q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
ret = devm_request_threaded_irq(&pdev->dev, q6v5->wdog_irq,
NULL, q6v5_wdog_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 wdog", q6v5);
if (ret) {
dev_err(&pdev->dev, "failed to acquire wdog IRQ\n");
return ret;
}
q6v5->fatal_irq = platform_get_irq_byname(pdev, "fatal");
ret = devm_request_threaded_irq(&pdev->dev, q6v5->fatal_irq,
NULL, q6v5_fatal_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 fatal", q6v5);
if (ret) {
dev_err(&pdev->dev, "failed to acquire fatal IRQ\n");
return ret;
}
q6v5->ready_irq = platform_get_irq_byname(pdev, "ready");
ret = devm_request_threaded_irq(&pdev->dev, q6v5->ready_irq,
NULL, q6v5_ready_interrupt,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"q6v5 ready", q6v5);
if (ret) {
dev_err(&pdev->dev, "failed to acquire ready IRQ\n");
return ret;
}
q6v5->handover_irq = platform_get_irq_byname(pdev, "handover");
ret = devm_request_threaded_irq(&pdev->dev, q6v5->handover_irq,