From patchwork Mon Jun 7 15:28:24 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455405 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2947FC47082 for ; Mon, 7 Jun 2021 15:31:01 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9118E61164 for ; Mon, 7 Jun 2021 15:30:59 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 9118E61164 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 40734166F; Mon, 7 Jun 2021 17:30:07 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 40734166F DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623079857; bh=fiqr3x3sbQuzQ8Z4mrijPyg0tgafBA8JLWPfhcDO75A=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=ufVsLHKaYxTaHHBbrvqsf88bSubMH58bm0OFd/qiyZmoWl1JoEsPKcix1FG08A+2f BQyomEmXX/lzIcUUzcKAsTN9tdWxfnbMnWJmt8uFGHthfLPuHEdIc6WDar9a1TAqu7 X+Kpy4fSW6tdTXAx9lK97R7ZgsdWaWYTJiVRNm7s= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 2CA40F801EC; Mon, 7 Jun 2021 17:30:06 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id DB243F804CF; Mon, 7 Jun 2021 17:29:19 +0200 (CEST) Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E1D62F801EC for ; Mon, 7 Jun 2021 17:29:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E1D62F801EC Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="tJomgDBc" Received: by mail-wr1-x42a.google.com with SMTP id y7so13473109wrh.7 for ; Mon, 07 Jun 2021 08:29: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 :mime-version:content-transfer-encoding; bh=vhIJnb1mQgSu0gmVypIYBdkC4S9c9PzuSNZQUQzKNNY=; b=tJomgDBcK0JlDDBHG5N4A3BmQEbquxf/O+e92BfCz1qRVRtleR1Gts4Bcopx/S8yPc PSeQZgiL1dD1/JGrQ4BFWbn5oTDzImnqmkHsaiklkOHGP+QZt1np1zwzHgj7a8lRGfz7 jFh8V2AgiF3Al1+38L+Tuh/iFpimcfMzdLjgyNrL5R3n+lkl3G/c78MzwQxYo5zLWBed Qk/uSVj/DKFcEeqVMw6xM5ffu2RN0ZHw8P1Gr0nrFOk3H6gqFsKnxUK7obO3YHHikvCi munwdxAkLd+ePvmnY3wBDKUs582u9syKeh/2EyzUyt4PMfTxtNl5FzL/hlTNwHDPB/46 kM6w== 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:mime-version:content-transfer-encoding; bh=vhIJnb1mQgSu0gmVypIYBdkC4S9c9PzuSNZQUQzKNNY=; b=gn9qP0PBajNKAe11LMFhTUBsgTcaBvdeQE+17jFZZPZB3XRTYs98Dva1hhaRifALZB XWlCrD9LS1nKYaIaxw5lvo0gUIlEVdR6O6b7oEnfUa2Af+36Fq2bWHy41YPezbz2e2M5 arEj78eyIybS2HUxVsETIdQiDTPrK5N5cy92hulaN4QsGGYRS+6CThJ1aiM3eFQTz0sb BgmSLrE+OISnZfF7vXe/A/FX9KQ+NdEQ1GkULSM87D3mdTeUseb2gP/lchJRj5MMqVKT BVi1demmbnJQPIKJC2ZRDFUK9gkkOjW3uteDVj5mA+cI1PuHMtfAXW/jaZUvwkLUXU/z fqrQ== X-Gm-Message-State: AOAM530Pgm8kNCuKGrxA/7Rk95kKPJ/A+4pFK5emm+zi7wEWnBTDUkZw 0HktFPFC8lkfhFizWaCtrroBOg== X-Google-Smtp-Source: ABdhPJxNjr+z1V7LeyDaphGfhZjV6FSkbENIz0QIxQc48rGOBMJhjuXyt948w4Tu+t6N1YbdGRa2Sg== X-Received: by 2002:adf:f98e:: with SMTP id f14mr17786882wrr.408.1623079740401; Mon, 07 Jun 2021 08:29:00 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.28.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:28:59 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 01/13] soc: dt-bindings: qcom: add gpr bindings Date: Mon, 7 Jun 2021 16:28:24 +0100 Message-Id: <20210607152836.17154-2-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Qualcomm Generic Packet router aka GPR is the IPC mechanism found in AudioReach next generation signal processing framework to perform command and response messages between various processors. GPR has concepts of static and dynamic port, all static services like APM (Audio Processing Manager), PRM (Proxy resource manager) have fixed port numbers where as dynamic services like graphs have dynamic port numbers which are allocated at runtime. All GPR packet messages will have source and destination domain and port along with opcode and payload. Signed-off-by: Srinivas Kandagatla --- .../bindings/soc/qcom/qcom,gpr.yaml | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,gpr.yaml diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,gpr.yaml b/Documentation/devicetree/bindings/soc/qcom/qcom,gpr.yaml new file mode 100644 index 000000000000..cc08ec51de6a --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,gpr.yaml @@ -0,0 +1,74 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/qcom/qcom,gpr.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Qualcomm Generic Packet Router binding + +maintainers: + - Srinivas Kandagatla + +description: | + This binding describes the Qualcomm Generic Packet Router,Shared Memory Manager, + used to send and receive packets between Audio DSP and Application processor. + +properties: + compatible: + const: qcom,gpr + + qcom,glink-channels: + const: adsp_apps + description: + glink channel associated with gpr function + + qcom,gpr-domain: + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [1, 2, 3] + description: + Selects the processor domain for gpr + 1 = Modem Domain + 2 = Audio DSP Domain + 3 = Application Processor Domain + + '#address-cells': + const: 1 + + '#size-cells': + const: 0 + +#GPR Services +patternProperties: + 'gprservice@[0-9]+$': + type: object + description: + GPR node's client devices use subnodes for desired static port services. + + properties: + reg: + maxItems: 1 + description: Service port id + + additionalProperties: false + +required: + - compatible + - qcom,glink-channels + - qcom,gpr-domain + +additionalProperties: false + +examples: + - | + #include + gpr { + compatible = "qcom,gpr"; + qcom,glink-channels = "adsp_apps"; + qcom,gpr-domain = ; + #address-cells = <1>; + #size-cells = <0>; + + gprservice@1 { + reg = ; + }; + }; From patchwork Mon Jun 7 15:28:25 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455403 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F997C47082 for ; Mon, 7 Jun 2021 15:32:45 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 87BCE61164 for ; Mon, 7 Jun 2021 15:32:42 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 87BCE61164 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 1F844169C; Mon, 7 Jun 2021 17:31:51 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 1F844169C DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623079961; bh=W/54klP5seAxgDJ52zB6BGKjwrsx3QKtOPNYGIL0j/0=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=WApsJyFbxTo65RoCMLLl2Go3NfRhhXAo7tb1kiz3w31tgAcDqKG6reWNfq0hoggXq 7optBiECEt+phLrzKwKqVkIEDB9yfT+H9egqb4F7Jr8nMDctuYb4GumCLK4koi7hEg IGucgyueB6IIkpR3Lgc/LcSFcV2OSAYrj3h9KMYc= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 16A92F804CF; Mon, 7 Jun 2021 17:30:10 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 61C83F801EC; Mon, 7 Jun 2021 17:29:23 +0200 (CEST) Received: from mail-wm1-x334.google.com (mail-wm1-x334.google.com [IPv6:2a00:1450:4864:20::334]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id E43B3F80212 for ; Mon, 7 Jun 2021 17:29:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz E43B3F80212 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="wacT53Bp" Received: by mail-wm1-x334.google.com with SMTP id p13-20020a05600c358db029019f44afc845so272673wmq.3 for ; Mon, 07 Jun 2021 08:29: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 :mime-version:content-transfer-encoding; bh=fi+lgkzJyzyN44ZmpOxGUoTme/W0RFyfLc8FFKN0BP0=; b=wacT53BplXQLr08Z7Ok4NBsQap9ghJ6LvG/6uNOl0gDkeG7dyhSKHWg/mdgxh7f2yJ EbuwDskXZ4QqKR9Kt9z75+Uycj5pk7aQZAKzYsKfKopSmL5r0tHGqhFLO0F7KHVxutM6 FMD76kRBb8tfFzzk/5N8Y49pSsSI31LolA8pmU1pDRaoWtk5FaXoql0XErGDZNVesAft 8ueA6fp4d0tRdgE/KolWFAhxtULmKMNyGSm/wypEnawvbS5n5bwl7ex1j3bxwbYfQJD8 wczDDDa5eDaD0ufJCHorme3aJW5bzePlEBBTHxOTgZirz8ic9gYQmuHRfOMt5vaYu7nv a8rw== 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:mime-version:content-transfer-encoding; bh=fi+lgkzJyzyN44ZmpOxGUoTme/W0RFyfLc8FFKN0BP0=; b=FtKt4Gk9NhSmRovp/Wk/QpA2BQ5tFcphsW8OsbTJEn+e4iVgUgY1aMyynSa/+G0J7r Fy7WCVyozzCA7Eu7KRxMswAbl448Ezrvb+CA3x4rECucxC+7s730tRXmF2OJKd1/tBtE 5iEVR1WFjBxZUnTEeH/eBfV5eRb8BsbeXFvNyfYfjOHdlsUm+mGmqJ/uGrHl5hcNFAUE N/9F8JoRBYa8I43t7lUwWZvIH66IDUe+GgYsSVHMmQPDt/jYRy+57zEa14iltnZa09bJ 2TENwX89kN7n9HFTFc8wuH05kkdpH4Z5gTk/rZBJFsmet8JNRrQSJKHeQh3yT6H3u5hy igJg== X-Gm-Message-State: AOAM530mf1Nu87pRTisp3zSWmWjMgPphmizz+W4qiULDCwepnaFE/NZr ZMY2sxhJ+H/dRJbUjW6O8yacxA== X-Google-Smtp-Source: ABdhPJwoGkRDBJpc8PQy3yX+NniyX6dDFoimp6p8Big9rY7ggUDpu1jEY5P8ft+bsZIB5H2z+mBmcQ== X-Received: by 2002:a05:600c:2dd0:: with SMTP id e16mr17744030wmh.180.1623079741790; Mon, 07 Jun 2021 08:29:01 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.29.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:29:01 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 02/13] soc: qcom: add gpr driver support Date: Mon, 7 Jun 2021 16:28:25 +0100 Message-Id: <20210607152836.17154-3-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Qualcomm Generic Packet router aka GPR is the IPC mechanism found in AudioReach next generation signal processing framework to perform command and response messages between various processors. GPR has concepts of static and dynamic port, all static services like APM (Audio Processing Manager), PRM (Proxy resource manager) have fixed port numbers where as dynamic services like graphs have dynamic port numbers which are allocated at runtime. All GPR packet messages will have source and destination domain and port along with opcode and payload. Signed-off-by: Srinivas Kandagatla --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/gpr.c | 487 +++++++++++++++++++++++++++++ include/dt-bindings/soc/qcom,gpr.h | 18 ++ include/linux/soc/qcom/gpr.h | 127 ++++++++ 5 files changed, 642 insertions(+) create mode 100644 drivers/soc/qcom/gpr.c create mode 100644 include/dt-bindings/soc/qcom,gpr.h create mode 100644 include/linux/soc/qcom/gpr.h diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 79b568f82a1c..66eb4a3e4bae 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -209,4 +209,13 @@ config QCOM_APR application processor and QDSP6. APR is used by audio driver to configure QDSP6 ASM, ADM and AFE modules. + +config QCOM_GPR + tristate "Qualcomm GPR Bus (Gecko Packet Router)" + depends on ARCH_QCOM || COMPILE_TEST + depends on RPMSG + help + Enable GPR IPC protocol support between + application processor and QDSP6. GPR is + used by audio driver to configure QDSP6. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index ad675a6593d0..2e4c4fdac77a 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -22,6 +22,7 @@ obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_SOCINFO) += socinfo.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o obj-$(CONFIG_QCOM_APR) += apr.o +obj-$(CONFIG_QCOM_GPR) += gpr.o obj-$(CONFIG_QCOM_LLCC) += llcc-qcom.o obj-$(CONFIG_QCOM_RPMHPD) += rpmhpd.o obj-$(CONFIG_QCOM_RPMPD) += rpmpd.o diff --git a/drivers/soc/qcom/gpr.c b/drivers/soc/qcom/gpr.c new file mode 100644 index 000000000000..7c0c0fe67d92 --- /dev/null +++ b/drivers/soc/qcom/gpr.c @@ -0,0 +1,487 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Some random values tbh which does not collide with static modules */ +#define GPR_DYNAMIC_PORT_START 0x10000000 +#define GPR_DYNAMIC_PORT_END 0x20000000 + +struct gpr_rx_buf { + struct list_head node; + int len; + uint8_t buf[]; +}; + +struct gpr { + struct rpmsg_endpoint *ch; + struct device *dev; + spinlock_t ports_lock; + spinlock_t rx_lock; + struct idr ports_idr; + int dest_domain_id; + struct workqueue_struct *rxwq; + struct work_struct rx_work; + struct list_head rx_list; +}; + +struct gpr_pkt *gpr_alloc_pkt(struct gpr_port *port, int payload_size, + uint32_t opcode, uint32_t token, + uint32_t dest_port) +{ + int pkt_size = GPR_HDR_SIZE + payload_size; + struct gpr *gpr = port->gpr; + struct gpr_pkt *pkt; + void *p; + + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return ERR_PTR(-ENOMEM); + + pkt = p; + pkt->hdr.version = GPR_PKT_VER; + pkt->hdr.hdr_size = GPR_PKT_HEADER_WORD_SIZE; + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.dest_port = dest_port; + pkt->hdr.src_port = port->id; + pkt->hdr.dest_domain = gpr->dest_domain_id; + pkt->hdr.src_domain = GPR_DOMAIN_ID_APPS; + pkt->hdr.token = token; + pkt->hdr.opcode = opcode; + + return pkt; +} +EXPORT_SYMBOL_GPL(gpr_alloc_pkt); + +void gpr_free_pkt(struct gpr_port *port, struct gpr_pkt *pkt) +{ + kfree(pkt); +} +EXPORT_SYMBOL_GPL(gpr_free_pkt); + +int gpr_send_port_pkt(struct gpr_port *port, struct gpr_pkt *pkt) +{ + struct gpr *gpr = port->gpr; + struct gpr_hdr *hdr; + unsigned long flags; + int ret; + + hdr = &pkt->hdr; + + spin_lock_irqsave(&port->lock, flags); + ret = rpmsg_trysend(gpr->ch, pkt, hdr->pkt_size); + spin_unlock_irqrestore(&port->lock, flags); + + return ret ? ret : hdr->pkt_size; +} +EXPORT_SYMBOL_GPL(gpr_send_port_pkt); + +static void gpr_dev_release(struct device *dev) +{ + struct gpr_device *gdev = to_gpr_device(dev); + + kfree(gdev); +} + +static int gpr_callback(struct rpmsg_device *rpdev, void *buf, + int len, void *priv, u32 addr) +{ + struct gpr *gpr = dev_get_drvdata(&rpdev->dev); + struct gpr_rx_buf *abuf; + unsigned long flags; + + abuf = kzalloc(sizeof(*abuf) + len, GFP_ATOMIC); + if (!abuf) + return -ENOMEM; + + abuf->len = len; + memcpy(abuf->buf, buf, len); + + spin_lock_irqsave(&gpr->rx_lock, flags); + list_add_tail(&abuf->node, &gpr->rx_list); + spin_unlock_irqrestore(&gpr->rx_lock, flags); + + queue_work(gpr->rxwq, &gpr->rx_work); + + return 0; +} + +static int gpr_do_rx_callback(struct gpr *gpr, struct gpr_rx_buf *abuf) +{ + uint16_t hdr_size, ver; + struct gpr_port *port = NULL; + struct gpr_resp_pkt resp; + struct gpr_hdr *hdr; + unsigned long flags; + void *buf = abuf->buf; + int len = abuf->len; + + hdr = buf; + ver = hdr->version; + if (ver > GPR_PKT_VER + 1) + return -EINVAL; + + hdr_size = hdr->hdr_size; + if (hdr_size < GPR_PKT_HEADER_WORD_SIZE) { + dev_err(gpr->dev, "GPR: Wrong hdr size:%d\n", hdr_size); + return -EINVAL; + } + + if (hdr->pkt_size < GPR_PKT_HEADER_BYTE_SIZE || hdr->pkt_size != len) { + dev_err(gpr->dev, "GPR: Wrong packet size\n"); + return -EINVAL; + } + + resp.hdr = *hdr; + resp.payload_size = hdr->pkt_size - (hdr_size * 4); + + /* + * NOTE: hdr_size is not same as GPR_HDR_SIZE as remote can include + * optional headers in to gpr_hdr which should be ignored + */ + if (resp.payload_size > 0) + resp.payload = buf + (hdr_size * 4); + + + spin_lock_irqsave(&gpr->ports_lock, flags); + port = idr_find(&gpr->ports_idr, hdr->dest_port); + spin_unlock_irqrestore(&gpr->ports_lock, flags); + + if (!port) { + dev_err(gpr->dev, "GPR: Port(%x) is not registered\n", + hdr->dest_port); + return -EINVAL; + } + + if (port->callback) + port->callback(&resp, port->priv, 0); + + return 0; +} + +static void gpr_rxwq(struct work_struct *work) +{ + struct gpr *gpr = container_of(work, struct gpr, rx_work); + struct gpr_rx_buf *abuf, *b; + unsigned long flags; + + if (!list_empty(&gpr->rx_list)) { + list_for_each_entry_safe(abuf, b, &gpr->rx_list, node) { + gpr_do_rx_callback(gpr, abuf); + spin_lock_irqsave(&gpr->rx_lock, flags); + list_del(&abuf->node); + spin_unlock_irqrestore(&gpr->rx_lock, flags); + kfree(abuf); + } + } +} + +static int gpr_device_match(struct device *dev, struct device_driver *drv) +{ + /* Attempt an OF style match first */ + if (of_driver_match_device(dev, drv)) + return 1; + + return 0; +} + +static int gpr_device_probe(struct device *dev) +{ + struct gpr_device *gdev = to_gpr_device(dev); + struct gpr_driver *adrv = to_gpr_driver(dev->driver); + int ret; + + ret = adrv->probe(gdev); + if (!ret) + gdev->port.callback = adrv->callback; + + return ret; +} + +static int gpr_device_remove(struct device *dev) +{ + struct gpr_device *gdev = to_gpr_device(dev); + struct gpr_driver *adrv; + struct gpr *gpr = dev_get_drvdata(gdev->dev.parent); + + if (dev->driver) { + adrv = to_gpr_driver(dev->driver); + if (adrv->remove) + adrv->remove(gdev); + spin_lock(&gpr->ports_lock); + idr_remove(&gpr->ports_idr, gdev->port_id); + spin_unlock(&gpr->ports_lock); + } + + return 0; +} + +static int gpr_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct gpr_device *gdev = to_gpr_device(dev); + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != -ENODEV) + return ret; + + return add_uevent_var(env, "MODALIAS=gpr:%s", gdev->name); +} + +struct bus_type gprbus = { + .name = "gprbus", + .match = gpr_device_match, + .probe = gpr_device_probe, + .uevent = gpr_uevent, + .remove = gpr_device_remove, +}; +EXPORT_SYMBOL_GPL(gprbus); + +void gpr_free_port(struct gpr_port *port) +{ + struct gpr *gpr = port->gpr; + unsigned long flags; + + spin_lock_irqsave(&gpr->ports_lock, flags); + idr_remove(&gpr->ports_idr, port->id); + spin_unlock_irqrestore(&gpr->ports_lock, flags); + + kfree(port); +} +EXPORT_SYMBOL_GPL(gpr_free_port); + +struct gpr_port *gpr_alloc_port(struct gpr_device* gdev, struct device *dev, + gpr_port_cb cb, void *priv) +{ + struct gpr *gpr = dev_get_drvdata(gdev->dev.parent); + struct gpr_port *port; + int id; + + port = kzalloc(sizeof(*port), GFP_KERNEL); + if (!port) + return ERR_PTR(-ENOMEM); + + port->callback = cb; + port->gpr = gpr; + port->priv = priv; + port->dev = dev; + spin_lock_init(&port->lock); + + spin_lock(&gpr->ports_lock); + id = idr_alloc_cyclic(&gpr->ports_idr, port, GPR_DYNAMIC_PORT_START, + GPR_DYNAMIC_PORT_END, GFP_ATOMIC); + if (id < 0) { + dev_err(dev, "Unable to allocate dynamic GPR src port\n"); + kfree(port); + spin_unlock(&gpr->ports_lock); + return ERR_PTR(-ENOMEM); + } + port->id = id; + spin_unlock(&gpr->ports_lock); + + dev_info(dev, "Adding GPR src port (%x)\n", port->id); + + return port; +} +EXPORT_SYMBOL_GPL(gpr_alloc_port); + +static int gpr_add_device(struct device *dev, struct device_node *np, + u32 port_id, u32 domain_id) +{ + struct gpr *gpr = dev_get_drvdata(dev); + struct gpr_device *gdev = NULL; + int ret; + + gdev = kzalloc(sizeof(*gdev), GFP_KERNEL); + if (!gdev) + return -ENOMEM; + + gdev->port_id = port_id; + gdev->domain_id = domain_id; + if (np) + snprintf(gdev->name, GPR_NAME_SIZE, "%pOFn", np); + + dev_set_name(&gdev->dev, "gprport:%s:%x:%x", gdev->name, + domain_id, port_id); + + gdev->dev.bus = &gprbus; + gdev->dev.parent = dev; + gdev->dev.of_node = np; + gdev->dev.release = gpr_dev_release; + gdev->dev.driver = NULL; + + gdev->port.gpr = gpr; + gdev->port.priv = gdev; + gdev->port.id = port_id; + spin_lock_init(&gdev->port.lock); + + spin_lock(&gpr->ports_lock); + idr_alloc(&gpr->ports_idr, &gdev->port, port_id, + port_id + 1, GFP_ATOMIC); + spin_unlock(&gpr->ports_lock); + + dev_info(dev, "Adding GPR dev: %s\n", dev_name(&gdev->dev)); + + ret = device_register(&gdev->dev); + if (ret) { + dev_err(dev, "device_register failed: %d\n", ret); + put_device(&gdev->dev); + } + + return ret; +} + +static void of_register_gpr_devices(struct device *dev) +{ + struct gpr *gpr = dev_get_drvdata(dev); + struct device_node *node; + + for_each_child_of_node(dev->of_node, node) { + u32 port_id; + u32 domain_id; + + if (of_property_read_u32(node, "reg", &port_id)) + continue; + + domain_id = gpr->dest_domain_id; + + if (gpr_add_device(dev, node, port_id, domain_id)) + dev_err(dev, "Failed to add gpr %d port\n", port_id); + } +} + +static int gpr_probe(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + struct gpr *gpr; + int ret; + + gpr = devm_kzalloc(dev, sizeof(*gpr), GFP_KERNEL); + if (!gpr) + return -ENOMEM; + + ret = of_property_read_u32(dev->of_node, "qcom,gpr-domain", + &gpr->dest_domain_id); + if (ret) { + dev_err(dev, "GPR Domain ID not specified in DT\n"); + return ret; + } + + dev_set_drvdata(dev, gpr); + gpr->ch = rpdev->ept; + gpr->dev = dev; + gpr->rxwq = create_singlethread_workqueue("qcom_gpr_rx"); + if (!gpr->rxwq) { + dev_err(gpr->dev, "Failed to start Rx WQ\n"); + return -ENOMEM; + } + INIT_WORK(&gpr->rx_work, gpr_rxwq); + + INIT_LIST_HEAD(&gpr->rx_list); + spin_lock_init(&gpr->rx_lock); + spin_lock_init(&gpr->ports_lock); + idr_init(&gpr->ports_idr); + + of_register_gpr_devices(dev); + + return 0; +} + +static int gpr_remove_device(struct device *dev, void *null) +{ + struct gpr_device *gdev = to_gpr_device(dev); + + device_unregister(&gdev->dev); + + return 0; +} + +static void gpr_remove(struct rpmsg_device *rpdev) +{ + struct gpr *gpr = dev_get_drvdata(&rpdev->dev); + + device_for_each_child(&rpdev->dev, NULL, gpr_remove_device); + flush_workqueue(gpr->rxwq); + destroy_workqueue(gpr->rxwq); +} + +/* + * __gpr_driver_register() - Client driver registration with gprbus + * + * @drv:Client driver to be associated with client-device. + * @owner: owning module/driver + * + * This API will register the client driver with the gprbus + * It is called from the driver's module-init function. + */ +int __gpr_driver_register(struct gpr_driver *drv, struct module *owner) +{ + drv->driver.bus = &gprbus; + drv->driver.owner = owner; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(__gpr_driver_register); + +/* + * gpr_driver_unregister() - Undo effect of gpr_driver_register + * + * @drv: Client driver to be unregistered + */ +void gpr_driver_unregister(struct gpr_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(gpr_driver_unregister); + +static const struct of_device_id gpr_of_match[] = { + { .compatible = "qcom,gpr", }, + {} +}; +MODULE_DEVICE_TABLE(of, gpr_of_match); + +static struct rpmsg_driver gpr_driver = { + .probe = gpr_probe, + .remove = gpr_remove, + .callback = gpr_callback, + .drv = { + .name = "qcom,gpr", + .of_match_table = gpr_of_match, + }, +}; + +static int __init gpr_init(void) +{ + int ret; + + ret = bus_register(&gprbus); + if (!ret) + ret = register_rpmsg_driver(&gpr_driver); + else + bus_unregister(&gprbus); + + return ret; +} + +static void __exit gpr_exit(void) +{ + bus_unregister(&gprbus); + unregister_rpmsg_driver(&gpr_driver); +} + +subsys_initcall(gpr_init); +module_exit(gpr_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm GPR Bus"); diff --git a/include/dt-bindings/soc/qcom,gpr.h b/include/dt-bindings/soc/qcom,gpr.h new file mode 100644 index 000000000000..1c68906e079c --- /dev/null +++ b/include/dt-bindings/soc/qcom,gpr.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_QCOM_GPR_H +#define __DT_BINDINGS_QCOM_GPR_H + +/* DOMAINS */ + +#define GPR_DOMAIN_ID_MODEM 1 +#define GPR_DOMAIN_ID_ADSP 2 +#define GPR_DOMAIN_ID_APPS 3 + +/* Static Services */ + +#define GPR_APM_MODULE_IID 1 +#define GPR_PRM_MODULE_IID 2 +#define GPR_AMDB_MODULE_IID 3 +#define GPR_VCPM_MODULE_IID 4 + +#endif /* __DT_BINDINGS_QCOM_GPR_H */ diff --git a/include/linux/soc/qcom/gpr.h b/include/linux/soc/qcom/gpr.h new file mode 100644 index 000000000000..05cbbc407a49 --- /dev/null +++ b/include/linux/soc/qcom/gpr.h @@ -0,0 +1,127 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCOM_GPR_H_ +#define __QCOM_GPR_H_ + +#include +#include +#include + +#define APM_MODULE_INSTANCE_ID GPR_APM_MODULE_IID +#define PRM_MODULE_INSTANCE_ID GPR_PRM_MODULE_IID +#define AMDB_MODULE_INSTANCE_ID GPR_AMDB_MODULE_IID +#define VCPM_MODULE_INSTANCE_ID GPR_VCPM_MODULE_IID + +struct gpr_hdr { + uint32_t version:4; + uint32_t hdr_size:4; + uint32_t pkt_size:24; + uint32_t dest_domain:8; + uint32_t src_domain:8; + uint32_t reserved:16; + uint32_t src_port; + uint32_t dest_port; + uint32_t token; + uint32_t opcode; +} __packed; + +struct gpr_pkt { + struct gpr_hdr hdr; + uint32_t payload[0]; +}; + +struct gpr_resp_pkt { + struct gpr_hdr hdr; + void *payload; + int payload_size; +}; + +#define GPR_HDR_SIZE sizeof(struct gpr_hdr) +#define GPR_PKT_VER 0x0 +#define GPR_PKT_HEADER_WORD_SIZE ((sizeof(struct gpr_pkt) + 3) >> 2) +#define GPR_PKT_HEADER_BYTE_SIZE (GPR_PKT_HEADER_WORD_SIZE << 2) +#define GPR_DOMAIN_ID_MODEM 1 +#define GPR_DOMAIN_ID_ADSP 2 +#define GPR_DOMAIN_ID_APPS 3 + +#define GPR_BASIC_RSP_RESULT 0x02001005 +struct gpr_ibasic_rsp_result_t { + uint32_t opcode; + uint32_t status; +}; + +#define GPR_BASIC_EVT_ACCEPTED 0x02001006 +struct gpr_ibasic_rsp_accepted_t { + uint32_t opcode; +}; + +extern struct bus_type gprbus; +typedef int (*gpr_port_cb) (struct gpr_resp_pkt *d, void *priv, int op); + +struct gpr_port { + struct device *dev; + gpr_port_cb callback; + struct gpr *gpr; + spinlock_t lock; + int id; + void *priv; +}; + +#define GPR_NAME_SIZE 128 +struct gpr_device { + struct device dev; + uint16_t port_id; + uint16_t domain_id; + uint32_t version; + char name[GPR_NAME_SIZE]; + struct gpr_port port; +}; + +#define to_gpr_device(d) container_of(d, struct gpr_device, dev) + +struct gpr_driver { + int (*probe)(struct gpr_device *sl); + int (*remove)(struct gpr_device *sl); + int (*callback)(struct gpr_resp_pkt *d, void *data, int op); + struct device_driver driver; +}; + +#define to_gpr_driver(d) container_of(d, struct gpr_driver, driver) + +/* + * use a macro to avoid include chaining to get THIS_MODULE + */ +#define gpr_driver_register(drv) __gpr_driver_register(drv, THIS_MODULE) + +int __gpr_driver_register(struct gpr_driver *drv, struct module *owner); +void gpr_driver_unregister(struct gpr_driver *drv); + +/** + * module_gpr_driver() - Helper macro for registering a aprbus driver + * @__aprbus_driver: aprbus_driver struct + * + * Helper macro for aprbus drivers which do not do anything special in + * module init/exit. This eliminates a lot of boilerplate. Each module + * may only use this macro once, and calling it replaces module_init() + * and module_exit() + */ +#define module_gpr_driver(__gpr_driver) \ + module_driver(__gpr_driver, gpr_driver_register, \ + gpr_driver_unregister) + +struct gpr_port *gpr_alloc_port(struct gpr_device *gdev, struct device *dev, + gpr_port_cb cb, void *priv); +void gpr_free_port(struct gpr_port *port); + +struct gpr_pkt *gpr_alloc_pkt(struct gpr_port *port, int payload_size, + uint32_t opcode, uint32_t token, + uint32_t dest_port); +void gpr_free_pkt(struct gpr_port *port, struct gpr_pkt *pkt); + +int gpr_send_port_pkt(struct gpr_port *port, struct gpr_pkt *pkt); +static inline int gpr_send_pkt(struct gpr_device *gdev, struct gpr_pkt *pkt) +{ + return gpr_send_port_pkt(&gdev->port, pkt); +} + +#endif /* __QCOM_GPR_H_ */ From patchwork Mon Jun 7 15:28:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455402 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 8F80BC47082 for ; Mon, 7 Jun 2021 15:33:24 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 94EEA61185 for ; Mon, 7 Jun 2021 15:33:23 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org 94EEA61185 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id A87F7167B; Mon, 7 Jun 2021 17:32:31 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz A87F7167B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623080001; bh=ynCOry29ZFEgHRjn0lcwKXseW0839hehHDgqZA58+7g=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=Mxz0pCFeuVkEI4VehTo+vnQdgRoSFxJ+j3Bc2dGYndRgKdHkOvmKd5N5cA2RfUAm9 1BtypLFZjbh+eEazo70M5tg0tDDlSZyplTmV9oL3YLENgy0vXdTUjupdPOcuZgLT4d QkAxiahcb83hQiccVfGKRcSb1+hcKsFop5R+aRFk= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id A47CFF804DF; Mon, 7 Jun 2021 17:30:11 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id EEC4CF800AF; Mon, 7 Jun 2021 17:29:27 +0200 (CEST) Received: from mail-wm1-x333.google.com (mail-wm1-x333.google.com [IPv6:2a00:1450:4864:20::333]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 66B66F8027C for ; Mon, 7 Jun 2021 17:29:06 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 66B66F8027C Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="ezJbmXJO" Received: by mail-wm1-x333.google.com with SMTP id g204so10297464wmf.5 for ; Mon, 07 Jun 2021 08:29:06 -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 :mime-version:content-transfer-encoding; bh=fpSALZ4QvKe+UDR9WTTzY0agA74ILnhkVcpsIKuvJFc=; b=ezJbmXJO+TlaXi+377R5+t//WGHiuxRZecowOixbzJ5L6PtvuxXnPe1iPyW+CLTMnz Bx8Vg5PfK23Woch4LMeisRwTojaNpRcBdtdIR5S5m6721EvE9nL3JvlsE6Jre2YDPr3T AJh8jowwAWYNtI36jAIVKvLx4rTpI/+BaKNu5hYB9IcJo/MbY6tFCHSJDoOnEDAoKuRk RUQ8PjoQDGIbponowtfYFyEmpiWxI4P5/OeR6VNF02Fw72tPoMaLYIGA8NtJPjccuw/J ukpy3sHey1Gz54KaFSeTmMTYb6b8WGbSF6Gg8T6eljn0ANs2uKUptQTwHD15y86NxoKX LAtg== 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:mime-version:content-transfer-encoding; bh=fpSALZ4QvKe+UDR9WTTzY0agA74ILnhkVcpsIKuvJFc=; b=KUz63qIzrznQq5G346RCAmE7dI02Ejm4nsk5yvHE54R0Eyjs7C4FFIrm68d0/EUZdD C94MULl+iWcIDnxelFcfDuQWSjaj45O4vIQAYGUKwxCfQCFvaC10MGORSG1uJpFYz/ni RbGnxfABYKigfJh/yv9dcjoEWaeu28iKdiooiE2NJ3UXD6P7nOWP6KreDxXB5TwodHs/ +EMWunWNbE1E81UvR8RShfOUPbY3ngAWSibynGMwD+2BBWBBNDYh44KpObln45rNhIyf 3QGGTXd0tlNoP0ek7W1Kx1Fm5WnnEm05c5GgvhfNzKxwcERMyXBkTeu8lYRAoEbrWigO WR+w== X-Gm-Message-State: AOAM531haP1pS2XLcdFPoITsWymLwt7Vb2ZUAnga+6d2/Jdd+4tmCnSq AlDxsuigZlCfLRBbiP5TUxgtfg== X-Google-Smtp-Source: ABdhPJzNmoRb5MhjYLVoSYZN5a7Ocf740gL5yunnhlVrnbgOOwuLFw+stHp1J5YG021fxxg7hLEtvQ== X-Received: by 2002:a7b:cb55:: with SMTP id v21mr16795371wmj.19.1623079745978; Mon, 07 Jun 2021 08:29:05 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.29.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:29:05 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 05/13] ASoC: qcom: audioreach: add q6apm support Date: Mon, 7 Jun 2021 16:28:28 +0100 Message-Id: <20210607152836.17154-6-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add support to q6apm (Audio Process Manager) component which is core Audioreach service running in the DSP. Signed-off-by: Srinivas Kandagatla --- include/dt-bindings/sound/qcom,q6apm.h | 215 ++++++++ sound/soc/qcom/audioreach/Makefile | 2 +- sound/soc/qcom/audioreach/audioreach.c | 252 +++++++++ sound/soc/qcom/audioreach/audioreach.h | 6 + sound/soc/qcom/audioreach/q6apm.c | 695 +++++++++++++++++++++++++ sound/soc/qcom/audioreach/q6apm.h | 171 ++++++ 6 files changed, 1340 insertions(+), 1 deletion(-) create mode 100644 include/dt-bindings/sound/qcom,q6apm.h create mode 100644 sound/soc/qcom/audioreach/q6apm.c create mode 100644 sound/soc/qcom/audioreach/q6apm.h diff --git a/include/dt-bindings/sound/qcom,q6apm.h b/include/dt-bindings/sound/qcom,q6apm.h new file mode 100644 index 000000000000..38e3a426b15a --- /dev/null +++ b/include/dt-bindings/sound/qcom,q6apm.h @@ -0,0 +1,215 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_Q6_APM_H__ +#define __DT_BINDINGS_Q6_APM_H__ + +#define MSM_FRONTEND_DAI_MULTIMEDIA1 1 +#define MSM_FRONTEND_DAI_MULTIMEDIA2 2 +#define MSM_FRONTEND_DAI_MULTIMEDIA3 3 +#define MSM_FRONTEND_DAI_MULTIMEDIA4 4 +#define MSM_FRONTEND_DAI_MULTIMEDIA5 5 +#define MSM_FRONTEND_DAI_MULTIMEDIA6 6 +#define MSM_FRONTEND_DAI_MULTIMEDIA7 7 +#define MSM_FRONTEND_DAI_MULTIMEDIA8 8 + +/* Audio Process Manager (APM) virtual ports IDs */ +#define HDMI_RX 1 +#define SLIMBUS_0_RX 2 +#define SLIMBUS_0_TX 3 +#define SLIMBUS_1_RX 4 +#define SLIMBUS_1_TX 5 +#define SLIMBUS_2_RX 6 +#define SLIMBUS_2_TX 7 +#define SLIMBUS_3_RX 8 +#define SLIMBUS_3_TX 9 +#define SLIMBUS_4_RX 10 +#define SLIMBUS_4_TX 11 +#define SLIMBUS_5_RX 12 +#define SLIMBUS_5_TX 13 +#define SLIMBUS_6_RX 14 +#define SLIMBUS_6_TX 15 +#define PRIMARY_MI2S_RX 16 +#define PRIMARY_MI2S_TX 17 +#define SECONDARY_MI2S_RX 18 +#define SECONDARY_MI2S_TX 19 +#define TERTIARY_MI2S_RX 20 +#define TERTIARY_MI2S_TX 21 +#define QUATERNARY_MI2S_RX 22 +#define QUATERNARY_MI2S_TX 23 +#define PRIMARY_TDM_RX_0 24 +#define PRIMARY_TDM_TX_0 25 +#define PRIMARY_TDM_RX_1 26 +#define PRIMARY_TDM_TX_1 27 +#define PRIMARY_TDM_RX_2 28 +#define PRIMARY_TDM_TX_2 29 +#define PRIMARY_TDM_RX_3 30 +#define PRIMARY_TDM_TX_3 31 +#define PRIMARY_TDM_RX_4 32 +#define PRIMARY_TDM_TX_4 33 +#define PRIMARY_TDM_RX_5 34 +#define PRIMARY_TDM_TX_5 35 +#define PRIMARY_TDM_RX_6 36 +#define PRIMARY_TDM_TX_6 37 +#define PRIMARY_TDM_RX_7 38 +#define PRIMARY_TDM_TX_7 39 +#define SECONDARY_TDM_RX_0 40 +#define SECONDARY_TDM_TX_0 41 +#define SECONDARY_TDM_RX_1 42 +#define SECONDARY_TDM_TX_1 43 +#define SECONDARY_TDM_RX_2 44 +#define SECONDARY_TDM_TX_2 45 +#define SECONDARY_TDM_RX_3 46 +#define SECONDARY_TDM_TX_3 47 +#define SECONDARY_TDM_RX_4 48 +#define SECONDARY_TDM_TX_4 49 +#define SECONDARY_TDM_RX_5 50 +#define SECONDARY_TDM_TX_5 51 +#define SECONDARY_TDM_RX_6 52 +#define SECONDARY_TDM_TX_6 53 +#define SECONDARY_TDM_RX_7 54 +#define SECONDARY_TDM_TX_7 55 +#define TERTIARY_TDM_RX_0 56 +#define TERTIARY_TDM_TX_0 57 +#define TERTIARY_TDM_RX_1 58 +#define TERTIARY_TDM_TX_1 59 +#define TERTIARY_TDM_RX_2 60 +#define TERTIARY_TDM_TX_2 61 +#define TERTIARY_TDM_RX_3 62 +#define TERTIARY_TDM_TX_3 63 +#define TERTIARY_TDM_RX_4 64 +#define TERTIARY_TDM_TX_4 65 +#define TERTIARY_TDM_RX_5 66 +#define TERTIARY_TDM_TX_5 67 +#define TERTIARY_TDM_RX_6 68 +#define TERTIARY_TDM_TX_6 69 +#define TERTIARY_TDM_RX_7 70 +#define TERTIARY_TDM_TX_7 71 +#define QUATERNARY_TDM_RX_0 72 +#define QUATERNARY_TDM_TX_0 73 +#define QUATERNARY_TDM_RX_1 74 +#define QUATERNARY_TDM_TX_1 75 +#define QUATERNARY_TDM_RX_2 76 +#define QUATERNARY_TDM_TX_2 77 +#define QUATERNARY_TDM_RX_3 78 +#define QUATERNARY_TDM_TX_3 79 +#define QUATERNARY_TDM_RX_4 80 +#define QUATERNARY_TDM_TX_4 81 +#define QUATERNARY_TDM_RX_5 82 +#define QUATERNARY_TDM_TX_5 83 +#define QUATERNARY_TDM_RX_6 84 +#define QUATERNARY_TDM_TX_6 85 +#define QUATERNARY_TDM_RX_7 86 +#define QUATERNARY_TDM_TX_7 87 +#define QUINARY_TDM_RX_0 88 +#define QUINARY_TDM_TX_0 89 +#define QUINARY_TDM_RX_1 90 +#define QUINARY_TDM_TX_1 91 +#define QUINARY_TDM_RX_2 92 +#define QUINARY_TDM_TX_2 93 +#define QUINARY_TDM_RX_3 94 +#define QUINARY_TDM_TX_3 95 +#define QUINARY_TDM_RX_4 96 +#define QUINARY_TDM_TX_4 97 +#define QUINARY_TDM_RX_5 98 +#define QUINARY_TDM_TX_5 99 +#define QUINARY_TDM_RX_6 100 +#define QUINARY_TDM_TX_6 101 +#define QUINARY_TDM_RX_7 102 +#define QUINARY_TDM_TX_7 103 +#define DISPLAY_PORT_RX 104 +#define WSA_CODEC_DMA_RX_0 105 +#define WSA_CODEC_DMA_TX_0 106 +#define WSA_CODEC_DMA_RX_1 107 +#define WSA_CODEC_DMA_TX_1 108 +#define WSA_CODEC_DMA_TX_2 109 +#define VA_CODEC_DMA_TX_0 110 +#define VA_CODEC_DMA_TX_1 111 +#define VA_CODEC_DMA_TX_2 112 +#define RX_CODEC_DMA_RX_0 113 +#define TX_CODEC_DMA_TX_0 114 +#define RX_CODEC_DMA_RX_1 115 +#define TX_CODEC_DMA_TX_1 116 +#define RX_CODEC_DMA_RX_2 117 +#define TX_CODEC_DMA_TX_2 118 +#define RX_CODEC_DMA_RX_3 119 +#define TX_CODEC_DMA_TX_3 120 +#define RX_CODEC_DMA_RX_4 121 +#define TX_CODEC_DMA_TX_4 122 +#define RX_CODEC_DMA_RX_5 123 +#define TX_CODEC_DMA_TX_5 124 +#define RX_CODEC_DMA_RX_6 125 +#define RX_CODEC_DMA_RX_7 126 + +#define LPASS_CLK_ID_PRI_MI2S_IBIT 1 +#define LPASS_CLK_ID_PRI_MI2S_EBIT 2 +#define LPASS_CLK_ID_SEC_MI2S_IBIT 3 +#define LPASS_CLK_ID_SEC_MI2S_EBIT 4 +#define LPASS_CLK_ID_TER_MI2S_IBIT 5 +#define LPASS_CLK_ID_TER_MI2S_EBIT 6 +#define LPASS_CLK_ID_QUAD_MI2S_IBIT 7 +#define LPASS_CLK_ID_QUAD_MI2S_EBIT 8 +#define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9 +#define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10 +#define LPASS_CLK_ID_SPEAKER_I2S_OSR 11 +#define LPASS_CLK_ID_QUI_MI2S_IBIT 12 +#define LPASS_CLK_ID_QUI_MI2S_EBIT 13 +#define LPASS_CLK_ID_SEN_MI2S_IBIT 14 +#define LPASS_CLK_ID_SEN_MI2S_EBIT 15 +#define LPASS_CLK_ID_INT0_MI2S_IBIT 16 +#define LPASS_CLK_ID_INT1_MI2S_IBIT 17 +#define LPASS_CLK_ID_INT2_MI2S_IBIT 18 +#define LPASS_CLK_ID_INT3_MI2S_IBIT 19 +#define LPASS_CLK_ID_INT4_MI2S_IBIT 20 +#define LPASS_CLK_ID_INT5_MI2S_IBIT 21 +#define LPASS_CLK_ID_INT6_MI2S_IBIT 22 +#define LPASS_CLK_ID_QUI_MI2S_OSR 23 +#define LPASS_CLK_ID_PRI_PCM_IBIT 24 +#define LPASS_CLK_ID_PRI_PCM_EBIT 25 +#define LPASS_CLK_ID_SEC_PCM_IBIT 26 +#define LPASS_CLK_ID_SEC_PCM_EBIT 27 +#define LPASS_CLK_ID_TER_PCM_IBIT 28 +#define LPASS_CLK_ID_TER_PCM_EBIT 29 +#define LPASS_CLK_ID_QUAD_PCM_IBIT 30 +#define LPASS_CLK_ID_QUAD_PCM_EBIT 31 +#define LPASS_CLK_ID_QUIN_PCM_IBIT 32 +#define LPASS_CLK_ID_QUIN_PCM_EBIT 33 +#define LPASS_CLK_ID_QUI_PCM_OSR 34 +#define LPASS_CLK_ID_PRI_TDM_IBIT 35 +#define LPASS_CLK_ID_PRI_TDM_EBIT 36 +#define LPASS_CLK_ID_SEC_TDM_IBIT 37 +#define LPASS_CLK_ID_SEC_TDM_EBIT 38 +#define LPASS_CLK_ID_TER_TDM_IBIT 39 +#define LPASS_CLK_ID_TER_TDM_EBIT 40 +#define LPASS_CLK_ID_QUAD_TDM_IBIT 41 +#define LPASS_CLK_ID_QUAD_TDM_EBIT 42 +#define LPASS_CLK_ID_QUIN_TDM_IBIT 43 +#define LPASS_CLK_ID_QUIN_TDM_EBIT 44 +#define LPASS_CLK_ID_QUIN_TDM_OSR 45 +#define LPASS_CLK_ID_MCLK_1 46 +#define LPASS_CLK_ID_MCLK_2 47 +#define LPASS_CLK_ID_MCLK_3 48 +#define LPASS_CLK_ID_MCLK_4 49 +#define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50 +#define LPASS_CLK_ID_INT_MCLK_0 51 +#define LPASS_CLK_ID_INT_MCLK_1 52 +#define LPASS_CLK_ID_MCLK_5 53 +#define LPASS_CLK_ID_WSA_CORE_MCLK 54 +#define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55 +#define LPASS_CLK_ID_VA_CORE_MCLK 56 +#define LPASS_CLK_ID_TX_CORE_MCLK 57 +#define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58 +#define LPASS_CLK_ID_RX_CORE_MCLK 59 +#define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60 +#define LPASS_CLK_ID_VA_CORE_2X_MCLK 61 + +#define LPASS_HW_AVTIMER_VOTE 101 +#define LPASS_HW_MACRO_VOTE 102 +#define LPASS_HW_DCODEC_VOTE 103 + +#define Q6APM_MAX_CLK_ID 104 + +#define LPASS_CLK_ATTRIBUTE_INVALID 0x0 +#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 +#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 +#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3 + +#endif /* __DT_BINDINGS_Q6_APM_H__ */ diff --git a/sound/soc/qcom/audioreach/Makefile b/sound/soc/qcom/audioreach/Makefile index 575edbed29a2..d76afc51556b 100644 --- a/sound/soc/qcom/audioreach/Makefile +++ b/sound/soc/qcom/audioreach/Makefile @@ -1,5 +1,5 @@ # SPDX-License-Identifier: GPL-2.0-only -snd-ar-objs := audioreach.o +snd-ar-objs := audioreach.o q6apm.o obj-$(CONFIG_SND_SOC_QCOM_AUDIOREACH) += snd-ar.o diff --git a/sound/soc/qcom/audioreach/audioreach.c b/sound/soc/qcom/audioreach/audioreach.c index 617163473b1c..7291adb37d49 100644 --- a/sound/soc/qcom/audioreach/audioreach.c +++ b/sound/soc/qcom/audioreach/audioreach.c @@ -5,6 +5,7 @@ #include #include #include +#include "q6apm.h" #include "audioreach.h" /* SubGraph Config */ @@ -277,3 +278,254 @@ void *audioreach_alloc_apm_cmd_pkt(int pkt_size, uint32_t opcode, APM_MODULE_INSTANCE_ID, true); } + +static void apm_populate_container_config( + struct apm_container_obj *cfg, + struct audioreach_container *cont) +{ + + /* Container Config */ + cfg->container_cfg.container_id = cont->container_id; + cfg->container_cfg.num_prop = 4; + + /* Capablity list */ + cfg->cap_data.prop_id = APM_CONTAINER_PROP_ID_CAPABILITY_LIST; + cfg->cap_data.prop_size = APM_CONTAINER_PROP_ID_CAPABILITY_SIZE; + cfg->num_capablity_id = 1; + cfg->capability_id = cont->capability_id; + + /* Graph Position */ + cfg->pos_data.prop_id = APM_CONTAINER_PROP_ID_GRAPH_POS; + cfg->pos_data.prop_size = sizeof(struct apm_cont_prop_id_graph_pos); + cfg->pos.graph_pos = cont->graph_pos; + + /* Stack size */ + cfg->stack_data.prop_id = APM_CONTAINER_PROP_ID_STACK_SIZE; + cfg->stack_data.prop_size = sizeof(struct + apm_cont_prop_id_stack_size); + cfg->stack.stack_size = cont->stack_size; + + /* Proc domain */ + cfg->domain_data.prop_id = APM_CONTAINER_PROP_ID_PROC_DOMAIN; + cfg->domain_data.prop_size = sizeof(struct + apm_cont_prop_id_domain); + cfg->domain.proc_domain = cont->proc_domain; +} + +static void apm_populate_sub_graph_config( + struct apm_sub_graph_data *cfg, + struct audioreach_sub_graph *sg) +{ + cfg->sub_graph_cfg.sub_graph_id = sg->sub_graph_id; + cfg->sub_graph_cfg.num_sub_graph_prop = APM_SUB_GRAPH_CFG_NPROP; + + /* Perf Mode */ + cfg->perf_data.prop_id = APM_SUB_GRAPH_PROP_ID_PERF_MODE; + cfg->perf_data.prop_size = APM_SG_PROP_ID_PERF_MODE_SIZE; + cfg->perf.perf_mode = sg->perf_mode; + + /* Direction */ + cfg->dir_data.prop_id = APM_SUB_GRAPH_PROP_ID_DIRECTION; + cfg->dir_data.prop_size = APM_SG_PROP_ID_DIR_SIZE; + cfg->dir.direction = sg->direction; + + /* Scenario ID */ + cfg->sid_data.prop_id = APM_SUB_GRAPH_PROP_ID_SCENARIO_ID; + cfg->sid_data.prop_size = APM_SG_PROP_ID_SID_SIZE; + cfg->sid.scenario_id = sg->scenario_id; +} + +static void apm_populate_connection_obj(struct apm_module_conn_obj *obj, + struct audioreach_module *module) +{ + obj->src_mod_inst_id = module->src_mod_inst_id; + obj->src_mod_op_port_id = module->src_mod_op_port_id; + obj->dst_mod_inst_id = module->instance_id; + obj->dst_mod_ip_port_id = module->in_port; +} + +static void apm_populate_module_prop_obj(struct apm_mod_prop_obj *obj, + struct audioreach_module *module) +{ + + obj->instance_id = module->instance_id; + obj->num_props = 1; + obj->prop_data_1.prop_id = APM_MODULE_PROP_ID_PORT_INFO; + obj->prop_data_1.prop_size = APM_MODULE_PROP_ID_PORT_INFO_SZ; + obj->prop_id_port.max_ip_port = module->max_ip_port; + obj->prop_id_port.max_op_port = module->max_op_port; +} + +static void apm_populate_module_list_obj(struct apm_mod_list_obj *obj, + struct audioreach_container *container, + int sub_graph_id) +{ + struct audioreach_module *module; + int i; + + obj->sub_graph_id = sub_graph_id; + obj->container_id = container->container_id; + obj->num_modules = container->num_modules; + i = 0; + list_for_each_entry(module, &container->modules_list, node) { + obj->mod_cfg[i].module_id = module->module_id; + obj->mod_cfg[i].instance_id = module->instance_id; + i++; + } +} + +static void audioreach_populate_graph(struct apm_graph_open_params *open, + struct list_head *sg_list, + int num_sub_graphs) +{ + struct apm_sub_graph_params *sg_data = open->sg_data; + struct apm_container_params *c_data = open->cont_data; + struct apm_module_list_params *ml_data = open->mod_list_data; + struct apm_prop_list_params *mp_data = open->mod_prop_data; + struct apm_mod_conn_list_params *mc_data = open->mod_conn_list_data; + struct apm_container_obj *cobj; + struct audioreach_container *container; + struct audioreach_module *module; + struct apm_mod_list_obj *mlobj; + struct apm_mod_prop_obj *module_prop_obj; + struct apm_module_conn_obj *conn_obj; + int ncontainer = 0, nmodule = 0, nconn = 0; + struct audioreach_sub_graph *sg; + int i = 0; + + mlobj = &ml_data->mod_list_obj[0]; + + list_for_each_entry(sg, sg_list, node) { + struct apm_sub_graph_data *sg_cfg = &sg_data->sg_cfg[i++]; + + apm_populate_sub_graph_config(sg_cfg, sg); + + list_for_each_entry(container, &sg->container_list, node) { + cobj = &c_data->cont_obj[ncontainer]; + + apm_populate_container_config(cobj, container); + apm_populate_module_list_obj(mlobj, container, + sg->sub_graph_id); + + list_for_each_entry(module, &container->modules_list, node) { + uint32_t src_mod_inst_id; + + src_mod_inst_id = module->src_mod_inst_id; + + module_prop_obj = &mp_data->mod_prop_obj[nmodule]; + apm_populate_module_prop_obj(module_prop_obj, + module); + + if (src_mod_inst_id /*&& dst_mod_inst_id*/) { + conn_obj = &mc_data->conn_obj[nconn]; + apm_populate_connection_obj(conn_obj, module); + nconn++; + } + + nmodule++; + } + mlobj = (void *) mlobj + + APM_MOD_LIST_OBJ_PSIZE(container->num_modules); + + ncontainer++; + } + } +} + +void *audioreach_alloc_graph_pkt(struct q6apm *apm, + struct list_head *sg_list, + int graph_id) +{ + void *p; + int payload_size, sg_sz, cont_sz, ml_sz, mp_sz, mc_sz; + struct gpr_pkt *pkt; + struct apm_graph_open_params params; + struct apm_module_param_data *param_data; + struct audioreach_container *container; + int num_containers = 0; + int num_modules = 0; + int num_modules_list; + int num_modules_per_list; + int num_connections = 0; + int num_sub_graphs = 0; + struct audioreach_sub_graph *sgs; + struct audioreach_module *module; + + list_for_each_entry(sgs, sg_list, node) { + num_sub_graphs++; + list_for_each_entry(container, &sgs->container_list, node) { + num_containers++; + num_modules += container->num_modules; + list_for_each_entry(module, &container->modules_list, node) { + if (module->src_mod_inst_id) + num_connections++; + } + } + } + + num_modules_list = num_containers; + num_modules_per_list = num_modules/num_containers; + sg_sz = APM_SUB_GRAPH_PSIZE(num_sub_graphs); + cont_sz = APM_CONTAINER_PSIZE(num_containers); + ml_sz = APM_MOD_LIST_PSIZE(num_modules_list, num_modules_per_list); + mp_sz = APM_MOD_PROP_PSIZE(num_modules); + mc_sz = APM_MOD_CONN_PSIZE(num_connections); + + payload_size = sg_sz + cont_sz + ml_sz + mp_sz + mc_sz; + p = audioreach_alloc_apm_cmd_pkt(payload_size, APM_CMD_GRAPH_OPEN, 0); + if (IS_ERR(p)) + return p; + + pkt = p; + p = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + // SG + params.sg_data = p; + param_data = ¶ms.sg_data->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_SUB_GRAPH_CONFIG; + param_data->param_size = sg_sz - APM_MODULE_PARAM_DATA_SIZE; + params.sg_data->num_sub_graphs = num_sub_graphs; + p += sg_sz; + + //CONT + params.cont_data = p; + param_data = ¶ms.cont_data->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_CONTAINER_CONFIG; + param_data->param_size = cont_sz - APM_MODULE_PARAM_DATA_SIZE; + params.cont_data->num_containers = num_containers; + p += cont_sz; + + // ML List + params.mod_list_data = p; + param_data = ¶ms.mod_list_data->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_MODULE_LIST; + param_data->param_size = ml_sz - APM_MODULE_PARAM_DATA_SIZE; + params.mod_list_data->num_modules_list = num_sub_graphs; + p += ml_sz; + + // MOD PROP + params.mod_prop_data = p; + param_data = ¶ms.mod_prop_data->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_MODULE_PROP; + param_data->param_size = mp_sz - APM_MODULE_PARAM_DATA_SIZE; + params.mod_prop_data->num_modules_prop_cfg = num_modules; + p += mp_sz; + + // MOD CONN + params.mod_conn_list_data = p; + param_data = ¶ms.mod_conn_list_data->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_MODULE_CONN; + param_data->param_size = mc_sz - APM_MODULE_PARAM_DATA_SIZE; + params.mod_conn_list_data->num_connections = num_connections; + p += mc_sz; + + audioreach_populate_graph(¶ms, sg_list, num_sub_graphs); + + return pkt; +} + diff --git a/sound/soc/qcom/audioreach/audioreach.h b/sound/soc/qcom/audioreach/audioreach.h index 872e400dce6c..e5736fdda66b 100644 --- a/sound/soc/qcom/audioreach/audioreach.h +++ b/sound/soc/qcom/audioreach/audioreach.h @@ -5,6 +5,9 @@ #include #include #include +struct q6apm; +struct q6apm_graph; + /* Module IDs */ #define MODULE_ID_WR_SHARED_MEM_EP 0x07001000 @@ -621,4 +624,7 @@ void *audioreach_alloc_apm_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port); void *audioreach_alloc_pkt(int pkt_size, uint32_t opcode, uint32_t token, uint32_t src_port, uint32_t dest_port); +void *audioreach_alloc_graph_pkt(struct q6apm *apm, + struct list_head *sg_list, + int graph_id); #endif /* __AUDIOREACH_H__ */ diff --git a/sound/soc/qcom/audioreach/q6apm.c b/sound/soc/qcom/audioreach/q6apm.c new file mode 100644 index 000000000000..d0deb69114b0 --- /dev/null +++ b/sound/soc/qcom/audioreach/q6apm.c @@ -0,0 +1,695 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2020, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audioreach.h" +#include "q6apm.h" + +/* Graph Management */ +struct apm_graph_mgmt_cmd { + struct apm_module_param_data param_data; + uint32_t num_sub_graphs; + uint32_t sub_graph_id_list[0]; +} __packed; + +#define APM_GRAPH_MGMT_PSIZE(n) ALIGN(sizeof(struct apm_graph_mgmt_cmd) + \ + n * sizeof(uint32_t), 8) + +int q6apm_send_cmd(struct q6apm *apm, struct gpr_pkt *pkt) +{ + int rc; + + mutex_lock(&apm->cmd_lock); + rc = gpr_send_pkt(apm->gdev, pkt); + mutex_unlock(&apm->cmd_lock); + + return rc; +} + +int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, + uint32_t rsp_opcode) +{ + struct gpr_device *gdev = apm->gdev; + struct gpr_hdr *hdr = &pkt->hdr; + int rc; + + mutex_lock(&apm->cmd_lock); + apm->result.opcode = 0; + apm->result.status = 0; + + rc = gpr_send_pkt(apm->gdev, pkt); + if (rc < 0) + goto err; + + if (rsp_opcode) + rc = wait_event_timeout(apm->wait, + (apm->result.opcode == hdr->opcode) || + (apm->result.opcode == rsp_opcode), + 5 * HZ); + else + rc = wait_event_timeout(apm->wait, + (apm->result.opcode == hdr->opcode), + 5 * HZ); + + if (!rc) { + dev_err(&gdev->dev, "CMD timeout for [%x] opcode\n", + hdr->opcode); + rc = -ETIMEDOUT; + } else if (apm->result.status > 0) { + dev_err(&gdev->dev, "DSP returned error[%x] %x\n", hdr->opcode, + apm->result.status); + rc = -EINVAL; + } else { + dev_err(&gdev->dev, "DSP returned [%x]\n", + apm->result.status); + rc = 0; + } + +err: + mutex_unlock(&apm->cmd_lock); + return rc; +} + +static struct audioreach_graph *q6apm_get_audioreach_graph(struct q6apm *apm, + uint32_t graph_id) +{ + struct audioreach_graph *graph = NULL; + struct audioreach_graph_info *info; + unsigned long flags; + + spin_lock_irqsave(&apm->lock, flags); + graph = idr_find(&apm->graph_idr, graph_id); + spin_unlock_irqrestore(&apm->lock, flags); + + if (graph) { + kref_get(&graph->refcount); + return graph; + } + + info = idr_find(&apm->graph_info_idr, graph_id); + + if (!info) + return ERR_PTR(-ENODEV); + + graph = kzalloc(sizeof(*graph), GFP_KERNEL); + if (!graph) + return ERR_PTR(-ENOMEM); + + graph->apm = apm; + graph->info = info; + graph->id = graph_id; + + /* Assuming Linear Graphs only for now! */ + graph->graph = audioreach_alloc_graph_pkt(apm, &info->sg_list, graph_id); + if (IS_ERR(graph->graph)) + return ERR_PTR(-ENOMEM); + + spin_lock(&apm->lock); + idr_alloc(&apm->graph_idr, graph, graph_id, + graph_id + 1, GFP_ATOMIC); + spin_unlock(&apm->lock); + + kref_init(&graph->refcount); + + q6apm_send_cmd_sync(apm, graph->graph, 0); + + return graph; +} + +static int audioreach_graph_mgmt_cmd(struct audioreach_graph *graph, + uint32_t opcode) +{ + struct gpr_pkt *pkt; + void *p; + int i = 0, rc, payload_size; + struct q6apm *apm = graph->apm; + struct audioreach_graph_info *info = graph->info; + int num_sub_graphs = info->num_sub_graphs; + struct apm_graph_mgmt_cmd *mgmt_cmd; + struct apm_module_param_data *param_data; + struct audioreach_sub_graph *sg; + + payload_size = APM_GRAPH_MGMT_PSIZE(num_sub_graphs); + + p = audioreach_alloc_apm_cmd_pkt(payload_size, opcode, 0); + if (IS_ERR(p)) + return -ENOMEM; + + pkt = p; + p = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + mgmt_cmd = p; + mgmt_cmd->num_sub_graphs = num_sub_graphs; + + param_data = &mgmt_cmd->param_data; + param_data->module_instance_id = APM_MODULE_INSTANCE_ID; + param_data->param_id = APM_PARAM_ID_SUB_GRAPH_LIST; + param_data->param_size = payload_size - APM_MODULE_PARAM_DATA_SIZE; + + list_for_each_entry(sg, &info->sg_list, node) { + mgmt_cmd->sub_graph_id_list[i++] = sg->sub_graph_id; + } + + rc = q6apm_send_cmd_sync(apm, pkt, 0); + + kfree(pkt); + + return rc; +} + +static void q6apm_put_audioreach_graph(struct kref *ref) +{ + struct audioreach_graph *graph; + struct q6apm *apm; + unsigned long flags; + + graph = container_of(ref, struct audioreach_graph, refcount); + apm = graph->apm; + + audioreach_graph_mgmt_cmd(graph, APM_CMD_GRAPH_CLOSE); + + spin_lock_irqsave(&apm->lock, flags); + graph = idr_remove(&apm->graph_idr, graph->id); + spin_unlock_irqrestore(&apm->lock, flags); + + kfree(graph->graph); + kfree(graph); +} + +static bool q6apm_get_apm_state(struct q6apm *apm) +{ + struct gpr_pkt *pkt; + + pkt = audioreach_alloc_apm_cmd_pkt(0, APM_CMD_GET_SPF_STATE, 0); + if (IS_ERR(pkt)) + return -ENOMEM; + + q6apm_send_cmd_sync(apm, pkt, APM_CMD_RSP_GET_SPF_STATE); + + kfree(pkt); + + return !apm->state ? false : true; +} + +static struct audioreach_module *__q6apm_find_module_by_mid(struct q6apm *apm, + struct audioreach_graph_info *info, + uint32_t mid) +{ + struct audioreach_sub_graph *sgs; + struct audioreach_container *container; + struct audioreach_module *module; + + list_for_each_entry(sgs, &info->sg_list, node) { + list_for_each_entry(container, &sgs->container_list, node) { + list_for_each_entry(module, &container->modules_list, node) { + if (mid == module->module_id) + return module; + } + } + } + + return NULL; +} + +static struct audioreach_module *q6apm_graph_get_last_module(struct q6apm *apm, + u32 sgid) +{ + struct audioreach_sub_graph *sg; + struct audioreach_module *module; + struct audioreach_container *container; + + spin_lock(&apm->lock); + sg = idr_find(&apm->sub_graphs_idr, sgid); + spin_unlock(&apm->lock); + if (!sg) + return NULL; + + container = list_last_entry(&sg->container_list, struct audioreach_container, node); + module = list_last_entry(&container->modules_list, struct audioreach_module, node); + + return module; +} + +static struct audioreach_module *q6apm_graph_get_first_module(struct q6apm *apm, + u32 sgid) +{ + struct audioreach_sub_graph *sg; + struct audioreach_module *module; + struct audioreach_container *container; + + spin_lock(&apm->lock); + sg = idr_find(&apm->sub_graphs_idr, sgid); + spin_unlock(&apm->lock); + if (!sg) + return NULL; + + container = list_first_entry(&sg->container_list, struct audioreach_container, node); + module = list_first_entry(&container->modules_list, struct audioreach_module, node); + + return module; +} + +bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, u32 dst_sgid) +{ + struct audioreach_module *module; + u32 iid; + + module = q6apm_graph_get_last_module(apm, src_sgid); + if (!module) + return false; + + iid = module->instance_id; + module = q6apm_graph_get_first_module(apm, dst_sgid); + if (!module) + return false; + + if (module->src_mod_inst_id == iid) + return true; + + return false; +} + +int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, + u32 dst_sgid, bool connect) +{ + + struct audioreach_module *module; + u32 iid; + + if (connect) { + module = q6apm_graph_get_last_module(apm, src_sgid); + if (!module) + return -ENODEV; + + iid = module->instance_id; + } else { + iid = 0; + } + + module = q6apm_graph_get_first_module(apm, dst_sgid); + if (!module) + return ENODEV; + + /* set src module in dst subgraph first module */ + module->src_mod_inst_id = iid; + + return 0; +} + +int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph) +{ + struct audioreach_module *module; + + module = q6apm_find_module_by_mid(graph, MODULE_ID_WR_SHARED_MEM_EP); + if (!module) + return -ENODEV; + + return module->instance_id; + +} +EXPORT_SYMBOL_GPL(q6apm_graph_get_rx_shmem_module_iid); + +static int graph_callback(struct gpr_resp_pkt *data, void *priv, int op) +{ + struct q6apm_graph *graph = priv; + struct device *dev = graph->dev; + struct gpr_hdr *hdr = &data->hdr; + struct gpr_ibasic_rsp_result_t *result; + int ret = -EINVAL; + uint32_t client_event = 0; + + result = data->payload; + + switch (hdr->opcode) { + case DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2: + client_event = APM_CLIENT_EVENT_DATA_WRITE_DONE; + if (graph) { + struct data_cmd_rsp_wr_sh_mem_ep_data_buffer_done_v2 *done; + phys_addr_t phys; + unsigned long flags; + + spin_lock_irqsave(&graph->lock, flags); + + done = data->payload; + phys = graph->rx_data.buf[hdr->token].phys; + + if (lower_32_bits(phys) != done->buf_addr_lsw || + upper_32_bits(phys) != done->buf_addr_msw) { + dev_err(dev, "WR BUFF Expected Token %d addr %pa\n", hdr->token, &phys); + ret = -EINVAL; + } else { + ret = 0; + graph->result.opcode = hdr->opcode; + graph->result.status = done->status; + } + spin_unlock_irqrestore(&graph->lock, flags); + } else { + dev_err(dev, "No SH Mem module found\n"); + ret = -EINVAL; + } + if (graph->cb) + graph->cb(client_event, hdr->token, data->payload, + graph->priv); + + break; + case APM_CMD_RSP_SHARED_MEM_MAP_REGIONS: + if (graph) { + struct apm_cmd_rsp_shared_mem_map_regions *rsp; + + graph->result.opcode = hdr->opcode; + graph->result.status = 0; + rsp = data->payload; + + if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) + graph->rx_data.mem_map_handle = rsp->mem_map_handle; + else + graph->tx_data.mem_map_handle = rsp->mem_map_handle; + + wake_up(&graph->cmd_wait); + ret = 0; + } + break; + case DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2: + if (graph) { + struct data_cmd_rsp_rd_sh_mem_ep_data_buffer_done_v2 *done; + unsigned long flags; + phys_addr_t phys; + + done = data->payload; + spin_lock_irqsave(&graph->lock, flags); + phys = graph->tx_data.buf[hdr->token].phys; + if (upper_32_bits(phys) != done->buf_addr_msw || + lower_32_bits(phys) != done->buf_addr_lsw) { + dev_err(dev, "RD BUFF Expected addr %pa %08x-%08x\n", + &phys, + done->buf_addr_lsw, + done->buf_addr_msw); + ret = -EINVAL; + //goto done; + } else { + ret = 0; + } + spin_unlock_irqrestore(&graph->lock, flags); + client_event = APM_CLIENT_EVENT_DATA_READ_DONE; + wake_up(&graph->cmd_wait); + + if (graph->cb) + graph->cb(client_event, hdr->token, data->payload, + graph->priv); + } + + break; + case DATA_CMD_WR_SH_MEM_EP_EOS_RENDERED: + break; + case GPR_BASIC_RSP_RESULT: + switch (result->opcode) { + case APM_CMD_SHARED_MEM_UNMAP_REGIONS: + if (graph) { + graph->result.opcode = result->opcode; + graph->result.status = 0; + if (hdr->token == SNDRV_PCM_STREAM_PLAYBACK) + graph->rx_data.mem_map_handle = 0; + else + graph->tx_data.mem_map_handle = 0; + + wake_up(&graph->cmd_wait); + ret = 0; + } + + break; + case APM_CMD_SHARED_MEM_MAP_REGIONS: + case DATA_CMD_WR_SH_MEM_EP_MEDIA_FORMAT: + case APM_CMD_SET_CFG: + graph->result.opcode = result->opcode; + graph->result.status = result->status; + if (result->status) { + dev_err(dev, + "Error (%d) Processing 0x%08x cmd\n", + result->status, result->opcode); + ret = -EINVAL; + } else { + ret = 0; + } + wake_up(&graph->cmd_wait); + if (graph->cb) + graph->cb(client_event, hdr->token, data->payload, + graph->priv); + + } + break; + } + + return ret; +} + +struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, + void *priv, int graph_id) +{ + struct q6apm *apm = dev_get_drvdata(dev->parent); + struct q6apm_graph *graph; + struct audioreach_graph *ar_graph; + int ret; + + dev_err(dev, "%s :graph id %d\n",__func__, graph_id); + ar_graph = q6apm_get_audioreach_graph(apm, graph_id); + if (IS_ERR(ar_graph)) { + dev_err(dev, "No graph found with id %d\n", graph_id); + return ERR_CAST(ar_graph); + } + + graph = kzalloc(sizeof(*graph), GFP_KERNEL); + if (!graph) { + ret = -ENOMEM; + goto err; + } + + graph->apm = apm; + graph->priv = priv; + graph->cb = cb; + graph->info = ar_graph->info; + graph->ar_graph = ar_graph; + graph->id = ar_graph->id; + graph->dev = dev; + + spin_lock_init(&graph->lock); + init_waitqueue_head(&graph->cmd_wait); + mutex_init(&graph->cmd_lock); + + graph->port = gpr_alloc_port(apm->gdev, dev, graph_callback, graph); + if (!graph->port) { + kfree(graph); + ret = -ENOMEM; + goto err; + } + + dev_dbg(dev, "%s: GRAPH-DEBUG Opening graph id %d with port id 0x%08x \n", __func__, + graph_id, graph->port->id); + + return graph; +err: + kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph); + return ERR_PTR(ret); +} + +int q6apm_graph_close(struct q6apm_graph *graph) +{ + struct audioreach_graph *ar_graph = graph->ar_graph; + + gpr_free_port(graph->port); + graph->port = NULL; + kref_put(&ar_graph->refcount, q6apm_put_audioreach_graph); + kfree(graph); + + return 0; +} + +int q6apm_graph_prepare(struct q6apm_graph *graph) +{ + return audioreach_graph_mgmt_cmd(graph->ar_graph, + APM_CMD_GRAPH_PREPARE); +} + +int q6apm_graph_start(struct q6apm_graph *graph) +{ + struct audioreach_graph *ar_graph = graph->ar_graph; + int ret = 0; + + if (ar_graph->start_count == 0) + ret = audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_START); + + ar_graph->start_count++; + + return ret; +} + +int q6apm_graph_stop(struct q6apm_graph *graph) +{ + struct audioreach_graph *ar_graph = graph->ar_graph; + + if (--ar_graph->start_count > 0) + return 0; + + return audioreach_graph_mgmt_cmd(ar_graph, APM_CMD_GRAPH_STOP); +} + +int q6apm_graph_flush(struct q6apm_graph *graph) +{ + return audioreach_graph_mgmt_cmd(graph->ar_graph, APM_CMD_GRAPH_FLUSH); +} + +static int q6apm_audio_probe(struct snd_soc_component *component) +{ + return 0; +} + +static void q6apm_audio_remove(struct snd_soc_component *component) +{ +} + +#define APM_AUDIO_DRV_NAME "q6apm-audio" + +static const struct snd_soc_component_driver q6apm_audio_component = { + .name = APM_AUDIO_DRV_NAME, + .probe = q6apm_audio_probe, + .remove = q6apm_audio_remove, +}; + +static int apm_probe(struct gpr_device *gdev) +{ + struct device *dev = &gdev->dev; + struct q6apm *apm; + + apm = devm_kzalloc(dev, sizeof(*apm), GFP_KERNEL); + if (!apm) + return -ENOMEM; + + dev_set_drvdata(dev, apm); + + mutex_init(&apm->cmd_lock); + apm->dev = dev; + apm->gdev = gdev; + init_waitqueue_head(&apm->wait); + + idr_init(&apm->graph_idr); + idr_init(&apm->graph_info_idr); + idr_init(&apm->sub_graphs_idr); + idr_init(&apm->containers_idr); + + idr_init(&apm->modules_idr); + spin_lock_init(&apm->lock); + + q6apm_get_apm_state(apm); + + devm_snd_soc_register_component(dev, &q6apm_audio_component, NULL, 0); + + return of_platform_populate(dev->of_node, NULL, NULL, dev); +} + +static int apm_exit(struct gpr_device *gdev) +{ + struct q6apm *apm = dev_get_drvdata(&gdev->dev); + + kfree(apm); + + return 0; +} + +struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, + uint32_t mid) +{ + struct audioreach_graph_info *info = graph->info; + struct q6apm *apm = graph->apm; + + return __q6apm_find_module_by_mid(apm, info, mid); + +} + +struct audioreach_module *q6apm_find_module(struct q6apm *apm, uint32_t iid) +{ + struct audioreach_module *module; + unsigned long flags; + + spin_lock_irqsave(&apm->lock, flags); + module = idr_find(&apm->modules_idr, iid); + spin_unlock_irqrestore(&apm->lock, flags); + + return module; +} + +static int apm_callback(struct gpr_resp_pkt *data, void *priv, int op) +{ + struct gpr_device *gdev = priv; + struct q6apm *apm = dev_get_drvdata(&gdev->dev); + struct device *dev = &gdev->dev; + struct gpr_ibasic_rsp_result_t *result; + struct gpr_hdr *hdr = &data->hdr; + int ret = -EINVAL; + + result = data->payload; + + switch (hdr->opcode) { + case APM_CMD_RSP_GET_SPF_STATE: + apm->result.opcode = hdr->opcode; + apm->result.status = 0; + wake_up(&apm->wait); + break; + case GPR_BASIC_RSP_RESULT: + switch (result->opcode) { + case APM_CMD_GRAPH_START: + case APM_CMD_GRAPH_OPEN: + case APM_CMD_GRAPH_PREPARE: + case APM_CMD_GRAPH_CLOSE: + case APM_CMD_GRAPH_FLUSH: + case APM_CMD_GRAPH_STOP: + case APM_CMD_SET_CFG: + apm->result.opcode = result->opcode; + apm->result.status = result->status; + if (result->status) { + dev_err(dev, + "Error (%d) Processing 0x%08x cmd\n", + result->status, result->opcode); + ret = -EINVAL; + } else { + ret = 0; + } + wake_up(&apm->wait); + + } + break; + } + + return ret; +} + +static const struct of_device_id apm_device_id[] = { + { .compatible = "qcom,q6apm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, apm_device_id); + +static struct gpr_driver apm_driver = { + .probe = apm_probe, + .remove = apm_exit, + .callback = apm_callback, + .driver = { + .name = "qcom-apm", + .of_match_table = of_match_ptr(apm_device_id), + }, +}; + +module_gpr_driver(apm_driver); +MODULE_DESCRIPTION("Audio Process Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/audioreach/q6apm.h b/sound/soc/qcom/audioreach/q6apm.h new file mode 100644 index 000000000000..3c8ecafae13b --- /dev/null +++ b/sound/soc/qcom/audioreach/q6apm.h @@ -0,0 +1,171 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6APM_H__ +#define __Q6APM_H__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audioreach.h" + +#define APM_PORT_MAX 127 +#define APM_PORT_MAX_AUDIO_CHAN_CNT 8 +#define PCM_CHANNEL_NULL 0 +#define PCM_CHANNEL_FL 1 /* Front left channel. */ +#define PCM_CHANNEL_FR 2 /* Front right channel. */ +#define PCM_CHANNEL_FC 3 /* Front center channel. */ +#define PCM_CHANNEL_LS 4 /* Left surround channel. */ +#define PCM_CHANNEL_RS 5 /* Right surround channel. */ +#define PCM_CHANNEL_LFE 6 /* Low frequency effect channel. */ +#define PCM_CHANNEL_CS 7 /* Center surround channel; Rear center ch */ +#define PCM_CHANNEL_LB 8 /* Left back channel; Rear left channel. */ +#define PCM_CHANNEL_RB 9 /* Right back channel; Rear right channel. */ +#define PCM_CHANNELS 10 /* Top surround channel. */ + +#define NO_TIMESTAMP 0xFF00 +#define FORMAT_LINEAR_PCM 0x0000 +/* APM client callback events */ +#define CMD_EOS 0x0003 +#define APM_CLIENT_EVENT_CMD_EOS_DONE 0x1003 +#define CMD_CLOSE 0x0004 +#define APM_CLIENT_EVENT_CMD_CLOSE_DONE 0x1004 +#define APM_CLIENT_EVENT_CMD_RUN_DONE 0x1008 +#define APM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009 +#define APM_CLIENT_EVENT_DATA_READ_DONE 0x100a +#define MAX_SESSIONS 8 + +struct q6apm { + struct device *dev; + struct gpr_port *port; + struct gpr_device *gdev; + /* For Graph OPEN/START/STOP/CLOSE operations */ + wait_queue_head_t wait; + struct gpr_ibasic_rsp_result_t result; + + struct mutex cmd_lock; + uint32_t state; + + spinlock_t lock; + struct idr graph_idr; + struct idr graph_info_idr; + struct idr sub_graphs_idr; + struct idr containers_idr; + struct idr modules_idr; +}; + +struct audio_buffer { + phys_addr_t phys; + uint32_t size; /* size of buffer */ +}; + +struct audioreach_graph_data { + struct audio_buffer *buf; + uint32_t num_periods; + uint32_t dsp_buf; + uint32_t mem_map_handle; +}; + +struct audioreach_graph { + struct audioreach_graph_info *info; + uint32_t id; + int state; + int start_count; + /* Cached Graph data */ + void *graph; + struct kref refcount; + struct q6apm *apm; +}; + +typedef void (*q6apm_cb) (uint32_t opcode, uint32_t token, + void *payload, void *priv); +struct q6apm_graph { + void *priv; + q6apm_cb cb; + uint32_t id; + struct device *dev; + struct q6apm *apm; + struct gpr_port *port; + struct audioreach_graph_data rx_data; + struct audioreach_graph_data tx_data; + struct gpr_ibasic_rsp_result_t result; + spinlock_t lock; + wait_queue_head_t cmd_wait; + struct mutex cmd_lock; + struct audioreach_graph *ar_graph; + struct audioreach_graph_info *info; +}; + +/* Graph Operations */ +struct q6apm_graph *q6apm_graph_open(struct device *dev, q6apm_cb cb, + void *priv, int graph_id); +int q6apm_graph_close(struct q6apm_graph *graph); +int q6apm_graph_prepare(struct q6apm_graph *graph); +int q6apm_graph_start(struct q6apm_graph *graph); +int q6apm_graph_stop(struct q6apm_graph *graph); +int q6apm_graph_flush(struct q6apm_graph *graph); + +/* Media Format */ +int q6apm_graph_media_format_pcm(struct q6apm_graph *graph, int direction, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample); + +int q6apm_graph_media_format_shmem(struct q6apm_graph *graph, int direction, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample); + +/* read/write related */ +int q6apm_send_eos_nowait(struct q6apm_graph *graph); +int q6apm_read(struct q6apm_graph *graph); +int q6apm_write_async(struct q6apm_graph *graph, uint32_t len, uint32_t msw_ts, + uint32_t lsw_ts, uint32_t flags); + +/* Memory Map related */ +int q6apm_map_memory_regions(struct q6apm_graph *graph, + unsigned int dir, + phys_addr_t phys, + size_t bufsz, unsigned int bufcnt); +int q6apm_unmap_memory_regions(struct q6apm_graph *graph, + unsigned int dir); +/* Helpers */ +struct audioreach_module *q6apm_find_module(struct q6apm *apm, uint32_t iid); +int q6apm_send_cmd(struct q6apm *apm, struct gpr_pkt *pkt); +int q6apm_send_cmd_sync(struct q6apm *apm, struct gpr_pkt *pkt, + uint32_t rsp_opcode); + +/* Callback for graph specific */ +struct audioreach_module *q6apm_find_module_by_mid(struct q6apm_graph *graph, + uint32_t mid); + + +struct q6apm_cdc_dma_cfg { + u16 sample_rate; + u16 bit_width; + u16 data_format; + u16 num_channels; + u16 active_channels_mask; +}; + +struct q6apm_port_config { + struct q6apm_cdc_dma_cfg dma_cfg; +}; + +void q6apm_set_fe_dai_ops(struct snd_soc_dai_driver *dai_drv); +int q6apm_connect_sub_graphs(struct q6apm *apm, u32 src_sgid, u32 dst_sgid, + bool connect); +bool q6apm_is_sub_graphs_connected(struct q6apm *apm, u32 src_sgid, + u32 dst_sgid); +int q6apm_graph_get_rx_shmem_module_iid(struct q6apm_graph *graph); + +#endif /* __APM_GRAPH_ */ From patchwork Mon Jun 7 15:28:32 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455401 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-14.0 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,UNWANTED_LANGUAGE_BODY, USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DAEEC47082 for ; Mon, 7 Jun 2021 15:34:11 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A349A611AC for ; Mon, 7 Jun 2021 15:34:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A349A611AC Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 3B40816AA; Mon, 7 Jun 2021 17:33:19 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 3B40816AA DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623080049; bh=dpWLBMf+XNgRpYLZhNKRp1T7uXXiePz3Vm3N7aFMJzE=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=mYiPP98Ii3LzILzlyzKPqbeHcWjyaC2VmX7EHoJ3cuc4ZgGd3l7loEeNALHMTUZ94 WqrunWiVXJgYh4lI5VWYMm7upXB8zytosapF851cBASwJDPGT9vKvyUtzb5RdOHwOc Pj0+VcM4fgAQRi8FSsGTFIqXTwWD0wOIRIOMsuSA= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 4C7A6F804EC; Mon, 7 Jun 2021 17:30:13 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id F3422F80212; Mon, 7 Jun 2021 17:29:33 +0200 (CEST) Received: from mail-wr1-x42e.google.com (mail-wr1-x42e.google.com [IPv6:2a00:1450:4864:20::42e]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 36834F8032D for ; Mon, 7 Jun 2021 17:29:13 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 36834F8032D Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="C2tiavq7" Received: by mail-wr1-x42e.google.com with SMTP id q5so18134799wrm.1 for ; Mon, 07 Jun 2021 08:29:13 -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 :mime-version:content-transfer-encoding; bh=ghMquO+JsY6coLYnrXZXNOKPAifXt8QsxJuCYWY+dW8=; b=C2tiavq7TQRvhQGBBxu0cVWIfCikpXiMdmkl9qu9HLUMaQ2rKxzRJIvU3RM3LZ4Kif rWrnbgpdtYHf3nM4ysvIdb5B4kvbtrDfmmtOpi534c9ZpA5psCY3QB5sNz0dMdBhB42F Qq/o6UevLzdzhfD58gOus2aLJneFZDHxDUgzv9xPSMjjyCaacBQjDDcG+x6SDjFK2wXt NIScOjYUTBNjozUXohhyTvuKIKM3+bNJs8ZmcUS+Nfh2+q+NuoP9qIUSap5n0n6W1LOC MQIKXU7KuAgFaFxjgC6gSJTdQYAMlhpwnUqIomfpwAwktTh4tWb+YvM05nyt3Zid4SCj sXGw== 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:mime-version:content-transfer-encoding; bh=ghMquO+JsY6coLYnrXZXNOKPAifXt8QsxJuCYWY+dW8=; b=CabWa9wrFh2VRcYJOQ0nQpIBbW3Zb0AQTUyewVv1TemVDZpGZ3ZsRz4+vWfpx1yllQ 5uNKVwT2azSCM3WI0b4pIAG6g/IJbbklLLskUhiz508vf8u2MyxNgNvJyNei4S2uyOKk owKkC8esUoreSVdajjjnEbbOMd9xib/51J88qrmWn7or4tBVgwDy0iyCEi2THfRtdzRJ m4F0QaJ0I8tXDgQb8qpAQCJs+Nx7NZdKJVtjYSLjCSVTAp7Y7ZGrS0V93QbONaT3YgEX gfJBKCkxIpJsFY7gwWRkbJLZdIPoPnU92UJIDAUVClPfrL8nzxNjqNKZOLDGoXwcj3V9 DJBw== X-Gm-Message-State: AOAM5330KNww3ieOycxUYllJnT5pGgV2XcMCBoms9kF9zWIqlMT/PVkR arpylYRWEbEZ6d0c69nMG1a4Pg== X-Google-Smtp-Source: ABdhPJzcdB2u3KnuxCfK0X0wXX+0tKUSccEszb0Rs8c6dyrkTQDHU/FwvEu4s72olWaaezqIM5pzhQ== X-Received: by 2002:adf:a550:: with SMTP id j16mr18026140wrb.25.1623079752373; Mon, 07 Jun 2021 08:29:12 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.29.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:29:11 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 09/13] ASoC: qcom: audioreach: add bedai support Date: Mon, 7 Jun 2021 16:28:32 +0100 Message-Id: <20210607152836.17154-10-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Signed-off-by: Srinivas Kandagatla --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/audioreach/Makefile | 2 + sound/soc/qcom/audioreach/q6apm-bedai.c | 377 ++++++++++++++++++++++++ 3 files changed, 383 insertions(+) create mode 100644 sound/soc/qcom/audioreach/q6apm-bedai.c diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 258fe9ef26f3..4eb1b1a7c1f7 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -106,11 +106,15 @@ config SND_SOC_QDSP6 config SND_SOC_QCOM_APM_DAI tristate +config SND_SOC_QCOM_APM_BEDAI + tristate + config SND_SOC_QCOM_AUDIOREACH tristate "SoC ALSA audio drives for Qualcomm AUDIOREACH" depends on QCOM_GPR select SND_SOC_TOPOLOGY select SND_SOC_QCOM_APM_DAI + select SND_SOC_QCOM_APM_BEDAI help Support for AudioReach in QDSP diff --git a/sound/soc/qcom/audioreach/Makefile b/sound/soc/qcom/audioreach/Makefile index 7160bddbb1fb..e8651455b206 100644 --- a/sound/soc/qcom/audioreach/Makefile +++ b/sound/soc/qcom/audioreach/Makefile @@ -1,8 +1,10 @@ # SPDX-License-Identifier: GPL-2.0-only snd-ar-objs := audioreach.o q6apm.o topology.o snd-apm-dai-objs := q6apm-dai.o +snd-apm-bedai-objs := q6apm-bedai.o obj-$(CONFIG_SND_SOC_QCOM_AUDIOREACH) += snd-ar.o obj-$(CONFIG_SND_SOC_QCOM_APM_DAI) += snd-apm-dai.o +obj-$(CONFIG_SND_SOC_QCOM_APM_BEDAI) += snd-apm-bedai.o diff --git a/sound/soc/qcom/audioreach/q6apm-bedai.c b/sound/soc/qcom/audioreach/q6apm-bedai.c new file mode 100644 index 000000000000..3b0ccf4f119c --- /dev/null +++ b/sound/soc/qcom/audioreach/q6apm-bedai.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audioreach.h" +#include "q6apm.h" + +#define Q6APM_CDC_DMA_RX_DAI(did) { \ + .playback = { \ + .stream_name = #did" Playback", \ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_176400, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + .channels_min = 1, \ + .channels_max = 8, \ + .rate_min = 8000, \ + .rate_max = 176400, \ + }, \ + .name = #did, \ + .ops = &q6dma_ops, \ + .id = did, \ + } + +#define Q6APM_CDC_DMA_TX_DAI(did) { \ + .capture = { \ + .stream_name = #did" Capture", \ + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |\ + SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_48000 |\ + SNDRV_PCM_RATE_176400, \ + .formats = SNDRV_PCM_FMTBIT_S16_LE | \ + SNDRV_PCM_FMTBIT_S24_LE | \ + SNDRV_PCM_FMTBIT_S32_LE, \ + .channels_min = 1, \ + .channels_max = 8, \ + .rate_min = 8000, \ + .rate_max = 176400, \ + }, \ + .name = #did, \ + .ops = &q6dma_ops, \ + .id = did, \ + } + +#define AUDIOREACH_BE_PCM_BASE 16 + +struct q6apm_bedai_data { + struct q6apm_graph *graph[APM_PORT_MAX]; + uint16_t bits_per_sample[APM_PORT_MAX]; + bool is_port_started[APM_PORT_MAX]; + struct q6apm_port_config port_config[APM_PORT_MAX]; +}; + +static int q6dma_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_ch_mask, + unsigned int rx_num, unsigned int *rx_ch_mask) +{ + + struct q6apm_bedai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6apm_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg; + int ch_mask; + int rc = 0; + + switch (dai->id) { + case WSA_CODEC_DMA_TX_0: + case WSA_CODEC_DMA_TX_1: + case WSA_CODEC_DMA_TX_2: + case VA_CODEC_DMA_TX_0: + case VA_CODEC_DMA_TX_1: + case VA_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_0: + case TX_CODEC_DMA_TX_1: + case TX_CODEC_DMA_TX_2: + case TX_CODEC_DMA_TX_3: + case TX_CODEC_DMA_TX_4: + case TX_CODEC_DMA_TX_5: + if (!tx_ch_mask) { + dev_err(dai->dev, "tx slot not found\n"); + return -EINVAL; + } + + if (tx_num > PCM_MAX_NUM_CHANNEL) { + dev_err(dai->dev, "invalid tx num %d\n", + tx_num); + return -EINVAL; + } + ch_mask = *tx_ch_mask; + + break; + case WSA_CODEC_DMA_RX_0: + case WSA_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_0: + case RX_CODEC_DMA_RX_1: + case RX_CODEC_DMA_RX_2: + case RX_CODEC_DMA_RX_3: + case RX_CODEC_DMA_RX_4: + case RX_CODEC_DMA_RX_5: + case RX_CODEC_DMA_RX_6: + case RX_CODEC_DMA_RX_7: + /* rx */ + if (!rx_ch_mask) { + dev_err(dai->dev, "rx slot not found\n"); + return -EINVAL; + } + if (rx_num > APM_PORT_MAX_AUDIO_CHAN_CNT) { + dev_err(dai->dev, "invalid rx num %d\n", + rx_num); + return -EINVAL; + } + ch_mask = *rx_ch_mask; + + break; + default: + dev_err(dai->dev, "%s: invalid dai id 0x%x\n", + __func__, dai->id); + return -EINVAL; + } + + cfg->active_channels_mask = ch_mask; + + return rc; +} + +static int q6dma_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6apm_bedai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6apm_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg; + + cfg->bit_width = params_width(params); + cfg->sample_rate = params_rate(params); + cfg->num_channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + dai_data->bits_per_sample[dai->id] = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + dai_data->bits_per_sample[dai->id] = 24; + break; + } + + return 0; +} + +static void q6apm_bedai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6apm_bedai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (!dai_data->is_port_started[dai->id]) + return; + rc = q6apm_graph_stop(dai_data->graph[dai->id]); + if (rc < 0) + dev_err(dai->dev, "fail to close APM port (%d)\n", rc); + + q6apm_graph_close(dai_data->graph[dai->id]); + dai_data->is_port_started[dai->id] = false; + +} + +static int q6apm_bedai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6apm_bedai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6apm_cdc_dma_cfg *cfg = &dai_data->port_config[dai->id].dma_cfg; + int graph_id = dai->id; + int rc; + int ret; + struct q6apm_graph *graph; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id); + if (IS_ERR(graph)) { + dev_err(dai->dev, "Failed to open graph (%d)\n", + graph_id); + ret = PTR_ERR(graph); + return ret; + } + dai_data->graph[graph_id] = graph; + } + + rc = q6apm_graph_media_format_pcm(dai_data->graph[dai->id], + substream->stream, cfg->sample_rate, + cfg->num_channels, NULL, cfg->bit_width); + + rc = q6apm_graph_prepare(dai_data->graph[dai->id]); + rc = q6apm_graph_start(dai_data->graph[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to start APM port %x\n", dai->id); + return rc; + } + dai_data->is_port_started[dai->id] = true; + + return 0; +} + +static const struct snd_soc_dapm_route q6apm_dapm_routes[] = { + {"WSA_CODEC_DMA_RX_0 Playback", NULL, "WSA_CODEC_DMA_RX_0"}, + {"WSA_CODEC_DMA_TX_0", NULL, "WSA_CODEC_DMA_TX_0 Capture"}, + {"WSA_CODEC_DMA_RX_1 Playback", NULL, "WSA_CODEC_DMA_RX_1"}, + {"WSA_CODEC_DMA_TX_1", NULL, "WSA_CODEC_DMA_TX_1 Capture"}, + {"WSA_CODEC_DMA_TX_2", NULL, "WSA_CODEC_DMA_TX_2 Capture"}, + {"VA_CODEC_DMA_TX_0", NULL, "VA_CODEC_DMA_TX_0 Capture"}, + {"VA_CODEC_DMA_TX_1", NULL, "VA_CODEC_DMA_TX_1 Capture"}, + {"VA_CODEC_DMA_TX_2", NULL, "VA_CODEC_DMA_TX_2 Capture"}, + {"RX_CODEC_DMA_RX_0 Playback", NULL, "RX_CODEC_DMA_RX_0"}, + {"TX_CODEC_DMA_TX_0", NULL, "TX_CODEC_DMA_TX_0 Capture"}, + {"RX_CODEC_DMA_RX_1 Playback", NULL, "RX_CODEC_DMA_RX_1"}, + {"TX_CODEC_DMA_TX_1", NULL, "TX_CODEC_DMA_TX_1 Capture"}, + {"RX_CODEC_DMA_RX_2 Playback", NULL, "RX_CODEC_DMA_RX_2"}, + {"TX_CODEC_DMA_TX_2", NULL, "TX_CODEC_DMA_TX_2 Capture"}, + {"RX_CODEC_DMA_RX_3 Playback", NULL, "RX_CODEC_DMA_RX_3"}, + {"TX_CODEC_DMA_TX_3", NULL, "TX_CODEC_DMA_TX_3 Capture"}, + {"RX_CODEC_DMA_RX_4 Playback", NULL, "RX_CODEC_DMA_RX_4"}, + {"TX_CODEC_DMA_TX_4", NULL, "TX_CODEC_DMA_TX_4 Capture"}, + {"RX_CODEC_DMA_RX_5 Playback", NULL, "RX_CODEC_DMA_RX_5"}, + {"TX_CODEC_DMA_TX_5", NULL, "TX_CODEC_DMA_TX_5 Capture"}, + {"RX_CODEC_DMA_RX_6 Playback", NULL, "RX_CODEC_DMA_RX_6"}, + {"RX_CODEC_DMA_RX_7 Playback", NULL, "RX_CODEC_DMA_RX_7"}, +}; + +static int q6apm_bedai_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6apm_bedai_data *dai_data = dev_get_drvdata(dai->dev); + int graph_id = dai->id, ret; + struct q6apm_graph *graph; + + if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { + graph = q6apm_graph_open(dai->dev, NULL, dai->dev, graph_id); + if (IS_ERR(graph)) { + dev_err(dai->dev, "Failed to open graph (%d)\n", + graph_id); + ret = PTR_ERR(graph); + return ret; + } + dai_data->graph[graph_id] = graph; + } + + return 0; +} + +static const struct snd_soc_dai_ops q6dma_ops = { + .prepare = q6apm_bedai_prepare, + .startup = q6apm_bedai_startup, + .shutdown = q6apm_bedai_shutdown, + .set_channel_map = q6dma_set_channel_map, + .hw_params = q6dma_hw_params, +}; + +static struct snd_soc_dai_driver q6apm_be_dais[] = { + Q6APM_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_0), + Q6APM_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_0), + Q6APM_CDC_DMA_RX_DAI(WSA_CODEC_DMA_RX_1), + Q6APM_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_1), + Q6APM_CDC_DMA_TX_DAI(WSA_CODEC_DMA_TX_2), + Q6APM_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_0), + Q6APM_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_1), + Q6APM_CDC_DMA_TX_DAI(VA_CODEC_DMA_TX_2), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_0), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_0), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_1), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_1), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_2), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_2), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_3), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_3), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_4), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_4), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_5), + Q6APM_CDC_DMA_TX_DAI(TX_CODEC_DMA_TX_5), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_6), + Q6APM_CDC_DMA_RX_DAI(RX_CODEC_DMA_RX_7), +}; + +static int q6apm_of_xlate_dai_name(struct snd_soc_component *component, + const struct of_phandle_args *args, + const char **dai_name) +{ + int id = args->args[0]; + int ret = -EINVAL; + int i; + + for (i = 0; i < ARRAY_SIZE(q6apm_be_dais); i++) { + if (q6apm_be_dais[i].id == id) { + *dai_name = q6apm_be_dais[i].name; + ret = 0; + break; + } + } + + return ret; +} + +static const struct snd_soc_dapm_widget q6apm_bedai_widgets[] = { + SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_0", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_0", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("WSA_CODEC_DMA_RX_1", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_1", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("WSA_CODEC_DMA_TX_2", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_0", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_1", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("VA_CODEC_DMA_TX_2", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_0", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_0", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_1", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_1", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_2", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_2", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_3", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_3", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_4", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_4", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_5", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_OUT("TX_CODEC_DMA_TX_5", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_6", "NULL", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("RX_CODEC_DMA_RX_7", "NULL", 0, SND_SOC_NOPM, 0, 0), +}; + +static const struct snd_soc_component_driver q6apm_bedai_component = { + .name = "q6apm-be-dai-component", + .dapm_widgets = q6apm_bedai_widgets, + .num_dapm_widgets = ARRAY_SIZE(q6apm_bedai_widgets), + .dapm_routes = q6apm_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(q6apm_dapm_routes), + .of_xlate_dai_name = q6apm_of_xlate_dai_name, + .be_pcm_base = AUDIOREACH_BE_PCM_BASE, + .use_dai_pcm_id = true, +}; + +static int q6apm_bedai_dev_probe(struct platform_device *pdev) +{ + struct q6apm_bedai_data *dai_data; + struct device *dev = &pdev->dev; + + dai_data = devm_kzalloc(dev, sizeof(*dai_data), GFP_KERNEL); + if (!dai_data) + return -ENOMEM; + + dev_set_drvdata(dev, dai_data); + + return devm_snd_soc_register_component(dev, &q6apm_bedai_component, + q6apm_be_dais, + ARRAY_SIZE(q6apm_be_dais)); +} + +#ifdef CONFIG_OF +static const struct of_device_id q6apm_bedai_device_id[] = { + { .compatible = "qcom,q6apm-be-dais" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6apm_bedai_device_id); +#endif + +static struct platform_driver q6apm_bedai_platform_driver = { + .driver = { + .name = "q6apm-bedai", + .of_match_table = of_match_ptr(q6apm_bedai_device_id), + }, + .probe = q6apm_bedai_dev_probe, +}; +module_platform_driver(q6apm_bedai_platform_driver); + +MODULE_DESCRIPTION("AUDIOREACH Audio BackEnd dai driver"); +MODULE_LICENSE("GPL"); From patchwork Mon Jun 7 15:28:34 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455399 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 720ADC47082 for ; Mon, 7 Jun 2021 15:36:13 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id ECA4961185 for ; Mon, 7 Jun 2021 15:36:12 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org ECA4961185 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 5D16516AB; Mon, 7 Jun 2021 17:35:21 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 5D16516AB DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623080171; bh=W9lmgr+t8ObTTV4Y+5oCs9OxKlzlU4hluW/y9TEMCqc=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=LjAyOQJPo1wDC1d2t4fnX8jiS3I74pNBMCSYT9xlSTL849XRMPSV6kHDrKnQHfhMp tABaxoUQjAZs+NKo+opO6CcVSkWDNHPQKdyDRqHm22nBBRuB/gdwInpLOhvycQKRTO H7iAHTxsTb6q1V+vuQkYfnEALJK0tbeUzS8rYSBA= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 1A0D9F80212; Mon, 7 Jun 2021 17:31:25 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 8241CF804BD; Mon, 7 Jun 2021 17:31:24 +0200 (CEST) Received: from mail-wr1-x432.google.com (mail-wr1-x432.google.com [IPv6:2a00:1450:4864:20::432]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id 469FBF804C3 for ; Mon, 7 Jun 2021 17:29:15 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz 469FBF804C3 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="PZvr5x8L" Received: by mail-wr1-x432.google.com with SMTP id c5so18074429wrq.9 for ; Mon, 07 Jun 2021 08:29:15 -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 :mime-version:content-transfer-encoding; bh=W1iJl2Pfs5N04zh5cLmR0BZtU7zADLjxFUl+4rPcNnk=; b=PZvr5x8LLRtYX0iEUaExxo/EiqG7KnCAH89iSPZDz82w6vUpYSqZjPKMUNXygi1LrR XLpkqkEcab1OM6cImBk5E9fPbAzM6smRJcnHu7zJ2ty0DIW1VBTV+m/yLhD4ZXHwUSR4 bDDL7enzp4XjJjzxa+SxpCn2btgDCNP1W5ocHC0aCd39iVLcrucLiwlDm760MIsjT6Zl 2lzZfYOARQg5Ci89bYQtWkfM0N/e0yeIhUKvVj3dagOmS4YP4ArT6fQsQBbtfyQmq2m/ GDQrAJggXTwD7xscNflS+2cAQXwOQIZ2qEIE8s77h1QJHAVU2ChtTTd9qpIZneweUYCD pbZg== 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:mime-version:content-transfer-encoding; bh=W1iJl2Pfs5N04zh5cLmR0BZtU7zADLjxFUl+4rPcNnk=; b=mlLhRNBVStOHAPABVv88YOrKd9Ud9pNSYdAXwVI5exAP4ud73pSdp1TPpQ3VfyAqxo f9TtCiWpaTPrqZp0Cdm4lDukCHmdv1yWK9haOn8EfmJW/phpbj7zFM+5oPppQakzlCf6 vxbcR1K95OHQL/dczXqRt4/GXP8MHzJUfi2XhBlQF1tz7ib1Zf1UWnU6ax3d05utlHaG uSCOOoHk5DYa5TMZFmHPYlkKuPh0Uyy6w4YcRvqSQ1nS+E2SrSpKr9vHSUELece/4jG5 F15Gq88odemOYsSQAHQifTeFR2zjCAe9Nh5iXd9ty4flnhj5UN43xdjOCnFYVSKtJT14 1YqA== X-Gm-Message-State: AOAM532t32mwd0Vua0QEubDKNeov3GcSimSHqRKXEbqKnugwVrGy/k3M nB3UH3GW171CIfwzO/uNTyeuKw== X-Google-Smtp-Source: ABdhPJxVry44u6Yqfb8ZZZYlSIbauOYV/owsF4CO10Qh09+t1V9EpliABlCj9lCFha936gdRCM6/1g== X-Received: by 2002:adf:cd87:: with SMTP id q7mr17501714wrj.370.1623079754630; Mon, 07 Jun 2021 08:29:14 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.29.13 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:29:14 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 11/13] ASoC: qcom: audioreach: add q6prm support Date: Mon, 7 Jun 2021 16:28:34 +0100 Message-Id: <20210607152836.17154-12-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add support to q6prm (Proxy Resource Manager) module used for clock resources Signed-off-by: Srinivas Kandagatla --- include/dt-bindings/sound/qcom,q6prm.h | 205 ++++++++++++ sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/audioreach/Makefile | 2 + sound/soc/qcom/audioreach/q6prm.c | 412 +++++++++++++++++++++++++ 4 files changed, 623 insertions(+) create mode 100644 include/dt-bindings/sound/qcom,q6prm.h create mode 100644 sound/soc/qcom/audioreach/q6prm.c diff --git a/include/dt-bindings/sound/qcom,q6prm.h b/include/dt-bindings/sound/qcom,q6prm.h new file mode 100644 index 000000000000..1c5f84fa573a --- /dev/null +++ b/include/dt-bindings/sound/qcom,q6prm.h @@ -0,0 +1,205 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_Q6_PRM_H__ +#define __DT_BINDINGS_Q6_PRM_H__ + +/* Audio Front End (PRM) virtual ports IDs */ +#define HDMI_RX 1 +#define SLIMBUS_0_RX 2 +#define SLIMBUS_0_TX 3 +#define SLIMBUS_1_RX 4 +#define SLIMBUS_1_TX 5 +#define SLIMBUS_2_RX 6 +#define SLIMBUS_2_TX 7 +#define SLIMBUS_3_RX 8 +#define SLIMBUS_3_TX 9 +#define SLIMBUS_4_RX 10 +#define SLIMBUS_4_TX 11 +#define SLIMBUS_5_RX 12 +#define SLIMBUS_5_TX 13 +#define SLIMBUS_6_RX 14 +#define SLIMBUS_6_TX 15 +#define PRIMARY_MI2S_RX 16 +#define PRIMARY_MI2S_TX 17 +#define SECONDARY_MI2S_RX 18 +#define SECONDARY_MI2S_TX 19 +#define TERTIARY_MI2S_RX 20 +#define TERTIARY_MI2S_TX 21 +#define QUATERNARY_MI2S_RX 22 +#define QUATERNARY_MI2S_TX 23 +#define PRIMARY_TDM_RX_0 24 +#define PRIMARY_TDM_TX_0 25 +#define PRIMARY_TDM_RX_1 26 +#define PRIMARY_TDM_TX_1 27 +#define PRIMARY_TDM_RX_2 28 +#define PRIMARY_TDM_TX_2 29 +#define PRIMARY_TDM_RX_3 30 +#define PRIMARY_TDM_TX_3 31 +#define PRIMARY_TDM_RX_4 32 +#define PRIMARY_TDM_TX_4 33 +#define PRIMARY_TDM_RX_5 34 +#define PRIMARY_TDM_TX_5 35 +#define PRIMARY_TDM_RX_6 36 +#define PRIMARY_TDM_TX_6 37 +#define PRIMARY_TDM_RX_7 38 +#define PRIMARY_TDM_TX_7 39 +#define SECONDARY_TDM_RX_0 40 +#define SECONDARY_TDM_TX_0 41 +#define SECONDARY_TDM_RX_1 42 +#define SECONDARY_TDM_TX_1 43 +#define SECONDARY_TDM_RX_2 44 +#define SECONDARY_TDM_TX_2 45 +#define SECONDARY_TDM_RX_3 46 +#define SECONDARY_TDM_TX_3 47 +#define SECONDARY_TDM_RX_4 48 +#define SECONDARY_TDM_TX_4 49 +#define SECONDARY_TDM_RX_5 50 +#define SECONDARY_TDM_TX_5 51 +#define SECONDARY_TDM_RX_6 52 +#define SECONDARY_TDM_TX_6 53 +#define SECONDARY_TDM_RX_7 54 +#define SECONDARY_TDM_TX_7 55 +#define TERTIARY_TDM_RX_0 56 +#define TERTIARY_TDM_TX_0 57 +#define TERTIARY_TDM_RX_1 58 +#define TERTIARY_TDM_TX_1 59 +#define TERTIARY_TDM_RX_2 60 +#define TERTIARY_TDM_TX_2 61 +#define TERTIARY_TDM_RX_3 62 +#define TERTIARY_TDM_TX_3 63 +#define TERTIARY_TDM_RX_4 64 +#define TERTIARY_TDM_TX_4 65 +#define TERTIARY_TDM_RX_5 66 +#define TERTIARY_TDM_TX_5 67 +#define TERTIARY_TDM_RX_6 68 +#define TERTIARY_TDM_TX_6 69 +#define TERTIARY_TDM_RX_7 70 +#define TERTIARY_TDM_TX_7 71 +#define QUATERNARY_TDM_RX_0 72 +#define QUATERNARY_TDM_TX_0 73 +#define QUATERNARY_TDM_RX_1 74 +#define QUATERNARY_TDM_TX_1 75 +#define QUATERNARY_TDM_RX_2 76 +#define QUATERNARY_TDM_TX_2 77 +#define QUATERNARY_TDM_RX_3 78 +#define QUATERNARY_TDM_TX_3 79 +#define QUATERNARY_TDM_RX_4 80 +#define QUATERNARY_TDM_TX_4 81 +#define QUATERNARY_TDM_RX_5 82 +#define QUATERNARY_TDM_TX_5 83 +#define QUATERNARY_TDM_RX_6 84 +#define QUATERNARY_TDM_TX_6 85 +#define QUATERNARY_TDM_RX_7 86 +#define QUATERNARY_TDM_TX_7 87 +#define QUINARY_TDM_RX_0 88 +#define QUINARY_TDM_TX_0 89 +#define QUINARY_TDM_RX_1 90 +#define QUINARY_TDM_TX_1 91 +#define QUINARY_TDM_RX_2 92 +#define QUINARY_TDM_TX_2 93 +#define QUINARY_TDM_RX_3 94 +#define QUINARY_TDM_TX_3 95 +#define QUINARY_TDM_RX_4 96 +#define QUINARY_TDM_TX_4 97 +#define QUINARY_TDM_RX_5 98 +#define QUINARY_TDM_TX_5 99 +#define QUINARY_TDM_RX_6 100 +#define QUINARY_TDM_TX_6 101 +#define QUINARY_TDM_RX_7 102 +#define QUINARY_TDM_TX_7 103 +#define DISPLAY_PORT_RX 104 +#define WSA_CODEC_DMA_RX_0 105 +#define WSA_CODEC_DMA_TX_0 106 +#define WSA_CODEC_DMA_RX_1 107 +#define WSA_CODEC_DMA_TX_1 108 +#define WSA_CODEC_DMA_TX_2 109 +#define VA_CODEC_DMA_TX_0 110 +#define VA_CODEC_DMA_TX_1 111 +#define VA_CODEC_DMA_TX_2 112 +#define RX_CODEC_DMA_RX_0 113 +#define TX_CODEC_DMA_TX_0 114 +#define RX_CODEC_DMA_RX_1 115 +#define TX_CODEC_DMA_TX_1 116 +#define RX_CODEC_DMA_RX_2 117 +#define TX_CODEC_DMA_TX_2 118 +#define RX_CODEC_DMA_RX_3 119 +#define TX_CODEC_DMA_TX_3 120 +#define RX_CODEC_DMA_RX_4 121 +#define TX_CODEC_DMA_TX_4 122 +#define RX_CODEC_DMA_RX_5 123 +#define TX_CODEC_DMA_TX_5 124 +#define RX_CODEC_DMA_RX_6 125 +#define RX_CODEC_DMA_RX_7 126 + +#define LPASS_CLK_ID_PRI_MI2S_IBIT 1 +#define LPASS_CLK_ID_PRI_MI2S_EBIT 2 +#define LPASS_CLK_ID_SEC_MI2S_IBIT 3 +#define LPASS_CLK_ID_SEC_MI2S_EBIT 4 +#define LPASS_CLK_ID_TER_MI2S_IBIT 5 +#define LPASS_CLK_ID_TER_MI2S_EBIT 6 +#define LPASS_CLK_ID_QUAD_MI2S_IBIT 7 +#define LPASS_CLK_ID_QUAD_MI2S_EBIT 8 +#define LPASS_CLK_ID_SPEAKER_I2S_IBIT 9 +#define LPASS_CLK_ID_SPEAKER_I2S_EBIT 10 +#define LPASS_CLK_ID_SPEAKER_I2S_OSR 11 +#define LPASS_CLK_ID_QUI_MI2S_IBIT 12 +#define LPASS_CLK_ID_QUI_MI2S_EBIT 13 +#define LPASS_CLK_ID_SEN_MI2S_IBIT 14 +#define LPASS_CLK_ID_SEN_MI2S_EBIT 15 +#define LPASS_CLK_ID_INT0_MI2S_IBIT 16 +#define LPASS_CLK_ID_INT1_MI2S_IBIT 17 +#define LPASS_CLK_ID_INT2_MI2S_IBIT 18 +#define LPASS_CLK_ID_INT3_MI2S_IBIT 19 +#define LPASS_CLK_ID_INT4_MI2S_IBIT 20 +#define LPASS_CLK_ID_INT5_MI2S_IBIT 21 +#define LPASS_CLK_ID_INT6_MI2S_IBIT 22 +#define LPASS_CLK_ID_QUI_MI2S_OSR 23 +#define LPASS_CLK_ID_PRI_PCM_IBIT 24 +#define LPASS_CLK_ID_PRI_PCM_EBIT 25 +#define LPASS_CLK_ID_SEC_PCM_IBIT 26 +#define LPASS_CLK_ID_SEC_PCM_EBIT 27 +#define LPASS_CLK_ID_TER_PCM_IBIT 28 +#define LPASS_CLK_ID_TER_PCM_EBIT 29 +#define LPASS_CLK_ID_QUAD_PCM_IBIT 30 +#define LPASS_CLK_ID_QUAD_PCM_EBIT 31 +#define LPASS_CLK_ID_QUIN_PCM_IBIT 32 +#define LPASS_CLK_ID_QUIN_PCM_EBIT 33 +#define LPASS_CLK_ID_QUI_PCM_OSR 34 +#define LPASS_CLK_ID_PRI_TDM_IBIT 35 +#define LPASS_CLK_ID_PRI_TDM_EBIT 36 +#define LPASS_CLK_ID_SEC_TDM_IBIT 37 +#define LPASS_CLK_ID_SEC_TDM_EBIT 38 +#define LPASS_CLK_ID_TER_TDM_IBIT 39 +#define LPASS_CLK_ID_TER_TDM_EBIT 40 +#define LPASS_CLK_ID_QUAD_TDM_IBIT 41 +#define LPASS_CLK_ID_QUAD_TDM_EBIT 42 +#define LPASS_CLK_ID_QUIN_TDM_IBIT 43 +#define LPASS_CLK_ID_QUIN_TDM_EBIT 44 +#define LPASS_CLK_ID_QUIN_TDM_OSR 45 +#define LPASS_CLK_ID_MCLK_1 46 +#define LPASS_CLK_ID_MCLK_2 47 +#define LPASS_CLK_ID_MCLK_3 48 +#define LPASS_CLK_ID_MCLK_4 49 +#define LPASS_CLK_ID_INTERNAL_DIGITAL_CODEC_CORE 50 +#define LPASS_CLK_ID_INT_MCLK_0 51 +#define LPASS_CLK_ID_INT_MCLK_1 52 +#define LPASS_CLK_ID_MCLK_5 53 +#define LPASS_CLK_ID_WSA_CORE_MCLK 54 +#define LPASS_CLK_ID_WSA_CORE_NPL_MCLK 55 +#define LPASS_CLK_ID_VA_CORE_MCLK 56 +#define LPASS_CLK_ID_TX_CORE_MCLK 57 +#define LPASS_CLK_ID_TX_CORE_NPL_MCLK 58 +#define LPASS_CLK_ID_RX_CORE_MCLK 59 +#define LPASS_CLK_ID_RX_CORE_NPL_MCLK 60 +#define LPASS_CLK_ID_VA_CORE_2X_MCLK 61 + +#define LPASS_HW_MACRO_VOTE 102 +#define LPASS_HW_DCODEC_VOTE 103 + +#define Q6PRM_MAX_CLK_ID 104 + +#define LPASS_CLK_ATTRIBUTE_INVALID 0x0 +#define LPASS_CLK_ATTRIBUTE_COUPLE_NO 0x1 +#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVIDEND 0x2 +#define LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR 0x3 + +#endif /* __DT_BINDINGS_Q6_PRM_H__ */ diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 4eb1b1a7c1f7..fa3ab78b125e 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -109,12 +109,16 @@ config SND_SOC_QCOM_APM_DAI config SND_SOC_QCOM_APM_BEDAI tristate +config SND_SOC_QCOM_PRM + tristate + config SND_SOC_QCOM_AUDIOREACH tristate "SoC ALSA audio drives for Qualcomm AUDIOREACH" depends on QCOM_GPR select SND_SOC_TOPOLOGY select SND_SOC_QCOM_APM_DAI select SND_SOC_QCOM_APM_BEDAI + select SND_SOC_QCOM_PRM help Support for AudioReach in QDSP diff --git a/sound/soc/qcom/audioreach/Makefile b/sound/soc/qcom/audioreach/Makefile index e8651455b206..d9904201ccf0 100644 --- a/sound/soc/qcom/audioreach/Makefile +++ b/sound/soc/qcom/audioreach/Makefile @@ -2,9 +2,11 @@ snd-ar-objs := audioreach.o q6apm.o topology.o snd-apm-dai-objs := q6apm-dai.o snd-apm-bedai-objs := q6apm-bedai.o +snd-prm-objs := q6prm.o obj-$(CONFIG_SND_SOC_QCOM_AUDIOREACH) += snd-ar.o obj-$(CONFIG_SND_SOC_QCOM_APM_DAI) += snd-apm-dai.o obj-$(CONFIG_SND_SOC_QCOM_APM_BEDAI) += snd-apm-bedai.o +obj-$(CONFIG_SND_SOC_QCOM_PRM) += snd-prm.o diff --git a/sound/soc/qcom/audioreach/q6prm.c b/sound/soc/qcom/audioreach/q6prm.c new file mode 100644 index 000000000000..84a9ca3aa7fd --- /dev/null +++ b/sound/soc/qcom/audioreach/q6prm.c @@ -0,0 +1,412 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2021, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "audioreach.h" + +#define Q6PRM_CLK(id) &(struct q6prm_clk) { \ + .clk_id = id, \ + .afe_clk_id = Q6PRM_##id, \ + .name = #id, \ + .attributes = LPASS_CLK_ATTRIBUTE_COUPLE_NO, \ + .rate = 19200000, \ + .hw.init = &(struct clk_init_data) { \ + .ops = &clk_q6prm_ops, \ + .name = #id, \ + }, \ + } + +#define Q6PRM_VOTE_CLK(id, blkid) &(struct q6prm_clk) { \ + .clk_id = id, \ + .afe_clk_id = blkid, \ + .hw.init = &(struct clk_init_data) { \ + .ops = &clk_vote_q6prm_ops, \ + .name = #id, \ + }, \ + } + +struct q6prm_clk { + struct device *dev; + int clk_id; + int afe_clk_id; + char *name; + int attributes; + int rate; + uint32_t handle; + struct clk_hw hw; +}; +#define to_q6prm_clk(_hw) container_of(_hw, struct q6prm_clk, hw) + +struct q6prm { + struct device *dev; + struct gpr_device *gdev; + wait_queue_head_t wait; + struct gpr_ibasic_rsp_result_t result; + struct mutex lock; + struct q6prm_clk **clks; + int num_clks; +}; + +#define PRM_CMD_REQUEST_HW_RSC 0x0100100F +#define PRM_CMD_RSP_REQUEST_HW_RSC 0x02001002 +#define PRM_CMD_RELEASE_HW_RSC 0x01001010 +#define PRM_CMD_RSP_RELEASE_HW_RSC 0x02001003 + +#define PARAM_ID_RSC_HW_CORE 0x08001032 +#define PARAM_ID_RSC_LPASS_CORE 0x0800102B +#define PARAM_ID_RSC_AUDIO_HW_CLK 0x0800102C + +#define Q6PRM_LPASS_CLK_ID_WSA_CORE_MCLK 0x305 +#define Q6PRM_LPASS_CLK_ID_WSA_CORE_NPL_MCLK 0x306 + +#define Q6PRM_LPASS_CLK_ID_VA_CORE_MCLK 0x307 +#define Q6PRM_LPASS_CLK_ID_VA_CORE_2X_MCLK 0x308 + +#define Q6PRM_LPASS_CLK_ID_TX_CORE_MCLK 0x30c +#define Q6PRM_LPASS_CLK_ID_TX_CORE_NPL_MCLK 0x30d + +#define Q6PRM_LPASS_CLK_ID_RX_CORE_MCLK 0x30e +#define Q6PRM_LPASS_CLK_ID_RX_CORE_NPL_MCLK 0x30f + +#define Q6PRM_LPASS_CLK_SRC_INTERNAL 1 +#define Q6PRM_LPASS_CLK_ROOT_DEFAULT 0 +#define Q6PRM_HW_CORE_ID_LPASS 1 +#define Q6PRM_HW_CORE_ID_DCODEC 2 + +struct prm_cmd_request_hw_core { + struct apm_module_param_data param_data; + uint32_t hw_clk_id; +} __packed; + +struct prm_cmd_request_rsc { + struct apm_module_param_data param_data; + uint32_t num_clk_id; + struct audio_hw_clk_cfg clock_ids[1]; +} __packed; + +struct prm_cmd_release_rsc { + struct apm_module_param_data param_data; + uint32_t num_clk_id; + struct audio_hw_clk_cfg clock_ids[1]; +} __packed; + +static int q6prm_send_cmd_sync(struct q6prm *prm, struct gpr_pkt *pkt, + uint32_t rsp_opcode) +{ + struct gpr_device *gdev = prm->gdev; + struct gpr_hdr *hdr = &pkt->hdr; + int rc; + + mutex_lock(&prm->lock); + prm->result.opcode = 0; + prm->result.status = 0; + + rc = gpr_send_pkt(prm->gdev, pkt); + if (rc < 0) + goto err; + + if (rsp_opcode) + rc = wait_event_timeout(prm->wait, + (prm->result.opcode == hdr->opcode) || + (prm->result.opcode == rsp_opcode), + 5 * HZ); + else + rc = wait_event_timeout(prm->wait, + (prm->result.opcode == hdr->opcode), + 5 * HZ); + + if (!rc) { + dev_err(&gdev->dev, "CMD timeout for [%x] opcode\n", + hdr->opcode); + rc = -ETIMEDOUT; + } else if (prm->result.status > 0) { + dev_err(&gdev->dev, "DSP returned error[%x] %x\n", hdr->opcode, + prm->result.status); + rc = -EINVAL; + } else { + dev_err(&gdev->dev, "DSP returned [%x]\n", + prm->result.status); + rc = 0; + } + +err: + mutex_unlock(&prm->lock); + return rc; +} + +static int q6prm_set_hw_core_req(struct device *dev, uint32_t hw_block_id, bool enable) +{ + struct prm_cmd_request_hw_core *req; + struct apm_module_param_data *param_data; + struct gpr_pkt *pkt; + struct q6prm *prm = dev_get_drvdata(dev); + struct gpr_device *gdev = prm->gdev; + void *p; + int rc = 0; + uint32_t opcode, rsp_opcode; + + if (enable) { + opcode = PRM_CMD_REQUEST_HW_RSC; + rsp_opcode = PRM_CMD_RSP_REQUEST_HW_RSC; + } else { + opcode = PRM_CMD_RELEASE_HW_RSC; + rsp_opcode = PRM_CMD_RSP_RELEASE_HW_RSC; + } + + p = audioreach_alloc_cmd_pkt(sizeof(*req), opcode, 0, gdev->port.id, + GPR_PRM_MODULE_IID); + if (IS_ERR(p)) + return -ENOMEM; + + pkt = p; + req = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + param_data = &req->param_data; + + param_data->module_instance_id = GPR_PRM_MODULE_IID; + param_data->error_code = 0; + param_data->param_id = PARAM_ID_RSC_HW_CORE; + param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; + + req->hw_clk_id = hw_block_id; + + q6prm_send_cmd_sync(prm, pkt, rsp_opcode); + + kfree(pkt); + + return rc; +} + +static int q6prm_set_lpass_clock(struct device *dev, int clk_id, int clk_attr, + int clk_root, unsigned int freq) +{ + struct prm_cmd_request_rsc *req; + struct apm_module_param_data *param_data; + struct gpr_pkt *pkt; + struct q6prm *prm = dev_get_drvdata(dev); + struct gpr_device *gdev = prm->gdev; + void *p; + int rc = 0; + + p = audioreach_alloc_cmd_pkt(sizeof(*req), PRM_CMD_REQUEST_HW_RSC, + 0, gdev->port.id, GPR_PRM_MODULE_IID); + if (IS_ERR(p)) + return -ENOMEM; + + pkt = p; + req = p + GPR_HDR_SIZE + APM_CMD_HDR_SIZE; + + param_data = &req->param_data; + + param_data->module_instance_id = GPR_PRM_MODULE_IID; + param_data->error_code = 0; + param_data->param_id = PARAM_ID_RSC_AUDIO_HW_CLK; + param_data->param_size = sizeof(*req) - APM_MODULE_PARAM_DATA_SIZE; + + req->num_clk_id = 1; + req->clock_ids[0].clock_id = clk_id; + req->clock_ids[0].clock_freq = freq; + req->clock_ids[0].clock_attri = clk_attr; + req->clock_ids[0].clock_root = clk_root; + + q6prm_send_cmd_sync(prm, pkt, PRM_CMD_RSP_REQUEST_HW_RSC); + + kfree(pkt); + + return rc; +} + +static int prm_callback(struct gpr_resp_pkt *data, void *priv, int op) +{ + struct gpr_device *gdev = priv; + struct q6prm *prm = dev_get_drvdata(&gdev->dev); + struct gpr_ibasic_rsp_result_t *result; + struct gpr_hdr *hdr = &data->hdr; + + result = data->payload; + + switch (hdr->opcode) { + case PRM_CMD_RSP_REQUEST_HW_RSC: + case PRM_CMD_RSP_RELEASE_HW_RSC: + prm->result.opcode = hdr->opcode; + prm->result.status = result->status; + wake_up(&prm->wait); + break; + default: + break; + } + + return 0; +} + +static int clk_q6prm_prepare(struct clk_hw *hw) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + return q6prm_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes, + Q6PRM_LPASS_CLK_ROOT_DEFAULT, clk->rate); +} + +static void clk_q6prm_unprepare(struct clk_hw *hw) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + q6prm_set_lpass_clock(clk->dev, clk->afe_clk_id, clk->attributes, + Q6PRM_LPASS_CLK_ROOT_DEFAULT, 0); +} + +static int clk_q6prm_set_rate(struct clk_hw *hw, unsigned long rate, + unsigned long parent_rate) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + clk->rate = rate; + + return 0; +} + +static unsigned long clk_q6prm_recalc_rate(struct clk_hw *hw, + unsigned long parent_rate) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + return clk->rate; +} + +static long clk_q6prm_round_rate(struct clk_hw *hw, unsigned long rate, + unsigned long *parent_rate) +{ + return rate; +} + +static const struct clk_ops clk_q6prm_ops = { + .prepare = clk_q6prm_prepare, + .unprepare = clk_q6prm_unprepare, + .set_rate = clk_q6prm_set_rate, + .round_rate = clk_q6prm_round_rate, + .recalc_rate = clk_q6prm_recalc_rate, +}; + +static int clk_vote_q6prm_block(struct clk_hw *hw) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + return q6prm_set_hw_core_req(clk->dev, clk->afe_clk_id, true); +} + +static void clk_unvote_q6prm_block(struct clk_hw *hw) +{ + struct q6prm_clk *clk = to_q6prm_clk(hw); + + q6prm_set_hw_core_req(clk->dev, clk->afe_clk_id, false); +} + +static const struct clk_ops clk_vote_q6prm_ops = { + .prepare = clk_vote_q6prm_block, + .unprepare = clk_unvote_q6prm_block, +}; + +static struct q6prm_clk *q6prm_clks[Q6PRM_MAX_CLK_ID] = { + [LPASS_CLK_ID_WSA_CORE_MCLK] = Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_MCLK), + [LPASS_CLK_ID_WSA_CORE_NPL_MCLK] = + Q6PRM_CLK(LPASS_CLK_ID_WSA_CORE_NPL_MCLK), + [LPASS_CLK_ID_VA_CORE_MCLK] = Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_MCLK), + [LPASS_CLK_ID_TX_CORE_MCLK] = Q6PRM_CLK(LPASS_CLK_ID_TX_CORE_MCLK), + [LPASS_CLK_ID_TX_CORE_NPL_MCLK] = + Q6PRM_CLK(LPASS_CLK_ID_TX_CORE_NPL_MCLK), + [LPASS_CLK_ID_RX_CORE_MCLK] = Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_MCLK), + [LPASS_CLK_ID_RX_CORE_NPL_MCLK] = + Q6PRM_CLK(LPASS_CLK_ID_RX_CORE_NPL_MCLK), + [LPASS_CLK_ID_VA_CORE_2X_MCLK] = + Q6PRM_CLK(LPASS_CLK_ID_VA_CORE_2X_MCLK), + [LPASS_HW_MACRO_VOTE] = Q6PRM_VOTE_CLK(LPASS_HW_MACRO_VOTE, + Q6PRM_HW_CORE_ID_LPASS), + [LPASS_HW_DCODEC_VOTE] = Q6PRM_VOTE_CLK(LPASS_HW_DCODEC_VOTE, + Q6PRM_HW_CORE_ID_DCODEC), +}; + +static struct clk_hw *q6prm_of_clk_hw_get(struct of_phandle_args *clkspec, + void *data) +{ + struct q6prm *cc = data; + unsigned int idx = clkspec->args[0]; + unsigned int attr = clkspec->args[1]; + + if (idx >= cc->num_clks || attr > LPASS_CLK_ATTRIBUTE_COUPLE_DIVISOR) { + dev_err(cc->dev, "Invalid clk specifier (%d, %d)\n", idx, attr); + return ERR_PTR(-EINVAL); + } + + if (cc->clks[idx]) { + cc->clks[idx]->attributes = attr; + return &cc->clks[idx]->hw; + } + + return ERR_PTR(-ENOENT); +} + +static int prm_probe(struct gpr_device *gdev) +{ + struct device *dev = &gdev->dev; + struct q6prm *cc; + int i, ret; + + cc = devm_kzalloc(dev, sizeof(*cc), GFP_KERNEL); + if (!cc) + return -ENOMEM; + + cc->dev = dev; + cc->gdev = gdev; + mutex_init(&cc->lock); + init_waitqueue_head(&cc->wait); + cc->clks = &q6prm_clks[0]; + cc->num_clks = ARRAY_SIZE(q6prm_clks); + for (i = 0; i < ARRAY_SIZE(q6prm_clks); i++) { + if (!q6prm_clks[i]) + continue; + + q6prm_clks[i]->dev = dev; + + ret = devm_clk_hw_register(dev, &q6prm_clks[i]->hw); + if (ret) + return ret; + } + + ret = of_clk_add_hw_provider(dev->of_node, q6prm_of_clk_hw_get, cc); + if (ret) + return ret; + + dev_set_drvdata(dev, cc); + + return 0; +} + +static const struct of_device_id prm_device_id[] = { + { .compatible = "qcom,q6prm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, prm_device_id); + +static struct gpr_driver prm_driver = { + .probe = prm_probe, + .callback = prm_callback, + .driver = { + .name = "qcom-prm", + .of_match_table = of_match_ptr(prm_device_id), + }, +}; + +module_gpr_driver(prm_driver); +MODULE_DESCRIPTION("Audio Process Manager"); +MODULE_LICENSE("GPL v2"); From patchwork Mon Jun 7 15:28:35 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 455400 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-16.8 required=3.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID, HEADER_FROM_DIFFERENT_DOMAINS, INCLUDES_CR_TRAILER, INCLUDES_PATCH, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,USER_AGENT_GIT autolearn=unavailable autolearn_force=no version=3.4.0 Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 68986C47094 for ; Mon, 7 Jun 2021 15:34:54 +0000 (UTC) Received: from alsa0.perex.cz (alsa0.perex.cz [77.48.224.243]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id A331460FF1 for ; Mon, 7 Jun 2021 15:34:53 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mail.kernel.org A331460FF1 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=linaro.org Authentication-Results: mail.kernel.org; spf=pass smtp.mailfrom=alsa-devel-bounces@alsa-project.org Received: from alsa1.perex.cz (alsa1.perex.cz [207.180.221.201]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by alsa0.perex.cz (Postfix) with ESMTPS id 35A3D168B; Mon, 7 Jun 2021 17:34:02 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa0.perex.cz 35A3D168B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=alsa-project.org; s=default; t=1623080092; bh=DmlLpbLKsgqcNtfmLN5WMY5K/nPNqbBFcCYWZVfrPTs=; h=From:To:Subject:Date:In-Reply-To:References:Cc:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: From; b=NuXmc5YtcRfSXLp8xfzDtZy+eM2WKql8wmUEGgLtFY47yK0ZVXJSyZEfAeJr5J3tV UIpiOGfZ0dPWOp/dciXgwP+uvIMGULPWws92pYYyhC3aSnVlkCIzuV8x2KyaSslZPJ tXQqoDiXK/uNfQAkSbXOzn9jOG0G07SovfNCCuqg= Received: from alsa1.perex.cz (localhost.localdomain [127.0.0.1]) by alsa1.perex.cz (Postfix) with ESMTP id 9EEA0F804FD; Mon, 7 Jun 2021 17:30:14 +0200 (CEST) Received: by alsa1.perex.cz (Postfix, from userid 50401) id 24487F8027C; Mon, 7 Jun 2021 17:29:39 +0200 (CEST) Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by alsa1.perex.cz (Postfix) with ESMTPS id A54A1F804C1 for ; Mon, 7 Jun 2021 17:29:16 +0200 (CEST) DKIM-Filter: OpenDKIM Filter v2.11.0 alsa1.perex.cz A54A1F804C1 Authentication-Results: alsa1.perex.cz; dkim=pass (2048-bit key) header.d=linaro.org header.i=@linaro.org header.b="UDhiFSqx" Received: by mail-wr1-x42a.google.com with SMTP id r9so1405802wrz.10 for ; Mon, 07 Jun 2021 08:29:16 -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 :mime-version:content-transfer-encoding; bh=lzk4lCLmAXbNCfDcTx4wmKLjACEaxBk+nh7dbPXaa38=; b=UDhiFSqxE1s5YjiU15JeFLbAqZTe5nrAp1XpGXbX3+6iigSEPtlXwzTkvntFfFKvUR CpBxINqcZhWT0UC1sfuoxFLEQRwISz4l/4Eiv4J3HFKjSN8JJTn4d+7SZ+3azQAoxnVh AxmwdoO+fl8Jq+VPXz37aaoKN8tzydm2SBo7HzVGMsl3tfb/UdJ2T/cO8q4jTYYecott QCPxHQ2SW6oWTs0oL1nM8oi6jOmXMtoR1gvlZD4nbeLwiSh5fXpXltWklGS9irK9lX/V WZlzDpgHayq+NoLyEkq675dzef9ZyF/MhtS5y3zUcKPzpZTzxk2P59ioGDKB2+5D2dfy cTIA== 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:mime-version:content-transfer-encoding; bh=lzk4lCLmAXbNCfDcTx4wmKLjACEaxBk+nh7dbPXaa38=; b=nZzUcefiVLlk4H1vlX0IX6WEZJc2cQ1JHEZYtPjX6AXNGowY5YkQAKaqJbsn0nLvwz +2aj6Amxtslkx9YdbOOo9PtF/OX4b6dtkmvQXBtrj5cTQDJ4atcmOezSo0LIi3NUvr7G UBHXTTHi5MGA12AXRasrtGSawclDcihJbKNbgEGHT9syg/PBq0zrx0v4N2I/veiU/zs6 oixOIh0+wcFwrS/veX09tl0n92d7WVVX2ds59mOzrk3HXcpjQW/LvtU4rpt+5L8NG8uS JotGUn5EOzzVx/gizfuKqHN9C1XcNaG8dHeD8FhboOJtW5FqKEfqZWb5qJp54DINErXI Sw5w== X-Gm-Message-State: AOAM530IR1joP+4mdhOUsYwPHYbw6ucFneuaKDcMsBI+EkZ/sSGbmNjU k8tZHlaNnzFoTiZmWsm+nBF5OA== X-Google-Smtp-Source: ABdhPJwzX/sWF8yrXRuPQ0fIro1jD8AuiOKC8LpOEgmpevy8/2G9wmoj3HHnFWe4aaCpWakoNCyS1Q== X-Received: by 2002:a05:6000:18a8:: with SMTP id b8mr17320018wri.208.1623079755937; Mon, 07 Jun 2021 08:29:15 -0700 (PDT) Received: from srini-hackbox.lan (cpc86377-aztw32-2-0-cust226.18-1.cable.virginm.net. [92.233.226.227]) by smtp.gmail.com with ESMTPSA id q3sm16370170wrr.43.2021.06.07.08.29.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 07 Jun 2021 08:29:15 -0700 (PDT) From: Srinivas Kandagatla To: bjorn.andersson@linaro.org, broonie@kernel.org Subject: [RFC PATCH 12/13] ASoC: qcom: dt-bindings: add audioreach soundcard compatibles Date: Mon, 7 Jun 2021 16:28:35 +0100 Message-Id: <20210607152836.17154-13-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.21.0 In-Reply-To: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> References: <20210607152836.17154-1-srinivas.kandagatla@linaro.org> MIME-Version: 1.0 Cc: robh@kernel.org, alsa-devel@alsa-project.org, bgoswami@codeaurora.org, devicetree@vger.kernel.org, tiwai@suse.de, lgirdwood@gmail.com, plai@codeaurora.org, linux-kernel@vger.kernel.org X-BeenThere: alsa-devel@alsa-project.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: "Alsa-devel mailing list for ALSA developers - http://www.alsa-project.org" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: alsa-devel-bounces@alsa-project.org Sender: "Alsa-devel" Add compatible strings for AudioReach DSP firmware based soundcards. Signed-off-by: Srinivas Kandagatla --- .../bindings/sound/qcom,sm8250.yaml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index 72ad9ab91832..551f4fe04749 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -18,6 +18,8 @@ properties: oneOf: - const: qcom,sm8250-sndcard - const: qcom,qrb5165-rb5-sndcard + - const: qcom,sm8250-audioreach-sndcard + - const: qcom,qrb5165-rb5-audioreach-sndcard audio-routing: $ref: /schemas/types.yaml#/definitions/non-unique-string-array @@ -157,3 +159,44 @@ examples: }; }; }; +#--------------------------- +# AudioReach based dai links +#--------------------------- + - | + #include + sound { + compatible = "qcom,qrb5165-rb5-audioreach-sndcard"; + model = "Qualcomm-qrb5165-RB5-WSA8815-Speakers-DMIC0"; + audio-routing = "SpkrLeft IN", "WSA_SPK1 OUT", + "SpkrRight IN", "WSA_SPK2 OUT"; + + wsa-dai-link { + link-name = "WSA Playback"; + cpu { + sound-dai = <&q6apmbedai WSA_CODEC_DMA_RX_0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + + codec { + sound-dai = <&left_spkr>, <&right_spkr>, <&swr0 0>, <&wsamacro>; + }; + }; + + va-dai-link { + link-name = "VA Capture"; + cpu { + sound-dai = <&q6apmbedai VA_CODEC_DMA_TX_0>; + }; + + platform { + sound-dai = <&q6apm>; + }; + + codec { + sound-dai = <&vamacro 0>; + }; + }; + }