From patchwork Wed May 23 05:20:51 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 10420205 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 05B896016C for ; Wed, 23 May 2018 05:22:15 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E8854290A2 for ; Wed, 23 May 2018 05:22:14 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DDDE0290B0; Wed, 23 May 2018 05:22:14 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-7.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, MAILING_LIST_MULTI, RCVD_IN_DNSWL_HI, T_DKIM_INVALID autolearn=unavailable version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3DEE6290A4 for ; Wed, 23 May 2018 05:22:14 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754031AbeEWFWM (ORCPT ); Wed, 23 May 2018 01:22:12 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:33900 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754073AbeEWFVB (ORCPT ); Wed, 23 May 2018 01:21:01 -0400 Received: by mail-pl0-f68.google.com with SMTP id ay10-v6so12288333plb.1 for ; Tue, 22 May 2018 22:21:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ZeprXwBIN1WpZGpP/S5ChZKNDekFto/8CiR+g99n/1A=; b=J5+GT2roFFRq9yoINs1fJ/4VJNc87o4GTJDGgQJ6iBAZGLa3dN3zdWsR5P2cM37Kzs Uxxj2ITxZcpl6dUwRHn26TP1coUhjt63q7GRBWlua7JgHyibJz8P8tvfgykVwXrOILCU ZBKEz/Zrwj3C18HeXockFJK8y326l7tY+7Q7E= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ZeprXwBIN1WpZGpP/S5ChZKNDekFto/8CiR+g99n/1A=; b=b/SvcBDP3uKxpCEy4DT7B70Ld7SOZF5gBLMjie7k20z+/wmz2Z/894JPRywgcoXxYK tOEfCrHJ/W8uWHcdJNoyWlN01jyGSzE9uSBaI8FbgOeuATFhjBZK5NYUIf+sdHrr9fpj xPCcFjjFXCbaXnj9F/HffYhyXpAUtTzHVxBN42tKuek0Q0U/LskGuAoqALuaBMAtpF6l xi115gVswVRTNldF22LKhl4YhjuFYCz9wuZ5/fC05/lrOTha6j+DfC5VNzlX/DgI2uGn PCbEiY4p/Zfg8HAEC5Rxyg+6lgYniwsoZ3BPduos143GdX0c1gL53Fsj4aOYjx8mxaQb N/aw== X-Gm-Message-State: ALKqPwfwFf8fYb8T/+Nkj8PXLjs0+k7wAEGaYrSZj+gbqf1SCTGi/Ksz cmeQDjpVZO+xv6gVG7l9Mkh7OA== X-Google-Smtp-Source: AB8JxZq6nkyzFSi3GwG5hgCSX1ILYmbIGcGmTag4WLzMnpGpATyNhHlnvgFzV3PHCvqRkGJUh5+zMg== X-Received: by 2002:a17:902:2983:: with SMTP id h3-v6mr1468162plb.232.1527052860975; Tue, 22 May 2018 22:21:00 -0700 (PDT) Received: from localhost.localdomain (104-188-17-28.lightspeed.sndgca.sbcglobal.net. [104.188.17.28]) by smtp.gmail.com with ESMTPSA id r76-v6sm34401146pfl.1.2018.05.22.22.20.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 May 2018 22:21:00 -0700 (PDT) From: Bjorn Andersson To: Ohad Ben-Cohen , Bjorn Andersson , Sricharan R , Sibi Sankar , Rohit kumar Cc: Andy Gross , linux-kernel@vger.kernel.org, linux-remoteproc@vger.kernel.org, linux-arm-msm@vger.kernel.org Subject: [RFC PATCH 2/5] remoteproc: q6v5: Extract common resource handling Date: Tue, 22 May 2018 22:20:51 -0700 Message-Id: <20180523052054.19025-3-bjorn.andersson@linaro.org> X-Mailer: git-send-email 2.17.0 In-Reply-To: <20180523052054.19025-1-bjorn.andersson@linaro.org> References: <20180523052054.19025-1-bjorn.andersson@linaro.org> Sender: linux-remoteproc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-remoteproc@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP Shared between all Hexagon V5 based remoteprocs is the handling of the 5 interrupts and the SMP2P stop request, so break this out into a separate function in order to allow these drivers to be cleaned up. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 5 + drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5.c | 243 +++++++++++++++++++++++++++++++++ drivers/remoteproc/qcom_q6v5.h | 46 +++++++ 4 files changed, 295 insertions(+) create mode 100644 drivers/remoteproc/qcom_q6v5.c create mode 100644 drivers/remoteproc/qcom_q6v5.h diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index cd1c168fd188..63b79ea91a21 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -102,6 +102,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 diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 02627ede8d4a..5dd0249cf76a 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -16,6 +16,7 @@ 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_SYSMON) += qcom_sysmon.o obj-$(CONFIG_QCOM_WCNSS_PIL) += qcom_wcnss_pil.o diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c new file mode 100644 index 000000000000..9076537a1671 --- /dev/null +++ b/drivers/remoteproc/qcom_q6v5.c @@ -0,0 +1,243 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Qualcomm Peripheral Image Loader for Q6V5 WCSS + * + * Copyright (C) 2016-2018 Linaro Ltd. + * Copyright (C) 2014 Sony Mobile Communications AB + * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#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; +} + +/** + * 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; +} + +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_FATAL_ERROR); + + 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; +} + +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; +} + +/** + * 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, + NULL, q6v5_handover_interrupt, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "q6v5 handover", q6v5); + if (ret) { + dev_err(&pdev->dev, "failed to acquire handover IRQ\n"); + return ret; + } + disable_irq(q6v5->handover_irq); + + q6v5->stop_irq = platform_get_irq_byname(pdev, "stop-ack"); + ret = devm_request_threaded_irq(&pdev->dev, q6v5->stop_irq, + NULL, q6v5_stop_interrupt, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "q6v5 stop", q6v5); + if (ret) { + dev_err(&pdev->dev, "failed to acquire stop-ack IRQ\n"); + return ret; + } + + q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit); + if (IS_ERR(q6v5->state)) { + dev_err(&pdev->dev, "failed to acquire stop state\n"); + return PTR_ERR(q6v5->state); + } + + return 0; +} diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h new file mode 100644 index 000000000000..7ac92c1e0f49 --- /dev/null +++ b/drivers/remoteproc/qcom_q6v5.h @@ -0,0 +1,46 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCOM_Q6V5_H__ +#define __QCOM_Q6V5_H__ + +#include +#include + +struct rproc; +struct qcom_smem_state; + +struct qcom_q6v5 { + struct device *dev; + struct rproc *rproc; + + struct qcom_smem_state *state; + unsigned stop_bit; + + int wdog_irq; + int fatal_irq; + int ready_irq; + int handover_irq; + int stop_irq; + + bool handover_issued; + + struct completion start_done; + struct completion stop_done; + + int crash_reason; + + bool running; + + void (*handover)(struct qcom_q6v5 *q6v5); +}; + +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 qcom_q6v5_prepare(struct qcom_q6v5 *q6v5); +int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5); +int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5); +int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout); + +#endif