From patchwork Wed May 23 05:20:52 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 136618 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp450167lji; Tue, 22 May 2018 22:21:45 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpIbfz5m9PMM0SrwHJpZliN3W68DUkuH3B81zibbcE2+WoPdmWp2viDz97nILQW/6JnoGgV X-Received: by 2002:a63:701b:: with SMTP id l27-v6mr1147359pgc.145.1527052905502; Tue, 22 May 2018 22:21:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527052905; cv=none; d=google.com; s=arc-20160816; b=0JqM12zoKSFbvHCgcDPXZoME9gpXMGw8ThnsM+qnIr4F7fOaD5Tuuo+oqVXEKRP6RW OLKv5o9aimeCD27reUDzhpgZH1WzTKbc4lzrVOBRi6OzQv+WuEuYbtcwCcy51RZ6HDSu eaGr1FtHkJK39C9fqmHc82yx9QE4MlVfPMqxhQw/PcfN5/hqz3dUL0cFFJHISlWsA8u8 AGJl+BnGNH8c4AOyYzQMLpxhEFbt0Fjfcd2IZe2OY7XCOpJgF1sE2Q7iCnI3+fhIEjM7 eN30Sv1RZb3p5mbs+aGy6wPBIFDkRUowdH1zkYcYPIzprS8Vc6kBoUAZ56/oQeOXSLoC MaBA== 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=E9a/ln6rN9zciYHtjKuNDj/KXQMF0e/6wY8x2Mazhxs=; b=WUxpuUhzcAe2QP64C/WgR9pmj6L1ljefdhemdQKeUq0jEyDtgwMMtMuxud5uxK0cOV jsSC+Tl/z/wNd7kU5Vnq4sqnmZfH81fVyhmjqHIATFb5NCx9hzkXZl17lXJecIuyscFI MCVzGL23VYrP3XDQFhNT1VHsjKISRERQtaOj08sxv+YZCtH7RaOxpyHz63hf1b7CoGIB plz6AOpEcknpX6WbMj6QbFuVr01+FT2Xe0vg+cabyuxZJBujYQEs11e6YIypxPCoXORw GKYoS9APznsZW/GmOW0pMVWUXv3VvA9zd47a4f4t3kpf9B6yNp7wDO8nUuVyjrewKE1N wZ1w== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=OrLAlC48; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (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 y5-v6si11141487pgq.276.2018.05.22.22.21.45; Tue, 22 May 2018 22:21:45 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=OrLAlC48; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932067AbeEWFVk (ORCPT + 13 others); Wed, 23 May 2018 01:21:40 -0400 Received: from mail-pg0-f67.google.com ([74.125.83.67]:38121 "EHLO mail-pg0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754083AbeEWFVD (ORCPT ); Wed, 23 May 2018 01:21:03 -0400 Received: by mail-pg0-f67.google.com with SMTP id n9-v6so8873336pgq.5 for ; Tue, 22 May 2018 22:21:02 -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=4hmV56D5pM+iajC2qqe4z96PIgpcRdLUZl2I093zQwY=; b=OrLAlC48m98fy05hztdT72VscJ46VeLqWsK6H90YSc8stK0rROqgg0UpRtM2EMn9bd pjuklKY4mmHoT+j1QAgnNnK4g19153uNI0Hk/3cr0zOcH2Ml8upps5fqQVR8OSqxsNOz j0o7+LSTARUAkJSvNG+E4ahlVQJr8Du/jcPOA= 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=4hmV56D5pM+iajC2qqe4z96PIgpcRdLUZl2I093zQwY=; b=nrEF2S45GwXPhhF3UgMmtxgcVE+ycN5ozBpEOcM6DsYktimssytsJY6Sr86IuhT0rD 0UZVPOPgv9Sw+8fkm1r8dY7zZWfLnOIm2sdGYkBVuUyxFAXXXlaFPKoyQzbMz+TjTbae 0PUZAqpZPvTAydhxoolJHqiCUTtAyj6ZLsnQKW6xvX2oUuxFyJA2GGLzccP8HXwcw86T 8GB1GZCJonu9OPs3fcPm5fI6lz5Boz0LfWnIiCmA1RWdBt0iEl0qZq9tQdA1y8Rp5u7S W2se2F35iWMHu4FTNui+49zmsOqmlCFsZi37+BnV83pjJH+0xgLdWfUsKZyxLW13Sghh VrXw== X-Gm-Message-State: ALKqPwdMNkv4s87f/X9WfjOxVzjs7aw8M9it3LjRZF2p3I1uoXs2TWOa fBxuYQsOWHNtrSZfBKqcanreVQ== X-Received: by 2002:a62:f20d:: with SMTP id m13-v6mr1425166pfh.170.1527052862044; Tue, 22 May 2018 22:21:02 -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.21.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 May 2018 22:21:01 -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 3/5] remoteproc: qcom: adsp: Use common q6v5 helpers Date: Tue, 22 May 2018 22:20:52 -0700 Message-Id: <20180523052054.19025-4-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-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org Migrate the Hexagon V5 PAS (ADSP) driver to using the newly extracted helper functions. The use of the handover callback does introduce latent disabling of proxy resources. But apart from this there should be no change in functionality. Signed-off-by: Bjorn Andersson --- drivers/remoteproc/Kconfig | 1 + drivers/remoteproc/qcom_adsp_pil.c | 156 +++++------------------------ 2 files changed, 28 insertions(+), 129 deletions(-) -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 63b79ea91a21..d51d155cf8bd 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -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 diff --git a/drivers/remoteproc/qcom_adsp_pil.c b/drivers/remoteproc/qcom_adsp_pil.c index 89a86ce07f99..d4339a6da616 100644 --- a/drivers/remoteproc/qcom_adsp_pil.c +++ b/drivers/remoteproc/qcom_adsp_pil.c @@ -31,6 +31,7 @@ #include #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); From patchwork Wed May 23 05:20:54 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Bjorn Andersson X-Patchwork-Id: 136616 Delivered-To: patch@linaro.org Received: by 2002:a2e:9706:0:0:0:0:0 with SMTP id r6-v6csp449908lji; Tue, 22 May 2018 22:21:22 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpmFcxfwadShAAWiZYoBTFEcIpaJ7hlC27mgF+RU5JfZAEp+UEzAKLpsih0uS3bruVRp3uj X-Received: by 2002:a62:d751:: with SMTP id v17-v6mr1400816pfl.39.1527052882469; Tue, 22 May 2018 22:21:22 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1527052882; cv=none; d=google.com; s=arc-20160816; b=VglAISNBxaLHUB/2iIxRx8BoJw3IUvxuJfrtD4TubEGYsM2eZynPx/STpSJ45pFzhs nHFQTkuFBLBJGqeKh2XAk4JiRd0RHC5t3iOeG4CoOgpUozx+OHPbhHiQxxgl6KjTEWpY ixWlhNLszOISksz9v0D0wYCH/BXyuhczHyFnFjpbo98xaMbkguoDVRXJt8dYKUAoAsqb ATweNcJCdMvpuEQd9N8dIFg9uTXgWwV4zGA91Ft4xIMH2w6eEWxlr6JMC/nOAEpzdc5F HkdEvzEmhNT4l2PhzZuECT5RXp6E+fDNh0a5VP62rbS1l1SQQhMqr0YPnk/kEJvZ3RwM P+mQ== 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=ZTctqjMjNGjiZWu7yRPhaoRcpphPeeUzwDItgN6Eh/Y=; b=qKvTfqe9L9XewmWXwEKqjkNRzeTHl2i4FePEYf5oblYz+Dn1/DwvgXtC7TXaILX0t2 A/527p6ywlcS1TiZfy0VRa/xn+8HNSJSZxlLlZAplGJi1mXGO/DopwehmUEKHJBsg/Ul IGaWYCdkcQA69uG/3dHhP3H0xksp1Bo1g7GUAfYJCRkLpqdo3tb1hthqu+ZcsghwUb19 24F/BzkCOOmlTCj+HAPkVtfudt7HVPeqfQebfVmgrM9EeLKu7aIWSmPTpq+ANCSGUF3s gc2YqTqOoOQUAaHKFvqLeJaKn1NL2O1trRnFbdy7e7vYvVHZIw5THzg/yrsk0ASILe9r dG8A== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=HecZBv6d; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (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 e125-v6si17937518pfg.112.2018.05.22.22.21.22; Tue, 22 May 2018 22:21:22 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@linaro.org header.s=google header.b=HecZBv6d; spf=pass (google.com: best guess record for domain of linux-arm-msm-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-arm-msm-owner@vger.kernel.org; dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754071AbeEWFVU (ORCPT + 13 others); Wed, 23 May 2018 01:21:20 -0400 Received: from mail-pg0-f68.google.com ([74.125.83.68]:42915 "EHLO mail-pg0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754096AbeEWFVF (ORCPT ); Wed, 23 May 2018 01:21:05 -0400 Received: by mail-pg0-f68.google.com with SMTP id p9-v6so8864843pgc.9 for ; Tue, 22 May 2018 22:21:05 -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=RMN0xgIyLuO3Gldtiscnzw9o+gStzzRj6N8ZrlxkUdI=; b=HecZBv6dd00WJhJ2NUnS62gwZn7Y0bhX0H5nx/IBq2tl1bsJCICDnIy7BVSngKJ6ti 1qrGxm74a8D10s4CKSVsy80UhTmN4ePUKEY9MxwnWmzivDBBxlvCQjjqMX5Bso8AaINm IrI0BhNFJeg2hLXqF1y7rDvH047JI/UPtsEEw= 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=RMN0xgIyLuO3Gldtiscnzw9o+gStzzRj6N8ZrlxkUdI=; b=IVPME8BeoHtegUEWqH1/FV1DuH5Vqvpkwbu6uY1sYZyaPUas/HblKsIWrBmAJnxn2i gBPdYTJEpR7FthjH4ieIfy8Vzoc+cCQ38g52SSf/QgFViVRSJi8/avQl08SyPcuzvOSJ Rl0+fJN7wE7+syHipUMC/f/olqCsw5fsFjoy2k2M26p23Sdw3Mxl5fQCkUZsVUH2ejSE pybaGSVXUPCHxz52h34oPt3b9JpnU15jfiqq5Anrt4R8TEGzlPjkAXpsyN9BEqCYN3os 6G9h8yuIF9bY5wacGzUvcJBMR8R6MZdvMo4y2fAJPMyxuUiOHkv4YfMkestpaqHXiyMz PmYg== X-Gm-Message-State: ALKqPwcbZbifb0OnQKVH4lKh3LkLsgmSoIpgZ/u/cc/sdaGiTI3XpQf6 //7KVRQrg1MIRRQ6SoxVD1VBfQ== X-Received: by 2002:a62:449c:: with SMTP id m28-v6mr1398178pfi.145.1527052864301; Tue, 22 May 2018 22:21:04 -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.21.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 22 May 2018 22:21:03 -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 5/5] remoteproc: qcom: Introduce Hexagon V5 based WCSS driver Date: Tue, 22 May 2018 22:20:54 -0700 Message-Id: <20180523052054.19025-6-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-arm-msm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-arm-msm@vger.kernel.org From: Sricharan R IPQ8074 has an integrated Hexagon dsp core q6v5 and a wireless lan (Lithium) IP. An mdt type single image format is used for the firmware. So the mdt_load function can be directly used to load the firmware. Also add the relevant resets required for this core. Signed-off-by: Sricharan R [bjorn: Rewrote as a separate driver, intead of extending q6v5_pil.c] Signed-off-by: Bjorn Andersson --- Due to lack of hardware this is only compile tested. So I'm interested in both feedback on the approach and testing of this. drivers/remoteproc/Kconfig | 15 +- drivers/remoteproc/Makefile | 1 + drivers/remoteproc/qcom_q6v5_wcss.c | 580 ++++++++++++++++++++++++++++ 3 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 drivers/remoteproc/qcom_q6v5_wcss.c -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig index 2316908e9788..4b55bfcfc8e1 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -119,12 +119,25 @@ config QCOM_Q6V5_PIL 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 Peripherial Image Loader for the - Hexagon V5 based remote processors. + Hexagon V5 based WCSS remote processors. config QCOM_SYSMON tristate "Qualcomm sysmon driver" diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile index 5dd0249cf76a..03332fa7e2ee 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -18,6 +18,7 @@ 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 diff --git a/drivers/remoteproc/qcom_q6v5_wcss.c b/drivers/remoteproc/qcom_q6v5_wcss.c new file mode 100644 index 000000000000..f0b38eae52df --- /dev/null +++ b/drivers/remoteproc/qcom_q6v5_wcss.c @@ -0,0 +1,580 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2016-2018 Linaro Ltd. + * Copyright (C) 2014 Sony Mobile Communications AB + * Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "qcom_common.h" +#include "qcom_q6v5.h" + +#define WCSS_CRASH_REASON 421 + +/* QDSP6SS Register Offsets */ +#define QDSP6SS_RESET_REG 0x014 +#define QDSP6SS_GFMUX_CTL_REG 0x020 +#define QDSP6SS_PWR_CTL_REG 0x030 +#define QDSP6SS_MEM_PWR_CTL 0x0B0 + +/* AXI Halt Register Offsets */ +#define AXI_HALTREQ_REG 0x0 +#define AXI_HALTACK_REG 0x4 +#define AXI_IDLE_REG 0x8 + +#define HALT_ACK_TIMEOUT_MS 100 + +/* QDSP6SS_RESET */ +#define Q6SS_STOP_CORE BIT(0) +#define Q6SS_CORE_ARES BIT(1) +#define Q6SS_BUS_ARES_ENABLE BIT(2) + +/* QDSP6SS_GFMUX_CTL */ +#define Q6SS_CLK_ENABLE BIT(1) + +/* QDSP6SS_PWR_CTL */ +#define Q6SS_L2DATA_STBY_N BIT(18) +#define Q6SS_SLP_RET_N BIT(19) +#define Q6SS_CLAMP_IO BIT(20) +#define QDSS_BHS_ON BIT(21) + +/* QDSP6v56 parameters */ +#define QDSP6v56_LDO_BYP BIT(25) +#define QDSP6v56_BHS_ON BIT(24) +#define QDSP6v56_CLAMP_WL BIT(21) +#define QDSP6v56_CLAMP_QMC_MEM BIT(22) +#define HALT_CHECK_MAX_LOOPS 200 +#define QDSP6SS_XO_CBCR 0x0038 + +/* QDSP6v5-WCSS config/status registers */ +#define TCSR_GLOBAL_CFG0 0x0 +#define TCSR_GLOBAL_CFG1 0x4 +#define SSCAON_CONFIG 0x8 +#define SSCAON_STATUS 0xc +#define QDSP6SS_BHS_STATUS 0x78 +#define QDSP6SS_RST_EVB 0x10 + +#define BHS_EN_REST_ACK BIT(0) +#define SSCAON_ENABLE BIT(13) + + +struct q6v5_wcss { + struct device *dev; + + void __iomem *reg_base; + void __iomem *rmb_base; + + struct regmap *halt_map; + u32 halt_q6; + u32 halt_wcss; + u32 halt_nc; + + struct reset_control *wcss_aon_reset; + struct reset_control *wcss_reset; + struct reset_control *wcss_q6_reset; + + struct qcom_q6v5 q6v5; + + phys_addr_t mem_phys; + phys_addr_t mem_reloc; + void *mem_region; + size_t mem_size; +}; + +static int q6v5_wcss_reset(struct q6v5_wcss *wcss) +{ + int ret; + u32 val; + int i; + + /* Assert resets, stop core */ + val = readl(wcss->reg_base + QDSP6SS_RESET_REG); + val |= Q6SS_CORE_ARES | Q6SS_BUS_ARES_ENABLE | Q6SS_STOP_CORE; + writel(val, wcss->reg_base + QDSP6SS_RESET_REG); + + /* BHS require xo cbcr to be enabled */ + val = readl(wcss->reg_base + QDSP6SS_XO_CBCR); + val |= 0x1; + writel(val, wcss->reg_base + QDSP6SS_XO_CBCR); + + /* Read CLKOFF bit to go low indicating CLK is enabled */ + ret = readl_poll_timeout(wcss->reg_base + QDSP6SS_XO_CBCR, + val, !(val & BIT(31)), 1, + HALT_CHECK_MAX_LOOPS); + if (ret) { + dev_err(wcss->dev, + "xo cbcr enabling timed out (rc:%d)\n", ret); + return ret; + } + /* Enable power block headswitch and wait for it to stabilize */ + val = readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val |= QDSP6v56_BHS_ON; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val |= readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + udelay(1); + + /* Put LDO in bypass mode */ + val |= QDSP6v56_LDO_BYP; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Deassert QDSP6 compiler memory clamp */ + val = readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val &= ~QDSP6v56_CLAMP_QMC_MEM; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Deassert memory peripheral sleep and L2 memory standby */ + val |= Q6SS_L2DATA_STBY_N | Q6SS_SLP_RET_N; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Turn on L1, L2, ETB and JU memories 1 at a time */ + val = readl(wcss->reg_base + QDSP6SS_MEM_PWR_CTL); + for (i = 19; i >= 0; i--) { + val |= BIT(i); + writel(val, wcss->reg_base + QDSP6SS_MEM_PWR_CTL); + /* + * Read back value to ensure the write is done then + * wait for 1us for both memory peripheral and data + * array to turn on. + */ + val |= readl(wcss->reg_base + QDSP6SS_MEM_PWR_CTL); + udelay(1); + } + /* Remove word line clamp */ + val = readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val &= ~QDSP6v56_CLAMP_WL; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Remove IO clamp */ + val &= ~Q6SS_CLAMP_IO; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* Bring core out of reset */ + val = readl(wcss->reg_base + QDSP6SS_RESET_REG); + val &= ~Q6SS_CORE_ARES; + writel(val, wcss->reg_base + QDSP6SS_RESET_REG); + + /* Turn on core clock */ + val = readl(wcss->reg_base + QDSP6SS_GFMUX_CTL_REG); + val |= Q6SS_CLK_ENABLE; + writel(val, wcss->reg_base + QDSP6SS_GFMUX_CTL_REG); + + /* Start core execution */ + val = readl(wcss->reg_base + QDSP6SS_RESET_REG); + val &= ~Q6SS_STOP_CORE; + writel(val, wcss->reg_base + QDSP6SS_RESET_REG); + + return 0; +} + +static int q6v5_wcss_start(struct rproc *rproc) +{ + struct q6v5_wcss *wcss = rproc->priv; + int ret; + + qcom_q6v5_prepare(&wcss->q6v5); + + /* Release Q6 and WCSS reset */ + ret = reset_control_deassert(wcss->wcss_reset); + if (ret) + dev_err(wcss->dev, "wcss_reset failed\n"); + + ret = reset_control_deassert(wcss->wcss_q6_reset); + if (ret) + dev_err(wcss->dev, "wcss_q6_reset failed\n"); + + /* Lithium configuration - clock gating and bus arbitration */ + ret = regmap_update_bits(wcss->halt_map, + wcss->halt_nc + TCSR_GLOBAL_CFG0, + 0x1F, 0x14); + if (ret) + return ret; + + ret = regmap_update_bits(wcss->halt_map, + wcss->halt_nc + TCSR_GLOBAL_CFG1, + 1, 0); + if (ret) + return ret; + + /* Write bootaddr to EVB so that Q6WCSS will jump there after reset */ + writel(rproc->bootaddr >> 4, wcss->reg_base + QDSP6SS_RST_EVB); + + ret = q6v5_wcss_reset(wcss); + if (ret) + return ret; + + ret = qcom_q6v5_wait_for_start(&wcss->q6v5, 5 * HZ); + if (ret == -ETIMEDOUT) + dev_err(wcss->dev, "start timed out\n"); + + return ret; +} + +static void q6v5_wcss_halt_axi_port(struct q6v5_wcss *wcss, + struct regmap *halt_map, + u32 offset) +{ + unsigned long timeout; + unsigned int val; + int ret; + + /* Check if we're already idle */ + ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); + if (!ret && val) + return; + + /* Assert halt request */ + regmap_write(halt_map, offset + AXI_HALTREQ_REG, 1); + + /* Wait for halt */ + timeout = jiffies + msecs_to_jiffies(HALT_ACK_TIMEOUT_MS); + for (;;) { + ret = regmap_read(halt_map, offset + AXI_HALTACK_REG, &val); + if (ret || val || time_after(jiffies, timeout)) + break; + + msleep(1); + } + + ret = regmap_read(halt_map, offset + AXI_IDLE_REG, &val); + if (ret || !val) + dev_err(wcss->dev, "port failed halt\n"); + + /* Clear halt request (port will remain halted until reset) */ + regmap_write(halt_map, offset + AXI_HALTREQ_REG, 0); +} + +static int q6v5_wcss_powerdown(struct q6v5_wcss *wcss) +{ + int ret; + u32 val; + + /* 1 - Assert WCSS/Q6 HALTREQ */ + q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_wcss); + + /* 2 - Enable WCSSAON_CONFIG */ + val = readl(wcss->rmb_base + SSCAON_CONFIG); + val |= SSCAON_ENABLE; + writel(val, wcss->rmb_base + SSCAON_CONFIG); + + /* 3 - Set SSCAON_CONFIG */ + val |= BIT(15); + val &= ~BIT(16); + val &= ~BIT(17); + val &= ~BIT(18); + writel(val, wcss->rmb_base + SSCAON_CONFIG); + + /* 4 - SSCAON_CONFIG 1 */ + val |= BIT(1); + writel(val, wcss->rmb_base + SSCAON_CONFIG); + + /* 5 - wait for SSCAON_STATUS */ + ret = readl_poll_timeout(wcss->rmb_base + SSCAON_STATUS, + val, (val & 0xffff) == 0x400, 1000, + HALT_CHECK_MAX_LOOPS); + if (ret) { + dev_err(wcss->dev, + "can't get SSCAON_STATUS rc:%d)\n", ret); + } + + /* 6 - De-assert WCSS_AON reset */ + reset_control_assert(wcss->wcss_aon_reset); + + /* 7 - Disable WCSSAON_CONFIG 13 */ + val = readl(wcss->rmb_base + SSCAON_CONFIG); + val &= ~SSCAON_ENABLE; + writel(val, wcss->rmb_base + SSCAON_CONFIG); + + /* 8 - De-assert WCSS/Q6 HALTREQ */ + reset_control_assert(wcss->wcss_reset); + + return ret; +} + +static int q6v5_q6_powerdown(struct q6v5_wcss *wcss) +{ + int ret; + u32 val; + int i; + + /* 1 - Halt Q6 bus interface */ + q6v5_wcss_halt_axi_port(wcss, wcss->halt_map, wcss->halt_q6); + + /* 2 - Disable Q6 Core clock */ + val = readl(wcss->reg_base + QDSP6SS_GFMUX_CTL_REG); + val &= ~Q6SS_CLK_ENABLE; + writel(val, wcss->reg_base + QDSP6SS_GFMUX_CTL_REG); + + /* 3 - Clamp I/O */ + val = readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val |= Q6SS_CLAMP_IO; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* 4 - Clamp WL */ + val |= QDSS_BHS_ON; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* 5 - Clear Erase standby */ + val &= ~Q6SS_L2DATA_STBY_N; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* 6 - Clear Sleep RTN */ + val &= ~Q6SS_SLP_RET_N; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* 7 - turn off QDSP6 memory foot/head switch one bank at a time */ + for (i = 0; i < 20; i++) { + val = readl(wcss->reg_base + QDSP6SS_MEM_PWR_CTL); + val &= ~BIT(i); + writel(val, wcss->reg_base + QDSP6SS_MEM_PWR_CTL); + mdelay(1); + } + /* 8 - Assert QMC memory RTN */ + val = readl(wcss->reg_base + QDSP6SS_PWR_CTL_REG); + val |= QDSP6v56_CLAMP_QMC_MEM; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + + /* 9 - Turn off BHS */ + val &= ~QDSP6v56_BHS_ON; + writel(val, wcss->reg_base + QDSP6SS_PWR_CTL_REG); + udelay(1); + /* 10 - Wait till BHS Reset is done */ + ret = readl_poll_timeout(wcss->reg_base + QDSP6SS_BHS_STATUS, + val, !(val & BHS_EN_REST_ACK), 1000, + HALT_CHECK_MAX_LOOPS); + if (ret) + dev_err(wcss->dev, "BHS_STATUS not OFF (rc:%d)\n", ret); + + /* 11 - Assert WCSS reset */ + reset_control_assert(wcss->wcss_reset); + + /* 12 - Assert Q6 reset */ + reset_control_assert(wcss->wcss_q6_reset); + + return 0; +} + + +static int q6v5_wcss_stop(struct rproc *rproc) +{ + struct q6v5_wcss *wcss = rproc->priv; + int ret; + + /* WCSS powerdown */ + ret = qcom_q6v5_request_stop(&wcss->q6v5); + if (ret == -ETIMEDOUT) { + dev_err(wcss->dev, "timed out on wait\n"); + return ret; + } + + ret = q6v5_wcss_powerdown(wcss); + if (ret) + return ret; + + /* Q6 Power down */ + ret = q6v5_q6_powerdown(wcss); + if (ret) + return ret; + + return 0; +} + +static void *q6v5_wcss_da_to_va(struct rproc *rproc, u64 da, int len) +{ + struct q6v5_wcss *wcss = rproc->priv; + int offset; + + offset = da - wcss->mem_reloc; + if (offset < 0 || offset + len > wcss->mem_size) + return NULL; + + return wcss->mem_region + offset; +} + +static int q6v5_wcss_load(struct rproc *rproc, const struct firmware *fw) +{ + struct q6v5_wcss *wcss = rproc->priv; + + return qcom_mdt_load_no_init(wcss->dev, fw, rproc->firmware, + 0, wcss->mem_region, wcss->mem_phys, + wcss->mem_size, &wcss->mem_reloc); +} + +static const struct rproc_ops q6v5_wcss_ops = { + .start = q6v5_wcss_start, + .stop = q6v5_wcss_stop, + .da_to_va = q6v5_wcss_da_to_va, + .load = q6v5_wcss_load, + .get_boot_addr = rproc_elf_get_boot_addr, +}; + +static int q6v5_wcss_init_reset(struct q6v5_wcss *wcss) +{ + struct device *dev = wcss->dev; + + wcss->wcss_aon_reset = devm_reset_control_get(dev, "wcss_aon_reset"); + if (IS_ERR(wcss->wcss_aon_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_aon_reset\n"); + return PTR_ERR(wcss->wcss_aon_reset); + } + + wcss->wcss_reset = devm_reset_control_get(dev, "wcss_reset"); + if (IS_ERR(wcss->wcss_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_reset\n"); + return PTR_ERR(wcss->wcss_reset); + } + + wcss->wcss_q6_reset = devm_reset_control_get(dev, "wcss_q6_reset"); + if (IS_ERR(wcss->wcss_q6_reset)) { + dev_err(wcss->dev, "unable to acquire wcss_q6_reset\n"); + return PTR_ERR(wcss->wcss_q6_reset); + } + + return 0; +} + +static int q6v5_wcss_init_mmio(struct q6v5_wcss *wcss, + struct platform_device *pdev) +{ + struct of_phandle_args args; + struct resource *res; + int ret; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "qdsp6"); + wcss->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wcss->reg_base)) + return PTR_ERR(wcss->reg_base); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rmb"); + wcss->rmb_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(wcss->rmb_base)) + return PTR_ERR(wcss->rmb_base); + + ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node, + "qcom,halt-regs", 3, 0, &args); + if (ret < 0) { + dev_err(&pdev->dev, "failed to parse qcom,halt-regs\n"); + return -EINVAL; + } + + wcss->halt_map = syscon_node_to_regmap(args.np); + of_node_put(args.np); + if (IS_ERR(wcss->halt_map)) + return PTR_ERR(wcss->halt_map); + + wcss->halt_q6 = args.args[0]; + wcss->halt_wcss = args.args[1]; + wcss->halt_nc = args.args[2]; + + return 0; +} + +static int q6v5_alloc_memory_region(struct q6v5_wcss *wcss) +{ + struct reserved_mem *rmem = NULL; + struct device_node *node; + struct device *dev = wcss->dev; + + node = of_parse_phandle(dev->of_node, "memory-region", 0); + if (node) + rmem = of_reserved_mem_lookup(node); + of_node_put(node); + + if (!rmem) { + dev_err(dev, "unable to acquire memory-region\n"); + return -EINVAL; + } + + wcss->mem_phys = rmem->base; + wcss->mem_reloc = rmem->base; + wcss->mem_size = rmem->size; + wcss->mem_region = devm_ioremap_wc(dev, wcss->mem_phys, wcss->mem_size); + if (!wcss->mem_region) { + dev_err(dev, "unable to map memory region: %pa+%pa\n", + &rmem->base, &rmem->size); + return -EBUSY; + } + + return 0; +} + +static int q6v5_wcss_probe(struct platform_device *pdev) +{ + struct q6v5_wcss *wcss; + struct rproc *rproc; + int ret; + + rproc = rproc_alloc(&pdev->dev, pdev->name, &q6v5_wcss_ops, + "IPQ8074/q6_fw.mdt", sizeof(*wcss)); + if (!rproc) { + dev_err(&pdev->dev, "failed to allocate rproc\n"); + return -ENOMEM; + } + + wcss = rproc->priv; + wcss->dev = &pdev->dev; + + ret = q6v5_wcss_init_mmio(wcss, pdev); + if (ret) + goto free_rproc; + + ret = q6v5_alloc_memory_region(wcss); + if (ret) + goto free_rproc; + + ret = q6v5_wcss_init_reset(wcss); + if (ret) + goto free_rproc; + + ret = qcom_q6v5_init(&wcss->q6v5, pdev, rproc, WCSS_CRASH_REASON, NULL); + if (ret) + goto free_rproc; + + ret = rproc_add(rproc); + if (ret) + goto free_rproc; + + platform_set_drvdata(pdev, rproc); + + return 0; + +free_rproc: + rproc_free(rproc); + + return ret; +} + +static int q6v5_wcss_remove(struct platform_device *pdev) +{ + struct rproc *rproc = platform_get_drvdata(pdev); + + rproc_del(rproc); + rproc_free(rproc); + + return 0; +} + +static const struct of_device_id q6v5_wcss_of_match[] = { + { .compatible = "qcom,ipq8074-wcss-pil" }, + { }, +}; +MODULE_DEVICE_TABLE(of, q6v5_wcss_of_match); + +static struct platform_driver q6v5_wcss_driver = { + .probe = q6v5_wcss_probe, + .remove = q6v5_wcss_remove, + .driver = { + .name = "qcom-q6v5-wcss-pil", + .of_match_table = q6v5_wcss_of_match, + }, +}; +module_platform_driver(q6v5_wcss_driver); + +MODULE_DESCRIPTION("Hexagon WCSS Peripheral Image Loader"); +MODULE_LICENSE("GPL v2");