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: 136619 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp450517lji; Tue, 22 May 2018 22:22:14 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrj9AyA4xc9B2ZSAo81IlpshqhfSuoU/EoC0q5dDyl+8r9IBLXS/gto5a5F0NSqxOA0IVkV X-Received: by 2002:a17:902:b488:: with SMTP id y8-v6mr261859plr.183.1527052934144; Tue, 22 May 2018 22:22:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527052934; cv=none; d=google.com; s=arc-20160816; b=wWInQA8qCr5+bJFfty/DxRsLz5hWNm40H0tVIgqOwfjhe49FkoyCZy6vJwxkTdgUf9 4iUF3/jAB3D+trB1R1Ujh98nDlXV9ck9hAZpFdL/lbd+03ZyOuljNiTh9o0TlyWyCe+C JNFdHW9Nrj6EEZbfPTzvEw5WSIOfcSnB/IpLvImNbNr6PZj6XjF36he/wPvIYw6nzGQG DQ69QCo/i/aSYbyxUNtSQr1HwWNO9EdVYaKQ9fSeo70FBo6H9kOFB4dhwoqOhRgeEzYF aPVPDG/LrP7BryQLWTRDhE2U3w7ZSBLrOQPFuFvxHwwteNFaUONynxgo44HyDfNYnyDt 80+A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=ZeprXwBIN1WpZGpP/S5ChZKNDekFto/8CiR+g99n/1A=; b=qy+Ya2kK+Ob5MCIY4+JnrvE5l0+KFEGO6nVYauf+xUG4z9Ltcb0gJHmNHf9lI0lOeV 3viN0A9T16Y5RFJrbArrvfKnK/NH+b/3XNIA4Dc0h9Nw/bKXhF7AHgzffxgRUMXzOkyh E7+TFaXoH8RuZrJ83QamfRYTbdmnIjcVFBQx1RwZNns2gu3o8i78ltHRHWr65WRWgoot oBMT0x16htkRjG8abfi2WT6XaL7arbW9Vj/HZmbnOXfzFZtxNsj17DnINyEtWNvfOR26 Q1SJ+VldHxYtUKRK2wNETLS7eAdaYI78x7KmZWmKmFfDekmVc6cGQ85VL9xiMk+vdGho QrSw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=J5+GT2ro; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q7-v6si17875323pls.286.2018.05.22.22.22.13; Tue, 22 May 2018 22:22:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=J5+GT2ro; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754126AbeEWFWL (ORCPT + 30 others); Wed, 23 May 2018 01:22:11 -0400 Received: from mail-pl0-f68.google.com ([209.85.160.68]:36704 "EHLO mail-pl0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754075AbeEWFVB (ORCPT ); Wed, 23 May 2018 01:21:01 -0400 Received: by mail-pl0-f68.google.com with SMTP id v24-v6so12282702plo.3 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=ii4mXqG5vpfcII/luvWRUoInRJCIe7PWl4ank6+DO7yS6QXlTSfuKP/w80MlljMduw KetZvHdUk8C2Nb1ZoQutRQJ5ebXecp4gAdUub60x4jrt6lXeE+9Koxw+tPr5eFJq+/Si rZZ+8rdbp5iYwy/sL2iLe/L9K+1CXNdW2SsBumUGB5U02PE+0MlBZfxSaiTnqsGvtMVa wG/ttemf/zxyUGvTPw8TdbY4wsS2ACknBb2Xix8IIwDXNu9v7HJxBfUhb1N4TMnfGPVk tsgyI7rEltWf9dLUKkScQJpLM+ThP266MlWcSa+L15+0ImpbkVzh8ep1gzNYvR0RXCWF 7n9Q== X-Gm-Message-State: ALKqPwdTkVm2ajC7hG16k/qKIc55Er9+PcAM5ri8WKH2iZmrgVPAUlgi VtTrPK2YeadGR71hNtZufXqZ4w== 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-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 -- 2.17.0 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