From patchwork Wed May 9 12:56:12 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135286 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5618741lji; Wed, 9 May 2018 06:07:23 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqj9lb+Ph/tJyctSgzaFKVLm60AwZgU6Jjj8PIZ3j7BeX1H+okJYIh7xZjR5iZM7fRQRVdH X-Received: by 10.98.75.139 with SMTP id d11mr44061319pfj.244.1525871243676; Wed, 09 May 2018 06:07:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871243; cv=none; d=google.com; s=arc-20160816; b=E/6MQSM6v5XrpYqtVzWonNIaciTZVg43jrLOON5PbNQQzOXjm7Q9FV7fEgstlRfqNd bvahjMAaPll6G7WXXiXY9/PtMbVMhYzuUa1Nl1M+b0QcC9BoukprffKcgkMSo96cIzdB n7vhzhhwfaPkuFdJXVgrsFl04wOKLMdJCKoi7wbhz6JfocWxuQyDOBqRVSqfDyfNV2rY qUYDFgyF7wvOsJYkpMj0DtjnTdZc6OOt7fRtVMBphYjZb/bKy9S4QUj1rNz8Nbuq48VL DhpiQfzmhMPjrcmgITsaQ1x4RJwGPVP2JSY0f+fBAaZwBl+UgdsOHgyhm8y+DqZgPi+B AQbg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=KZrt5teWAbacRWTd8ubWhWGRHumLg8s+/jHOxAiG3FI=; b=kIJzVoH2UPTTExrB2K4Mjcx4J+ky48mJNh7b2pE+3RTjd0zt4ZsL5SzkHegsQ6xYKp phrwKEn71JJL2Z5nU/Gk4Exo4cIBjGq49ghGNHPk95mvEEpqAqe4xdhalECyNbvtHxaM 1wn1rP6Rq/Pp9j0/C+BlXX6/CxW7QMWOhyH2OhqoA32GVOWKzGzGS1JsjiNtOTGOPVQg haMsQf4MvF1sKdzfN6JRl8tW0R5h/caNjs+mhkU7BYrx0sD2ZINARk5CkW4WH4AY3GQu Fwq7jdm0PfnjfJ/967f8TZpzoebabX/TuSJde1DYBnCwXE/n5CEIe5JEVQzgUZThR3z7 1JzA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=b0SW7P6F; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o6-v6si8245583pls.234.2018.05.09.06.07.23; Wed, 09 May 2018 06:07:23 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=b0SW7P6F; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935028AbeEINHV (ORCPT + 29 others); Wed, 9 May 2018 09:07:21 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:35078 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935035AbeEINAj (ORCPT ); Wed, 9 May 2018 09:00:39 -0400 Received: by mail-wm0-f66.google.com with SMTP id o78-v6so27742708wmg.0 for ; Wed, 09 May 2018 06:00:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=KZrt5teWAbacRWTd8ubWhWGRHumLg8s+/jHOxAiG3FI=; b=b0SW7P6FLwvVs3TJsqpwGh93G8v7v3HLd0S7iYJi6rq98CgtBrGeokjw6esr6tiJCH k4J8CS3yS0I9JmygzoJd5y+7vGpn9wBALSaIDXFd+hBlv6Xw22Xr4nwzCKUHCq6+A3bG o4+obCM6ZrCsicqIvw+TG4Y7R/2rWs2hT/uMg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=KZrt5teWAbacRWTd8ubWhWGRHumLg8s+/jHOxAiG3FI=; b=Os7wSgpAwvFKVo7PIY7LuTlp6k9yejkJrJPpNxElDpNTPSEWG+YIdWhWU9Y2h4Van3 8VKKgkIyqoRV38dj3QGKX/PEryA4ppunqmk/GxmTwinTxEi4R+c43LlnoLYTU+t3YtKT BpGg1xkIBSVyoODdHFfFfyYYXifwJMthvX/YrPDov2buOZsbeURy4d7V6ZL9F8pvFB/+ kOWNkyOwtEAyTA/LdZ+sVDlCaIYIAwO03K59cvZmVP1MdJFFyMttR6pWAmz/yTcR0VFa 6mY+78jV01/HdFzHt0LifId1VaDl43TOysSeDpPsJXoKcOTwTDB/0xZS2GoV4hpuojtk 70sQ== X-Gm-Message-State: ALKqPwdGqw+QoD4AiRO1w3dlIWVx39viMhfKKBTpLmbWS6bSdd5cIvUg EsWADqAx4yuzJhR48O7JW6N20A== X-Received: by 10.28.10.149 with SMTP id 143mr5646076wmk.134.1525870837972; Wed, 09 May 2018 06:00:37 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.36 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:37 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 01/24] soc: qcom dt-bindings: Add APR bus bindings Date: Wed, 9 May 2018 13:56:12 +0100 Message-Id: <20180509125635.5653-2-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch add dt bindings for Qualcomm APR (Asynchronous Packet Router) bus driver. This bus is used for communicating with DSP which provides audio and various other services to cpu. Signed-off-by: Srinivas Kandagatla Reviewed-by: Rob Herring Reviewed-by: Bjorn Andersson Reviewed-by: Banajit Goswami --- .../devicetree/bindings/soc/qcom/qcom,apr.txt | 84 ++++++++++++++++++++++ include/dt-bindings/soc/qcom,apr.h | 28 ++++++++ 2 files changed, 112 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt create mode 100644 include/dt-bindings/soc/qcom,apr.h -- 2.16.2 diff --git a/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt new file mode 100644 index 000000000000..bcc612cc7423 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/qcom/qcom,apr.txt @@ -0,0 +1,84 @@ +Qualcomm APR (Asynchronous Packet Router) binding + +This binding describes the Qualcomm APR. APR is a IPC protocol for +communication between Application processor and QDSP. APR is mainly +used for audio/voice services on the QDSP. + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,apr-v", example "qcom,apr-v2" + +- reg + Usage: required + Value type: + Definition: Destination processor ID. + Possible values are : + 1 - APR simulator + 2 - PC + 3 - MODEM + 4 - ADSP + 5 - APPS + 6 - MODEM2 + 7 - APPS2 + += APR SERVICES +Each subnode of the APR node represents service tied to this apr. The name +of the nodes are not important. The properties of these nodes are defined +by the individual bindings for the specific service +- All APR services MUST contain the following property: + +- reg + Usage: required + Value type: + Definition: APR Service ID + Possible values are : + 3 - DSP Core Service + 4 - Audio Front End Service. + 5 - Voice Stream Manager Service. + 6 - Voice processing manager. + 7 - Audio Stream Manager Service. + 8 - Audio Device Manager Service. + 9 - Multimode voice manager. + 10 - Core voice stream. + 11 - Core voice processor. + 12 - Ultrasound stream manager. + 13 - Listen stream manager. + += EXAMPLE +The following example represents a QDSP based sound card on a MSM8996 device +which uses apr as communication between Apps and QDSP. + + apr@4 { + compatible = "qcom,apr-v2"; + reg = ; + + q6core@3 { + compatible = "qcom,q6core"; + reg = ; + }; + + q6afe@4 { + compatible = "qcom,q6afe"; + reg = ; + + dais { + #sound-dai-cells = <1>; + hdmi@1 { + reg = <1>; + }; + }; + }; + + q6asm@7 { + compatible = "qcom,q6asm"; + reg = ; + ... + }; + + q6adm@8 { + compatible = "qcom,q6adm"; + reg = ; + ... + }; + }; diff --git a/include/dt-bindings/soc/qcom,apr.h b/include/dt-bindings/soc/qcom,apr.h new file mode 100644 index 000000000000..006362400c0f --- /dev/null +++ b/include/dt-bindings/soc/qcom,apr.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __DT_BINDINGS_QCOM_APR_H +#define __DT_BINDINGS_QCOM_APR_H + +/* Domain IDs */ +#define APR_DOMAIN_SIM 0x1 +#define APR_DOMAIN_PC 0x2 +#define APR_DOMAIN_MODEM 0x3 +#define APR_DOMAIN_ADSP 0x4 +#define APR_DOMAIN_APPS 0x5 +#define APR_DOMAIN_MAX 0x6 + +/* ADSP service IDs */ +#define APR_SVC_ADSP_CORE 0x3 +#define APR_SVC_AFE 0x4 +#define APR_SVC_VSM 0x5 +#define APR_SVC_VPM 0x6 +#define APR_SVC_ASM 0x7 +#define APR_SVC_ADM 0x8 +#define APR_SVC_ADSP_MVM 0x09 +#define APR_SVC_ADSP_CVS 0x0A +#define APR_SVC_ADSP_CVP 0x0B +#define APR_SVC_USM 0x0C +#define APR_SVC_LSM 0x0D +#define APR_SVC_VIDC 0x16 +#define APR_SVC_MAX 0x17 + +#endif /* __DT_BINDINGS_QCOM_APR_H */ From patchwork Wed May 9 12:56:13 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135262 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5609401lji; Wed, 9 May 2018 06:00:52 -0700 (PDT) X-Google-Smtp-Source: AB8JxZoJZpbHBKBHcJvkiB94niYRhvquyX2gMf/aOWMii175GfQ9/GYHafD+Iz8GhLhKixWtSkKb X-Received: by 10.98.73.22 with SMTP id w22mr35585085pfa.63.1525870852443; Wed, 09 May 2018 06:00:52 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525870852; cv=none; d=google.com; s=arc-20160816; b=fep5nua9y9PNgpf2kL3YAuyw2c5G2Yjblh0HCg2owmBy8fjs9S/JsKDD1aB0epvAEv 3R1+cGsn/u7VVELA02Unalu2Y2qm0LnZ2EczLxlIiFQ9LjaL6ow630yWdHyumn6CLgtj ikg+0oHiCvXP1FaFCcGkPlOxwMpN4A8IN8AqlnwpEq7+Dhx9ydRXS0J8XLFxreUgjqif ggNd7X/RHVWkxQzSecaxGxpobfngfE2JELcs6dNeyOZgEPBuBIAykN22iQHvfL4Mi9fm 7YPTFG/E6cDE3aYLhVu87vU+JiCofoFtY7sAFpTQ3Bnwmjur+2weGsIU9SiPLhkO0ha3 f58Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=5eOk7Os7bnH3jXQcC1qI4T5QgxAYu6eaz9tCULGNXW0=; b=ewXLPsiT1nhy8CCws+32ZvizSwNVbWlxrATZx6IMnXWIlrK6/0nZd5GWkS9GTiy+Y7 zjKcQD5S7DkX6+n1Cl8IQ1YuOYncJBdlRRUv85AD9MxXijSBg6z1a3dBTxtKv+C8zp8J tLmvuzxW3vaObBIaKIpRLNFARRvscYYnwIQXtu5Pr+WbGpUw5WnzORAI7ThKIQrnERJ6 vXc4PhEtU4BH+HgnQpMmtc/3dIbLYXCNUi68JlqRT2mlkumaL2oUVSvquz+wMI1tc1pc mthyL8uTuZeDT47J6TMVo/DjpnktezH3c0irLS7HNV17Ycy0egkUpkTQB5H9Vi7nnDTY XOlQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=DFsugrZr; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id w66si27030291pfj.144.2018.05.09.06.00.52; Wed, 09 May 2018 06:00:52 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=DFsugrZr; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S934857AbeEINAt (ORCPT + 29 others); Wed, 9 May 2018 09:00:49 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:52711 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934912AbeEINAl (ORCPT ); Wed, 9 May 2018 09:00:41 -0400 Received: by mail-wm0-f66.google.com with SMTP id w194so24484697wmf.2 for ; Wed, 09 May 2018 06:00:40 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=5eOk7Os7bnH3jXQcC1qI4T5QgxAYu6eaz9tCULGNXW0=; b=DFsugrZrLuMIlfcEG/+qNpVJJX1VRaQYOXdYfSGR2p6ahBELAbOK+MLfzdi7nKfiZP WgxuVR3loyOptlTuto41wunAhVrH24lIYZn2mPJWLQVQqMjhuQU5x/yg8Jne2az4VjyW a2/O/M2SQtbSeFnd25CIZhAk4CU2CLDt+027k= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=5eOk7Os7bnH3jXQcC1qI4T5QgxAYu6eaz9tCULGNXW0=; b=IhnDn59Pwuzsfr++HeiFoEvVQzCrViR0zmnQUIul3NjMqjMl6NzSGfmKyv2Hb5WB9V AuGL0BKlo4XEZrl00bOK29Hkohs4lHA47tWOfgTlyFCtm4YfHmOcIfm8Ya6hx3CdvQQw viKOSNtQ3sChEL5t6E8OY2o4gk4tkDRXRa/zG6wmZrR9QNk2hSPrJGI95o1XrJbpokHp 8yXE44K1prBGpROq4bEyL/6d9+g/vk7bBKd0kMuK3zf2sNjI5byE66uhuPRxs+J8nU0J cOOL05jAMzhosCT42VOMGxBSP4bOxBOWzHQVo47zYU0pV2MxVm3bsNgTWKihDAm4JyQq 9SQA== X-Gm-Message-State: ALKqPwerq5N4cY2+Dk5fHoVoHFFrzM8Vegup+qZW+drQdpL1HEL//jVM IT8EGiVTAURZoOB6hZhr+ghVQA== X-Received: by 2002:a1c:bf52:: with SMTP id p79-v6mr5657924wmf.43.1525870839466; Wed, 09 May 2018 06:00:39 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.38 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:38 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 02/24] soc: qcom: Add APR bus driver Date: Wed, 9 May 2018 13:56:13 +0100 Message-Id: <20180509125635.5653-3-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to APR bus (Asynchronous Packet Router) driver. APR driver is made as a bus driver so that the apr devices can added removed more dynamically depending on the state of the services on the dsp. APR is used for communication between application processor and QDSP to use services on QDSP like Audio and others. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Acked-by: Andy Gross Reviewed-by: Bjorn Andersson --- drivers/soc/qcom/Kconfig | 9 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/apr.c | 378 ++++++++++++++++++++++++++++++++++++++++ include/linux/mod_devicetable.h | 11 ++ include/linux/soc/qcom/apr.h | 128 ++++++++++++++ 5 files changed, 527 insertions(+) create mode 100644 drivers/soc/qcom/apr.c create mode 100644 include/linux/soc/qcom/apr.h -- 2.16.2 diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 5c4535b545cc..d053f2634c67 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -108,4 +108,13 @@ config QCOM_WCNSS_CTRL Client driver for the WCNSS_CTRL SMD channel, used to download nv firmware to a newly booted WCNSS chip. +config QCOM_APR + tristate "Qualcomm APR Bus (Asynchronous Packet Router)" + depends on ARCH_QCOM + depends on RPMSG + help + Enable APR IPC protocol support between + application processor and QDSP6. APR is + used by audio driver to configure QDSP6 + ASM, ADM and AFE modules. endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index dcebf2814e6d..39de5dee55d9 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -12,3 +12,4 @@ obj-$(CONFIG_QCOM_SMEM_STATE) += smem_state.o obj-$(CONFIG_QCOM_SMP2P) += smp2p.o obj-$(CONFIG_QCOM_SMSM) += smsm.o obj-$(CONFIG_QCOM_WCNSS_CTRL) += wcnss_ctrl.o +obj-$(CONFIG_QCOM_APR) += apr.o diff --git a/drivers/soc/qcom/apr.c b/drivers/soc/qcom/apr.c new file mode 100644 index 000000000000..97f3622da535 --- /dev/null +++ b/drivers/soc/qcom/apr.c @@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct apr { + struct rpmsg_endpoint *ch; + struct device *dev; + spinlock_t svcs_lock; + struct idr svcs_idr; + int dest_domain_id; +}; + +/** + * apr_send_pkt() - Send a apr message from apr device + * + * @adev: Pointer to previously registered apr device. + * @pkt: Pointer to apr packet to send + * + * Return: Will be an negative on packet size on success. + */ +int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt) +{ + struct apr *apr = dev_get_drvdata(adev->dev.parent); + struct apr_hdr *hdr; + unsigned long flags; + int ret; + + spin_lock_irqsave(&adev->lock, flags); + + hdr = &pkt->hdr; + hdr->src_domain = APR_DOMAIN_APPS; + hdr->src_svc = adev->svc_id; + hdr->dest_domain = adev->domain_id; + hdr->dest_svc = adev->svc_id; + + ret = rpmsg_trysend(apr->ch, pkt, hdr->pkt_size); + spin_unlock_irqrestore(&adev->lock, flags); + + return ret ? ret : hdr->pkt_size; +} +EXPORT_SYMBOL_GPL(apr_send_pkt); + +static void apr_dev_release(struct device *dev) +{ + struct apr_device *adev = to_apr_device(dev); + + kfree(adev); +} + +static int apr_callback(struct rpmsg_device *rpdev, void *buf, + int len, void *priv, u32 addr) +{ + struct apr *apr = dev_get_drvdata(&rpdev->dev); + uint16_t hdr_size, msg_type, ver, svc_id; + struct apr_device *svc = NULL; + struct apr_driver *adrv = NULL; + struct apr_resp_pkt resp; + struct apr_hdr *hdr; + unsigned long flags; + + if (len <= APR_HDR_SIZE) { + dev_err(apr->dev, "APR: Improper apr pkt received:%p %d\n", + buf, len); + return -EINVAL; + } + + hdr = buf; + ver = APR_HDR_FIELD_VER(hdr->hdr_field); + if (ver > APR_PKT_VER + 1) + return -EINVAL; + + hdr_size = APR_HDR_FIELD_SIZE_BYTES(hdr->hdr_field); + if (hdr_size < APR_HDR_SIZE) { + dev_err(apr->dev, "APR: Wrong hdr size:%d\n", hdr_size); + return -EINVAL; + } + + if (hdr->pkt_size < APR_HDR_SIZE || hdr->pkt_size != len) { + dev_err(apr->dev, "APR: Wrong paket size\n"); + return -EINVAL; + } + + msg_type = APR_HDR_FIELD_MT(hdr->hdr_field); + if (msg_type >= APR_MSG_TYPE_MAX && msg_type != APR_BASIC_RSP_RESULT) { + dev_err(apr->dev, "APR: Wrong message type: %d\n", msg_type); + return -EINVAL; + } + + if (hdr->src_domain >= APR_DOMAIN_MAX || + hdr->dest_domain >= APR_DOMAIN_MAX || + hdr->src_svc >= APR_SVC_MAX || + hdr->dest_svc >= APR_SVC_MAX) { + dev_err(apr->dev, "APR: Wrong APR header\n"); + return -EINVAL; + } + + svc_id = hdr->dest_svc; + spin_lock_irqsave(&apr->svcs_lock, flags); + svc = idr_find(&apr->svcs_idr, svc_id); + if (svc && svc->dev.driver) + adrv = to_apr_driver(svc->dev.driver); + spin_unlock_irqrestore(&apr->svcs_lock, flags); + + if (!adrv) { + dev_err(apr->dev, "APR: service is not registered\n"); + return -EINVAL; + } + + resp.hdr = *hdr; + resp.payload_size = hdr->pkt_size - hdr_size; + + /* + * NOTE: hdr_size is not same as APR_HDR_SIZE as remote can include + * optional headers in to apr_hdr which should be ignored + */ + if (resp.payload_size > 0) + resp.payload = buf + hdr_size; + + adrv->callback(svc, &resp); + + return 0; +} + +static int apr_device_match(struct device *dev, struct device_driver *drv) +{ + struct apr_device *adev = to_apr_device(dev); + struct apr_driver *adrv = to_apr_driver(drv); + const struct apr_device_id *id = adrv->id_table; + + /* Attempt an OF style match first */ + if (of_driver_match_device(dev, drv)) + return 1; + + if (!id) + return 0; + + while (id->domain_id != 0 || id->svc_id != 0) { + if (id->domain_id == adev->domain_id && + id->svc_id == adev->svc_id) + return 1; + id++; + } + + return 0; +} + +static int apr_device_probe(struct device *dev) +{ + struct apr_device *adev = to_apr_device(dev); + struct apr_driver *adrv = to_apr_driver(dev->driver); + + return adrv->probe(adev); +} + +static int apr_device_remove(struct device *dev) +{ + struct apr_device *adev = to_apr_device(dev); + struct apr_driver *adrv; + struct apr *apr = dev_get_drvdata(adev->dev.parent); + + if (dev->driver) { + adrv = to_apr_driver(dev->driver); + if (adrv->remove) + adrv->remove(adev); + spin_lock(&apr->svcs_lock); + idr_remove(&apr->svcs_idr, adev->svc_id); + spin_unlock(&apr->svcs_lock); + } + + return 0; +} + +static int apr_uevent(struct device *dev, struct kobj_uevent_env *env) +{ + struct apr_device *adev = to_apr_device(dev); + int ret; + + ret = of_device_uevent_modalias(dev, env); + if (ret != -ENODEV) + return ret; + + return add_uevent_var(env, "MODALIAS=apr:%s", adev->name); +} + +struct bus_type aprbus = { + .name = "aprbus", + .match = apr_device_match, + .probe = apr_device_probe, + .uevent = apr_uevent, + .remove = apr_device_remove, +}; +EXPORT_SYMBOL_GPL(aprbus); + +static int apr_add_device(struct device *dev, struct device_node *np, + const struct apr_device_id *id) +{ + struct apr *apr = dev_get_drvdata(dev); + struct apr_device *adev = NULL; + int ret; + + adev = kzalloc(sizeof(*adev), GFP_KERNEL); + if (!adev) + return -ENOMEM; + + spin_lock_init(&adev->lock); + + adev->svc_id = id->svc_id; + adev->domain_id = id->domain_id; + adev->version = id->svc_version; + if (np) + strncpy(adev->name, np->name, APR_NAME_SIZE); + else + strncpy(adev->name, id->name, APR_NAME_SIZE); + + dev_set_name(&adev->dev, "aprsvc:%s:%x:%x", adev->name, + id->domain_id, id->svc_id); + + adev->dev.bus = &aprbus; + adev->dev.parent = dev; + adev->dev.of_node = np; + adev->dev.release = apr_dev_release; + adev->dev.driver = NULL; + + spin_lock(&apr->svcs_lock); + idr_alloc(&apr->svcs_idr, adev, id->svc_id, + id->svc_id + 1, GFP_ATOMIC); + spin_unlock(&apr->svcs_lock); + + dev_info(dev, "Adding APR dev: %s\n", dev_name(&adev->dev)); + + ret = device_register(&adev->dev); + if (ret) { + dev_err(dev, "device_register failed: %d\n", ret); + put_device(&adev->dev); + } + + return ret; +} + +static void of_register_apr_devices(struct device *dev) +{ + struct apr *apr = dev_get_drvdata(dev); + struct device_node *node; + + for_each_child_of_node(dev->of_node, node) { + struct apr_device_id id = { {0} }; + + if (of_property_read_u32(node, "reg", &id.svc_id)) + continue; + + id.domain_id = apr->dest_domain_id; + + if (apr_add_device(dev, node, &id)) + dev_err(dev, "Failed to add apr %d svc\n", id.svc_id); + } +} + +static int apr_probe(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + struct apr *apr; + int ret; + + apr = devm_kzalloc(dev, sizeof(*apr), GFP_KERNEL); + if (!apr) + return -ENOMEM; + + ret = of_property_read_u32(dev->of_node, "reg", &apr->dest_domain_id); + if (ret) { + dev_err(dev, "APR Domain ID not specified in DT\n"); + return ret; + } + + dev_set_drvdata(dev, apr); + apr->ch = rpdev->ept; + apr->dev = dev; + spin_lock_init(&apr->svcs_lock); + idr_init(&apr->svcs_idr); + of_register_apr_devices(dev); + + return 0; +} + +static int apr_remove_device(struct device *dev, void *null) +{ + struct apr_device *adev = to_apr_device(dev); + + device_unregister(&adev->dev); + + return 0; +} + +static void apr_remove(struct rpmsg_device *rpdev) +{ + device_for_each_child(&rpdev->dev, NULL, apr_remove_device); +} + +/* + * __apr_driver_register() - Client driver registration with aprbus + * + * @drv:Client driver to be associated with client-device. + * @owner: owning module/driver + * + * This API will register the client driver with the aprbus + * It is called from the driver's module-init function. + */ +int __apr_driver_register(struct apr_driver *drv, struct module *owner) +{ + drv->driver.bus = &aprbus; + drv->driver.owner = owner; + + return driver_register(&drv->driver); +} +EXPORT_SYMBOL_GPL(__apr_driver_register); + +/* + * apr_driver_unregister() - Undo effect of apr_driver_register + * + * @drv: Client driver to be unregistered + */ +void apr_driver_unregister(struct apr_driver *drv) +{ + driver_unregister(&drv->driver); +} +EXPORT_SYMBOL_GPL(apr_driver_unregister); + +static const struct of_device_id apr_of_match[] = { + { .compatible = "qcom,apr"}, + { .compatible = "qcom,apr-v2"}, + {} +}; +MODULE_DEVICE_TABLE(of, apr_of_match); + +static struct rpmsg_driver apr_driver = { + .probe = apr_probe, + .remove = apr_remove, + .callback = apr_callback, + .drv = { + .name = "qcom,apr", + .of_match_table = apr_of_match, + }, +}; + +static int __init apr_init(void) +{ + int ret; + + ret = bus_register(&aprbus); + if (!ret) + ret = register_rpmsg_driver(&apr_driver); + else + bus_unregister(&aprbus); + + return ret; +} + +static void __exit apr_exit(void) +{ + bus_unregister(&aprbus); + unregister_rpmsg_driver(&apr_driver); +} + +subsys_initcall(apr_init); +module_exit(apr_exit); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("Qualcomm APR Bus"); diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h index 7d361be2e24f..2014bd19f28e 100644 --- a/include/linux/mod_devicetable.h +++ b/include/linux/mod_devicetable.h @@ -471,6 +471,17 @@ struct slim_device_id { kernel_ulong_t driver_data; }; +#define APR_NAME_SIZE 32 +#define APR_MODULE_PREFIX "apr:" + +struct apr_device_id { + char name[APR_NAME_SIZE]; + __u32 domain_id; + __u32 svc_id; + __u32 svc_version; + kernel_ulong_t driver_data; /* Data private to the driver */ +}; + #define SPMI_NAME_SIZE 32 #define SPMI_MODULE_PREFIX "spmi:" diff --git a/include/linux/soc/qcom/apr.h b/include/linux/soc/qcom/apr.h new file mode 100644 index 000000000000..c5d52e2cb275 --- /dev/null +++ b/include/linux/soc/qcom/apr.h @@ -0,0 +1,128 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __QCOM_APR_H_ +#define __QCOM_APR_H_ + +#include +#include +#include +#include + +extern struct bus_type aprbus; + +#define APR_HDR_LEN(hdr_len) ((hdr_len)/4) + +/* + * HEADER field + * version:0:3 + * header_size : 4:7 + * message_type : 8:9 + * reserved: 10:15 + */ +#define APR_HDR_FIELD(msg_type, hdr_len, ver)\ + (((msg_type & 0x3) << 8) | ((hdr_len & 0xF) << 4) | (ver & 0xF)) + +#define APR_HDR_SIZE sizeof(struct apr_hdr) +#define APR_SEQ_CMD_HDR_FIELD APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, \ + APR_HDR_LEN(APR_HDR_SIZE), \ + APR_PKT_VER) +/* Version */ +#define APR_PKT_VER 0x0 + +/* Command and Response Types */ +#define APR_MSG_TYPE_EVENT 0x0 +#define APR_MSG_TYPE_CMD_RSP 0x1 +#define APR_MSG_TYPE_SEQ_CMD 0x2 +#define APR_MSG_TYPE_NSEQ_CMD 0x3 +#define APR_MSG_TYPE_MAX 0x04 + +/* APR Basic Response Message */ +#define APR_BASIC_RSP_RESULT 0x000110E8 +#define APR_RSP_ACCEPTED 0x000100BE + +struct aprv2_ibasic_rsp_result_t { + uint32_t opcode; + uint32_t status; +}; + +/* hdr field Ver [0:3], Size [4:7], Message type [8:10] */ +#define APR_HDR_FIELD_VER(h) (h & 0x000F) +#define APR_HDR_FIELD_SIZE(h) ((h & 0x00F0) >> 4) +#define APR_HDR_FIELD_SIZE_BYTES(h) (((h & 0x00F0) >> 4) * 4) +#define APR_HDR_FIELD_MT(h) ((h & 0x0300) >> 8) + +struct apr_hdr { + uint16_t hdr_field; + uint16_t pkt_size; + uint8_t src_svc; + uint8_t src_domain; + uint16_t src_port; + uint8_t dest_svc; + uint8_t dest_domain; + uint16_t dest_port; + uint32_t token; + uint32_t opcode; +} __packed; + +struct apr_pkt { + struct apr_hdr hdr; + uint8_t payload[]; +}; + +struct apr_resp_pkt { + struct apr_hdr hdr; + void *payload; + int payload_size; +}; + +/* Bits 0 to 15 -- Minor version, Bits 16 to 31 -- Major version */ +#define APR_SVC_MAJOR_VERSION(v) ((v >> 16) & 0xFF) +#define APR_SVC_MINOR_VERSION(v) (v & 0xFF) + +struct apr_device { + struct device dev; + uint16_t svc_id; + uint16_t domain_id; + uint32_t version; + char name[APR_NAME_SIZE]; + spinlock_t lock; + struct list_head node; +}; + +#define to_apr_device(d) container_of(d, struct apr_device, dev) + +struct apr_driver { + int (*probe)(struct apr_device *sl); + int (*remove)(struct apr_device *sl); + int (*callback)(struct apr_device *a, + struct apr_resp_pkt *d); + struct device_driver driver; + const struct apr_device_id *id_table; +}; + +#define to_apr_driver(d) container_of(d, struct apr_driver, driver) + +/* + * use a macro to avoid include chaining to get THIS_MODULE + */ +#define apr_driver_register(drv) __apr_driver_register(drv, THIS_MODULE) + +int __apr_driver_register(struct apr_driver *drv, struct module *owner); +void apr_driver_unregister(struct apr_driver *drv); + +/** + * module_apr_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_apr_driver(__apr_driver) \ + module_driver(__apr_driver, apr_driver_register, \ + apr_driver_unregister) + +int apr_send_pkt(struct apr_device *adev, struct apr_pkt *pkt); + +#endif /* __QCOM_APR_H_ */ From patchwork Wed May 9 12:56:14 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135283 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5617222lji; Wed, 9 May 2018 06:06:13 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqdfNjhGNdAB3j65lJnJf9op9eEoktJkkiUTUElFH6Q4xeUPlk2kKDIn6OwV1SxWRRt39fE X-Received: by 10.98.12.202 with SMTP id 71mr43735408pfm.61.1525871173429; Wed, 09 May 2018 06:06:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871173; cv=none; d=google.com; s=arc-20160816; b=v5e7ds8ka1kBrwU6RQKgzJvNjqFbtpuAdTR4afQ9Wgh1+vN0mKiddF1wPkM3ZlwOE0 qdoXZWcu+yo4eHJT375xqWaHfNNmWqwFZ24ofmEMFrXB/3jVKdtmxI3khQQHL4Ojo4ZN XGiWWUhAo2/QX2ZuqFdN/qXGyCYyPSeAZHinhdof0JjcSOgqELH4jfZnSXiq2WZ8cgnE RBfm6hFC/b8bdHJz1POnspmPlB20GmKhOf+KhdOthe2jSxsb82l2yFvh6HQRxE3V19pI QW5cZDc40fzqcwXST+RtEahLdAGTasMoKZ61Qg9RHgFqP+03yXtq+W6MtxMvzJXnKEQg zisw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=7QY0Jir7FHjo2znovGpIiqHvAm6kI7ZR8Aut4xTvvzU=; b=NBW28jvi76JZBw1x4wShMkucb2TrbFbCZmu+K077TZv3AblBYfyEefCRLCi7YdA0bH NTYu4mByK4FS8825waSVKCmjYwuJ/ISmYKJohYjDMhnyIoVMqxQTbH4RXCtiCeFF251r tGb8sjDtFxJOgiW74TS7FmBbWWWtEriSnLEjS0YOZKS3OZOIRjYApH+jcdIKjAAhyKF+ DmSYIqTL6XbgRIFjdQxQfWmEGDEUOzVFrsYqyxuSiknzqYdauW/BhKmIiyXnRxMySRsn GySEgqZcpmZnxLzPr5G1RAFGUB4TKTDAG2pJI13ygQ/pWUtPfsUaGZkMRDuFtJm1lHnD hjUg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jqJgakEL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s5-v6si3064238pgo.12.2018.05.09.06.06.13; Wed, 09 May 2018 06:06:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=jqJgakEL; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935075AbeEINAq (ORCPT + 29 others); Wed, 9 May 2018 09:00:46 -0400 Received: from mail-wr0-f193.google.com ([209.85.128.193]:37429 "EHLO mail-wr0-f193.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935052AbeEINAm (ORCPT ); Wed, 9 May 2018 09:00:42 -0400 Received: by mail-wr0-f193.google.com with SMTP id h5-v6so11640314wrm.4 for ; Wed, 09 May 2018 06:00:41 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=7QY0Jir7FHjo2znovGpIiqHvAm6kI7ZR8Aut4xTvvzU=; b=jqJgakELrSGZE2v3yjIlhTBofvOQ8Rb6hKpWSX+2zVyd9IsCvQ7zVpxIAZd+vIlROn vskQBs3KqACuQV63YscaIda+bYptSZ4nHOWH8QDAXs/93y2aj7B3ZPQCDiHbSs2NaDbc veSDqcU6aodscH3EnB/EWrhTBNkSW/AsDnXjg= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=7QY0Jir7FHjo2znovGpIiqHvAm6kI7ZR8Aut4xTvvzU=; b=D6znQPmSzvRDXHpWfkh8xTiSoLCb7a7/01YavHi1F9i8BeEO/gR6hgb5Av7+Zuur9q 0JrgvTLZu/1UjKQCk56BC2/5O2M12xIQ40+QQarc2907CJmyARQas4iWYqSSi4smmdnR fHXVH2XrIbQ8Yj6rk1k93/Km0cNLtdh+UBxNVYnhxk/v2WH2VCDzNpLOdA3pH6fA6qLk IIi830EHFSLWBLpwvvilKEeQlc8G8nnNXFSUH6V+4qKiBJVJOI97wT5z0Pb+oFK+oW2K vt2avI8XCrTqHWnG+SrtH8dEzvSe2XTMYEKf7nuJqHb7I5RtcGeu8SfRh4FU+zUOTwb1 ZfOw== X-Gm-Message-State: ALQs6tCUWi39DrO8EzBUnBpd2IBuP4CruXCGS/snVXmIg7WTRGiHdGsr FOyiMoE+v+Ipb2CRnnJvx0h50w== X-Received: by 2002:adf:8ac5:: with SMTP id z5-v6mr34710744wrz.22.1525870840788; Wed, 09 May 2018 06:00:40 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.39 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:40 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 03/24] ASoC: qdsp6: dt-bindings: Add q6core dt bindings Date: Wed, 9 May 2018 13:56:14 +0100 Message-Id: <20180509125635.5653-4-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch add DT bindings for Q6CORE DSP module. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Rob Herring Reviewed-by: Banajit Goswami --- .../devicetree/bindings/sound/qcom,q6core.txt | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,q6core.txt -- 2.16.2 diff --git a/Documentation/devicetree/bindings/sound/qcom,q6core.txt b/Documentation/devicetree/bindings/sound/qcom,q6core.txt new file mode 100644 index 000000000000..7f36ff8bec18 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,q6core.txt @@ -0,0 +1,21 @@ +Qualcomm ADSP Core service binding + +Q6CORE is one of the APR audio service on Q6DSP. +Please refer to qcom,apr.txt for details of the common apr service bindings +used by the apr service device. + +- but must contain the following property: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6core-v.". + Or "qcom,q6core" where the version number can be queried + from DSP. + example "qcom,q6core-v2.0" + += EXAMPLE +q6core@3 { + compatible = "qcom,q6core"; + reg = ; +}; From patchwork Wed May 9 12:56:16 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135284 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5617320lji; Wed, 9 May 2018 06:06:18 -0700 (PDT) X-Google-Smtp-Source: AB8JxZq6/Zl/SSxU0We1jYbkjM0I/q9dVRI/X3zHJ9IYBezXyl8ec4MQimkAAR6qvSwFAxsl0NFt X-Received: by 2002:a17:902:b949:: with SMTP id h9-v6mr45005777pls.146.1525871178458; Wed, 09 May 2018 06:06:18 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871178; cv=none; d=google.com; s=arc-20160816; b=TJ9z0eMF0cHSNEVcVUU+360jCd9j34tZKJIvR6kolPZEVXbobyPPvucZexZXkbpFIt l35z8ZVwZBaFNeIUOfKnh2eQJd8/+4LPNHrSphl3992Yl/khuEwURIYB+KMd/4YBVl0V oJohbeoVqAvfXVKVstgunz8wM4XyYvoYB7Vtoti8NIN3yY8e7eJQh6Uw1gDsTiQgJYog sHg/xgxwxjZoEEIQta+dg2C7rPZ+XQlo020shEOantU8079JrX3+E6ovfFrNvAlzX7yc TRh71QyfOmv3HkSpBFith1XfxOGbWmUiHc0yDSLVCi4l0JHDFkOr1/ml3M8BXzC5obiC XpaQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=tY7RukcqLqht8CWrDAkJpg45GsDcbcOVEI8s/t/u01c=; b=htCIxg65kSka/Sjw3xueE8s0dGknF6eePDKgubGJLisO1f03dBKLhZj11pjbqR2Xy/ v1SDu6omi5f843Mhk9lT6t/7r4bRcLGIpxgpz9n/YiWZoMwHxZYcCL7FsBUBp0ykgn0B iCsd/eXhIkIv049lz0BYGRvktX1Mj83jnLgzdDLO2bxvAag24+W5pAwySlLaQF1Zclwu wm4tFpPq1szxE+Hur7zCwbJ+ZIx3TBmppW3+WxVIiZYCOpMBI3J/HTYMFsa1mQfKCopX 8CdwTqsVqZ9+T4FDQ6KujZimSxdJ0WA1WmwOKf1h+DjRveFW257wHwHrVRxIIbyv/+S2 jqZQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Us423h+S; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s5-v6si3064238pgo.12.2018.05.09.06.06.18; Wed, 09 May 2018 06:06:18 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Us423h+S; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935269AbeEINGP (ORCPT + 29 others); Wed, 9 May 2018 09:06:15 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:40367 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935065AbeEINAp (ORCPT ); Wed, 9 May 2018 09:00:45 -0400 Received: by mail-wm0-f65.google.com with SMTP id j5-v6so27680536wme.5 for ; Wed, 09 May 2018 06:00:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=tY7RukcqLqht8CWrDAkJpg45GsDcbcOVEI8s/t/u01c=; b=Us423h+SkI14iLD1AuH33HuVbUmxCGtZMXGV6WG+JReSPp9xgn+TxnVWTRSDs8Y+bX YJjhK8Z82aUNopkuV4ClLYUf+vX7D90ECKtsq3PVL7UgCd0Nn5i/V8ggpcLOsGkJio2A Xqp4w0HPmKf9b9mZqjMyJdmI/BTFchYkTPWdc= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=tY7RukcqLqht8CWrDAkJpg45GsDcbcOVEI8s/t/u01c=; b=fRRsSs2vexx74BDZqtiJP6OwPEjGqglcnnGyAYfqomcf/m/P+VI2mZof3hZH0evCcO 0yQASijwWk7jV6J1BmoElEdbX57fRR0e3QPDsnBGCzo52sa3/a6Nu/deRcJZ02TLyI2H 5dBc8A0MXjcSFTkwKOrK0usCl4vEvAa27D4T9GvpZKxcCTiwRLJLkj3JrWu6DNZc30du VCWQZX5MR+TaaGTyGMMvSSwrlgUwVU0V+0XqZeHVXfUBBFZBOMFqzpotoGZxSYUZHoFH NCRtyKYK38yOLtMAzlpUYnPcyeT9IHgNUW0ouP4ZbuxSBk5gKtTvhn+IKFlgQNvVOLzk wyrg== X-Gm-Message-State: ALKqPwfhniIjvLED1C0Xh9ZXHC3ryfzhw9A66XmNuq4xl8piI7oy57U0 rVapHqC55vA+f3dVDW46nkpxVg== X-Received: by 2002:a1c:c702:: with SMTP id x2-v6mr6215951wmf.57.1525870844216; Wed, 09 May 2018 06:00:44 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.42 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:43 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 05/24] ASoC: qdsp6: dt-bindings: Add q6adm dt bindings Date: Wed, 9 May 2018 13:56:16 +0100 Message-Id: <20180509125635.5653-6-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch add DT bindings for ADM (Audio Device Manager) DSP module. This module implements mixer controls to setup the connections between AFE ports and ASM streams. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Rob Herring Reviewed-by: Banajit Goswami --- .../devicetree/bindings/sound/qcom,q6adm.txt | 33 ++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/qcom,q6adm.txt -- 2.16.2 diff --git a/Documentation/devicetree/bindings/sound/qcom,q6adm.txt b/Documentation/devicetree/bindings/sound/qcom,q6adm.txt new file mode 100644 index 000000000000..cb709e5dbc44 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/qcom,q6adm.txt @@ -0,0 +1,33 @@ +Qualcomm Audio Device Manager (Q6ADM) binding + +Q6ADM is one of the APR audio service on Q6DSP. +Please refer to qcom,apr.txt for details of the coommon apr service bindings +used by the apr service device. + +- but must contain the following property: + +- compatible: + Usage: required + Value type: + Definition: must be "qcom,q6adm-v.". + Or "qcom,q6adm" where the version number can be queried + from DSP. + example "qcom,q6adm-v2.0" + + += ADM routing +"routing" subnode of the ADM node represents adm routing specific configuration + +- #sound-dai-cells + Usage: required + Value type: + Definition: Must be 0 + += EXAMPLE +q6adm@8 { + compatible = "qcom,q6adm"; + reg = ; + q6routing: routing { + #sound-dai-cells = <0>; + }; +}; From patchwork Wed May 9 12:56:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135264 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5609694lji; Wed, 9 May 2018 06:01:03 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrlH5ZnUdwK91GjBvaeoLY3lnR7fcKPXX2vSUfjyqBntRT0EAZSlTwRHyngCB1BNhKa6wLi X-Received: by 2002:a63:7f50:: with SMTP id p16-v6mr35567936pgn.79.1525870863300; Wed, 09 May 2018 06:01:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525870863; cv=none; d=google.com; s=arc-20160816; b=H5aKQ6HzQo+d65AdjPKWRuN/0JgZsc+WnJuzs1HE3fu3xfTqF3I1T/ibg44MNPdiPk 8eZpxfntRxkLNAVvAf8Y/mHUm2tM5gioTvdjLynZs3QZ2Z8lsvORAbMwumr8A3MidZHL sK60/QLTyzCKyqffhOrg00W1y0h9iwAMxnAQ157mJONvPZGdG/8euVJAn05h2gIPCKQe CEUmsFY2UqvGimsgJNFOKeZMMWWvp/ZSn8csaTp5rdsfLq1tx3WLTHhxlo4HgT7r7aH1 wdFlN/Uvy+eD3m+LrZVvUovcQMxkqeUyLeCO1wYbInmVc1woaS6W7n3+4KEmRa5D/yts MgNA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=1FQGwVWt2lSgLHbUmJol3Fc6QbJMc5g8+ARmwFksKxo=; b=Jnz8FvPjIs2JpXwC7CyEUo82SJOKQ85vfFvp/yVYlD6LbH2AQTIPE3mAywViNEPfKi OIOMPwkh15K+J5bMQOmXAq0hD/9ek0TLQTV6R5ZwY5gyLgWgdYFG+Na0utBby4xVM0ye wCIutL5WUyVY1GBgsrI1hQnfWG6+wfLQN0qCX1z1HFqDFHv408tlsNb0OO2pvMKBLv2t sKzN9O+a6HoMlm7L3Xf8AcFv788N8MB5pthPxkDRssM9oTuUNLSIh01ZDDfWdaNYOuW/ 76MVNBMz1VBpKM9iKlbtMOqTZWMaEy/DsalYIvx4B85MFoHDbZN1UgQ7k0ux0ctmPZGH +3pA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=BhBhkQAB; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r4si27552479pff.24.2018.05.09.06.01.03; Wed, 09 May 2018 06:01:03 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=BhBhkQAB; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935134AbeEINBA (ORCPT + 29 others); Wed, 9 May 2018 09:01:00 -0400 Received: from mail-wm0-f65.google.com ([74.125.82.65]:38889 "EHLO mail-wm0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935095AbeEINAt (ORCPT ); Wed, 9 May 2018 09:00:49 -0400 Received: by mail-wm0-f65.google.com with SMTP id y189-v6so9462871wmc.3 for ; Wed, 09 May 2018 06:00:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=1FQGwVWt2lSgLHbUmJol3Fc6QbJMc5g8+ARmwFksKxo=; b=BhBhkQAB0bp5v9/z4Z+msjLnoeWd9mbNLsbkBvh6A2AWrOPfSt4G/ktAQObLVVdfuR n/+OrwBVEH6qNiLrb6x7JRKvnSk2EJyFiRoDBiXP8q6pIA7iXp2k486mr+vTeWghv6pk byd0t6JHSr5fVUSkLLxdh3aMveGKWUcNCkVMM= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=1FQGwVWt2lSgLHbUmJol3Fc6QbJMc5g8+ARmwFksKxo=; b=p+2r1LgWNhzDVQ0bQeqV/OPPBERINGZTC2Bki7GeLj40sfa6ZHv+FZwCN2fIMZrS5T Y7eVoeGDMPGSLzeyNlh+gN+222C3rMS7USs7Qtt9LP9fI3Fomh3jpO6y24IpKbgYBzc7 smooUdwOXil5WL6hI9Jbs4UhSsv+SioJO0Kfd4dz90qmGWNM7pDORd4l+S1DGL34yrdl oXM4pOigR0y90Rpewc7LaglAcflnXTCVbwnQ5GgiVdklpwRf7odAVjkYQ/akFkXv2CRn qNeOrKT57Di3Rnl7CRseELXOGEkwt/0Y/UO7ktyfd43easkFi6FexbNmlhJU+rcdIc98 6jNw== X-Gm-Message-State: ALKqPwcXTMSeUn5tNJrFCYNAmXGDOtyMYOFpL+qwheCVuhOCYzjmhzDU euvAGLoFEhjqe5sYKFjYZx3WFQ== X-Received: by 10.28.13.202 with SMTP id 193mr5563777wmn.36.1525870848431; Wed, 09 May 2018 06:00:48 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:47 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 08/24] ASoC: qdsp6: q6core: Add q6core driver Date: Wed, 9 May 2018 13:56:19 +0100 Message-Id: <20180509125635.5653-9-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to core apr service, which is used to query status of other static and dynamic services on the dsp. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6core.c | 380 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6core.h | 15 ++ 4 files changed, 400 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6core.c create mode 100644 sound/soc/qcom/qdsp6/q6core.h -- 2.16.2 diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index b44a9fcd7ed3..37ee0d958145 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -44,10 +44,14 @@ config SND_SOC_APQ8016_SBC config SND_SOC_QDSP6_COMMON tristate +config SND_SOC_QDSP6_CORE + tristate + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" depends on QCOM_APR && HAS_DMA select SND_SOC_QDSP6_COMMON + select SND_SOC_QDSP6_CORE help To add support for MSM QDSP6 Soc Audio. This will enable sound soc platform specific diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index accebdb49306..03b8e89c9731 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1 +1,2 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o +obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o diff --git a/sound/soc/qcom/qdsp6/q6core.c b/sound/soc/qcom/qdsp6/q6core.c new file mode 100644 index 000000000000..06f03a5fe9bd --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6core.c @@ -0,0 +1,380 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6core.h" +#include "q6dsp-errno.h" + +#define ADSP_STATE_READY_TIMEOUT_MS 3000 +#define Q6_READY_TIMEOUT_MS 100 +#define AVCS_CMD_ADSP_EVENT_GET_STATE 0x0001290C +#define AVCS_CMDRSP_ADSP_EVENT_GET_STATE 0x0001290D +#define AVCS_GET_VERSIONS 0x00012905 +#define AVCS_GET_VERSIONS_RSP 0x00012906 +#define AVCS_CMD_GET_FWK_VERSION 0x001292c +#define AVCS_CMDRSP_GET_FWK_VERSION 0x001292d + +struct avcs_svc_info { + uint32_t service_id; + uint32_t version; +} __packed; + +struct avcs_cmdrsp_get_version { + uint32_t build_id; + uint32_t num_services; + struct avcs_svc_info svc_api_info[]; +} __packed; + +/* for ADSP2.8 and above */ +struct avcs_svc_api_info { + uint32_t service_id; + uint32_t api_version; + uint32_t api_branch_version; +} __packed; + +struct avcs_cmdrsp_get_fwk_version { + uint32_t build_major_version; + uint32_t build_minor_version; + uint32_t build_branch_version; + uint32_t build_subbranch_version; + uint32_t num_services; + struct avcs_svc_api_info svc_api_info[]; +} __packed; + +struct q6core { + struct apr_device *adev; + wait_queue_head_t wait; + uint32_t avcs_state; + struct mutex lock; + bool resp_received; + uint32_t num_services; + struct avcs_cmdrsp_get_fwk_version *fwk_version; + struct avcs_cmdrsp_get_version *svc_version; + bool fwk_version_supported; + bool get_state_supported; + bool get_version_supported; + bool is_version_requested; +}; + +static struct q6core *g_core; + +static int q6core_callback(struct apr_device *adev, struct apr_resp_pkt *data) +{ + struct q6core *core = dev_get_drvdata(&adev->dev); + struct aprv2_ibasic_rsp_result_t *result; + struct apr_hdr *hdr = &data->hdr; + + result = data->payload; + switch (hdr->opcode) { + case APR_BASIC_RSP_RESULT:{ + result = data->payload; + switch (result->opcode) { + case AVCS_GET_VERSIONS: + if (result->status == ADSP_EUNSUPPORTED) + core->get_version_supported = false; + core->resp_received = true; + break; + case AVCS_CMD_GET_FWK_VERSION: + if (result->status == ADSP_EUNSUPPORTED) + core->fwk_version_supported = false; + core->resp_received = true; + break; + case AVCS_CMD_ADSP_EVENT_GET_STATE: + if (result->status == ADSP_EUNSUPPORTED) + core->get_state_supported = false; + core->resp_received = true; + break; + } + break; + } + case AVCS_CMDRSP_GET_FWK_VERSION: { + struct avcs_cmdrsp_get_fwk_version *fwk; + int bytes; + + fwk = data->payload; + bytes = sizeof(*fwk) + fwk->num_services * + sizeof(fwk->svc_api_info[0]); + + core->fwk_version = kzalloc(bytes, GFP_ATOMIC); + if (!core->fwk_version) + return -ENOMEM; + + memcpy(core->fwk_version, data->payload, bytes); + + core->fwk_version_supported = true; + core->resp_received = true; + + break; + } + case AVCS_GET_VERSIONS_RSP: { + struct avcs_cmdrsp_get_version *v; + int len; + + v = data->payload; + + len = sizeof(*v) + v->num_services * sizeof(v->svc_api_info[0]); + + core->svc_version = kzalloc(len, GFP_ATOMIC); + if (!core->svc_version) + return -ENOMEM; + + memcpy(core->svc_version, data->payload, len); + + core->get_version_supported = true; + core->resp_received = true; + + break; + } + case AVCS_CMDRSP_ADSP_EVENT_GET_STATE: + core->get_state_supported = true; + core->avcs_state = result->opcode; + + core->resp_received = true; + break; + default: + dev_err(&adev->dev, "Message id from adsp core svc: 0x%x\n", + hdr->opcode); + break; + } + + if (core->resp_received) + wake_up(&core->wait); + + return 0; +} + +static int q6core_get_fwk_versions(struct q6core *core) +{ + struct apr_device *adev = core->adev; + struct apr_pkt pkt; + int rc; + + pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + pkt.hdr.pkt_size = APR_HDR_SIZE; + pkt.hdr.opcode = AVCS_CMD_GET_FWK_VERSION; + + rc = apr_send_pkt(adev, &pkt); + if (rc < 0) + return rc; + + rc = wait_event_timeout(core->wait, (core->resp_received), + msecs_to_jiffies(Q6_READY_TIMEOUT_MS)); + if (rc > 0 && core->resp_received) { + core->resp_received = false; + + if (!core->fwk_version_supported) + return -ENOTSUPP; + else + return 0; + } + + + return rc; +} + +static int q6core_get_svc_versions(struct q6core *core) +{ + struct apr_device *adev = core->adev; + struct apr_pkt pkt; + int rc; + + pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + pkt.hdr.pkt_size = APR_HDR_SIZE; + pkt.hdr.opcode = AVCS_GET_VERSIONS; + + rc = apr_send_pkt(adev, &pkt); + if (rc < 0) + return rc; + + rc = wait_event_timeout(core->wait, (core->resp_received), + msecs_to_jiffies(Q6_READY_TIMEOUT_MS)); + if (rc > 0 && core->resp_received) { + core->resp_received = false; + return 0; + } + + return rc; +} + +static bool __q6core_is_adsp_ready(struct q6core *core) +{ + struct apr_device *adev = core->adev; + struct apr_pkt pkt; + int rc; + + core->get_state_supported = false; + + pkt.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + pkt.hdr.pkt_size = APR_HDR_SIZE; + pkt.hdr.opcode = AVCS_CMD_ADSP_EVENT_GET_STATE; + + rc = apr_send_pkt(adev, &pkt); + if (rc < 0) + return false; + + rc = wait_event_timeout(core->wait, (core->resp_received), + msecs_to_jiffies(Q6_READY_TIMEOUT_MS)); + if (rc > 0 && core->resp_received) { + core->resp_received = false; + + if (core->avcs_state) + return true; + } + + /* assume that the adsp is up if we not support this command */ + if (!core->get_state_supported) + return true; + + return false; +} + +/** + * q6core_get_svc_api_info() - Get version number of a service. + * + * @svc_id: service id of the service. + * @ainfo: Valid struct pointer to fill svc api information. + * + * Return: zero on success and error code on failure or unsupported + */ +int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo) +{ + int i; + int ret = -ENOTSUPP; + + if (!g_core || !ainfo) + return 0; + + mutex_lock(&g_core->lock); + if (!g_core->is_version_requested) { + if (q6core_get_fwk_versions(g_core) == -ENOTSUPP) + q6core_get_svc_versions(g_core); + g_core->is_version_requested = true; + } + + if (g_core->fwk_version_supported) { + for (i = 0; i < g_core->fwk_version->num_services; i++) { + struct avcs_svc_api_info *info; + + info = &g_core->fwk_version->svc_api_info[i]; + if (svc_id != info->service_id) + continue; + + ainfo->api_version = info->api_version; + ainfo->api_branch_version = info->api_branch_version; + ret = 0; + break; + } + } else if (g_core->get_version_supported) { + for (i = 0; i < g_core->svc_version->num_services; i++) { + struct avcs_svc_info *info; + + info = &g_core->svc_version->svc_api_info[i]; + if (svc_id != info->service_id) + continue; + + ainfo->api_version = info->version; + ainfo->api_branch_version = 0; + ret = 0; + break; + } + } + + mutex_unlock(&g_core->lock); + + return ret; +} +EXPORT_SYMBOL_GPL(q6core_get_svc_api_info); + +/** + * q6core_is_adsp_ready() - Get status of adsp + * + * Return: Will be an true if adsp is ready and false if not. + */ +bool q6core_is_adsp_ready(void) +{ + unsigned long timeout; + bool ret = false; + + if (!g_core) + return false; + + mutex_lock(&g_core->lock); + timeout = jiffies + msecs_to_jiffies(ADSP_STATE_READY_TIMEOUT_MS); + for (;;) { + if (__q6core_is_adsp_ready(g_core)) { + ret = true; + break; + } + + if (!time_after(timeout, jiffies)) { + ret = false; + break; + } + } + + mutex_unlock(&g_core->lock); + return ret; +} +EXPORT_SYMBOL_GPL(q6core_is_adsp_ready); + +static int q6core_probe(struct apr_device *adev) +{ + g_core = kzalloc(sizeof(*g_core), GFP_KERNEL); + if (!g_core) + return -ENOMEM; + + dev_set_drvdata(&adev->dev, g_core); + + mutex_init(&g_core->lock); + g_core->adev = adev; + init_waitqueue_head(&g_core->wait); + return 0; +} + +static int q6core_exit(struct apr_device *adev) +{ + struct q6core *core = dev_get_drvdata(&adev->dev); + + if (core->fwk_version_supported) + kfree(core->fwk_version); + if (core->get_version_supported) + kfree(core->svc_version); + + g_core = NULL; + kfree(core); + + return 0; +} + +static const struct of_device_id q6core_device_id[] = { + { .compatible = "qcom,q6core" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6core_device_id); + +static struct apr_driver qcom_q6core_driver = { + .probe = q6core_probe, + .remove = q6core_exit, + .callback = q6core_callback, + .driver = { + .name = "qcom-q6core", + .of_match_table = of_match_ptr(q6core_device_id), + }, +}; + +module_apr_driver(qcom_q6core_driver); +MODULE_DESCRIPTION("q6 core"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6core.h b/sound/soc/qcom/qdsp6/q6core.h new file mode 100644 index 000000000000..4105b1d730be --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6core.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +#ifndef __Q6CORE_H__ +#define __Q6CORE_H__ + +struct q6core_svc_api_info { + uint32_t service_id; + uint32_t api_version; + uint32_t api_branch_version; +}; + +bool q6core_is_adsp_ready(void); +int q6core_get_svc_api_info(int svc_id, struct q6core_svc_api_info *ainfo); + +#endif /* __Q6CORE_H__ */ From patchwork Wed May 9 12:56:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135281 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5616205lji; Wed, 9 May 2018 06:05:24 -0700 (PDT) X-Google-Smtp-Source: AB8JxZrsT4WIH40VwY1N3wzFAxkcqZPNo59QUaBhAZqonmeEMuWsTA6lBZY7qiPFaj6GBTueYpcz X-Received: by 2002:a17:902:5ac1:: with SMTP id g1-v6mr45602004plm.43.1525871123984; Wed, 09 May 2018 06:05:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871123; cv=none; d=google.com; s=arc-20160816; b=RtQRiARYpa6TkW1tCR0oegI5OnQVlRbSw6Ys97xAqTSVR2GFyhfZunhU/361WEYOEy zj4AvpP3SK2+y9qrb/8Qi7D0WnUFlUJ3sH+xRMgGeqRK2j1CcespeGmnRhmwCcCHxFD0 F94OIlZN5DxYBvIGsSct71HmRKxZ264kwUlyWuLHvoghUZpUsMknp+os3jLy6xim2R2u /j6BFUXWNzcnERv6k0d9WFrY3XYcQj0rfs8+sAFi17/YRmB2wGzJPmE82QGszUd422PC IMSEcTqbHJUM0rI0QI1XQAAbE9JnGdLq4IMtR3/DrQ6FmxFDK1KFNjEBvObiBVTGAKYK cLYg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=o9zSY8uqSnrmkD1RIMV/wGVazTSDuQFxf06zYOLNSI8=; b=to7fjRM1UXRZy+7memJlWaE+42mkXlQXY7oLHiaxALVe/6CSQexfy9P7/dx1oWIvYE vbjbXreZsEgPf3PUv6M6oU/WxSEybCiqADI6fR96q4EydHVYrnhpnt7tsq23K8dTQrDs zXw1NapumeXHbdY+JQusoiaehW73wgIsv4xxNc54IL9Qs15ThE2qHnS7riBvkkpAh88E S4OZlN29Cklu7Gy0S7IgJiYdmhkXRVz6SXQa84aiELBfcWTdwOhcllnry9vdm0TJZW2L bRPns+UNf6j4UqQ1IxA9ijHFF5YgJ3tyo4gnulexVV+eHyPPi4KB8oNrwGkiQu5DMIwm BURg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=VQnoa86P; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id o2-v6si13002982plk.527.2018.05.09.06.05.23; Wed, 09 May 2018 06:05:23 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=VQnoa86P; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935262AbeEINFV (ORCPT + 29 others); Wed, 9 May 2018 09:05:21 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:35154 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935097AbeEINAw (ORCPT ); Wed, 9 May 2018 09:00:52 -0400 Received: by mail-wm0-f68.google.com with SMTP id o78-v6so27744539wmg.0 for ; Wed, 09 May 2018 06:00:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=o9zSY8uqSnrmkD1RIMV/wGVazTSDuQFxf06zYOLNSI8=; b=VQnoa86PxiCR5KBtI0XnsBjKNTd1UcNuGOLG+4d+OOHIUN2PPOzUXUmq5RZ1MY1cXn 52rAyWOZN8anJU3rAP4ZOgW08gIwDvRjgD/HsfBikaST48VdpI4fwo5bNixSu3f1eT3M fS3/eYWerCIDYTl63huqgS895DJtK1O8e5JtU= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=o9zSY8uqSnrmkD1RIMV/wGVazTSDuQFxf06zYOLNSI8=; b=kig+c1TeiRHvLvRxqLoOsPgX3enLNOa98Kj+voZlTGAiTd6+YaGAff0qk0Lp66NNen /6vR2GYdVg6Iq0WlSl1U1fQWtAbO4jNpwNM9Nj6V7vgNNZB/zvO6WAeygtng/odQKxxk ohxz6K67WRlYy+ugrsdjSMzKZsXCyZjjyPygNPVXHMfUHPSbKYGkAG3PepaGTvoYiXTN qrW/EYoDKPU6ixII4ZkWnaQeB9sBKe6h+EcuG2o41C4GI/p2NBboAa0pOePu8yACBSzs YYJ/2eam7Ru6zk6v7lU/vNhS6nekAvdFqB6uB6CvU9lX7O6kmwxcATQZdRn5QbLmKGlO MEiw== X-Gm-Message-State: ALKqPwfn9zwA8kHT+DH7a+WvBPXLO5cBsYbqHf75GaVW7sBSD7fBL9Qc /kr7T4ZSrRtEfQsE9LjFhfdMEg== X-Received: by 10.28.130.75 with SMTP id e72mr5678289wmd.64.1525870851209; Wed, 09 May 2018 06:00:51 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:50 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 10/24] ASoC: qdsp6: qdafe: Add SLIMBus port Support Date: Wed, 9 May 2018 13:56:21 +0100 Message-Id: <20180509125635.5653-11-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to 6 SLIMBus AFE ports, which are used as backend dais. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6afe.c | 129 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6afe.h | 14 +++++ 2 files changed, 143 insertions(+) -- 2.16.2 diff --git a/sound/soc/qcom/qdsp6/q6afe.c b/sound/soc/qcom/qdsp6/q6afe.c index ec35ed1ffede..1de5c941b11e 100644 --- a/sound/soc/qcom/qdsp6/q6afe.c +++ b/sound/soc/qcom/qdsp6/q6afe.c @@ -27,9 +27,45 @@ #define AFE_PARAM_ID_HDMI_CONFIG 0x00010210 #define AFE_MODULE_AUDIO_DEV_INTERFACE 0x0001020C +#define AFE_PARAM_ID_CDC_SLIMBUS_SLAVE_CFG 0x00010235 + +#define AFE_PARAM_ID_SLIMBUS_CONFIG 0x00010212 + /* Port IDs */ #define AFE_API_VERSION_HDMI_CONFIG 0x1 #define AFE_PORT_ID_MULTICHAN_HDMI_RX 0x100E + +#define AFE_API_VERSION_SLIMBUS_CONFIG 0x1 + +/* SLIMbus Rx port on channel 0. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX 0x4000 +/* SLIMbus Tx port on channel 0. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_TX 0x4001 +/* SLIMbus Rx port on channel 1. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX 0x4002 +/* SLIMbus Tx port on channel 1. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_TX 0x4003 +/* SLIMbus Rx port on channel 2. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX 0x4004 +/* SLIMbus Tx port on channel 2. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_TX 0x4005 +/* SLIMbus Rx port on channel 3. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX 0x4006 +/* SLIMbus Tx port on channel 3. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_TX 0x4007 +/* SLIMbus Rx port on channel 4. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX 0x4008 +/* SLIMbus Tx port on channel 4. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_TX 0x4009 +/* SLIMbus Rx port on channel 5. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX 0x400a +/* SLIMbus Tx port on channel 5. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_TX 0x400b +/* SLIMbus Rx port on channel 6. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX 0x400c +/* SLIMbus Tx port on channel 6. */ +#define AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_TX 0x400d + #define TIMEOUT_MS 1000 #define AFE_CMD_RESP_AVAIL 0 #define AFE_CMD_RESP_NONE 1 @@ -80,8 +116,53 @@ struct afe_param_id_hdmi_multi_chan_audio_cfg { u16 reserved; } __packed; +struct afe_param_id_slimbus_cfg { + u32 sb_cfg_minor_version; +/* Minor version used for tracking the version of the SLIMBUS + * configuration interface. + * Supported values: #AFE_API_VERSION_SLIMBUS_CONFIG + */ + + u16 slimbus_dev_id; +/* SLIMbus hardware device ID, which is required to handle + * multiple SLIMbus hardware blocks. + * Supported values: - #AFE_SLIMBUS_DEVICE_1 - #AFE_SLIMBUS_DEVICE_2 + */ + u16 bit_width; +/* Bit width of the sample. + * Supported values: 16, 24 + */ + u16 data_format; +/* Data format supported by the SLIMbus hardware. The default is + * 0 (#AFE_SB_DATA_FORMAT_NOT_INDICATED), which indicates the + * hardware does not perform any format conversions before the data + * transfer. + */ + u16 num_channels; +/* Number of channels. + * Supported values: 1 to #AFE_PORT_MAX_AUDIO_CHAN_CNT + */ + u8 shared_ch_mapping[AFE_PORT_MAX_AUDIO_CHAN_CNT]; +/* Mapping of shared channel IDs (128 to 255) to which the + * master port is to be connected. + * Shared_channel_mapping[i] represents the shared channel assigned + * for audio channel i in multichannel audio data. + */ + u32 sample_rate; +/* Sampling rate of the port. + * Supported values: + * - #AFE_PORT_SAMPLE_RATE_8K + * - #AFE_PORT_SAMPLE_RATE_16K + * - #AFE_PORT_SAMPLE_RATE_48K + * - #AFE_PORT_SAMPLE_RATE_96K + * - #AFE_PORT_SAMPLE_RATE_192K + */ +} __packed; + + union afe_port_config { struct afe_param_id_hdmi_multi_chan_audio_cfg hdmi_multi_ch; + struct afe_param_id_slimbus_cfg slim_cfg; } __packed; struct q6afe_port { @@ -110,6 +191,20 @@ struct afe_port_map { static struct afe_port_map port_maps[AFE_PORT_MAX] = { [HDMI_RX] = { AFE_PORT_ID_MULTICHAN_HDMI_RX, HDMI_RX, 1, 1}, + [SLIMBUS_0_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX, + SLIMBUS_0_RX, 1, 1}, + [SLIMBUS_1_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX, + SLIMBUS_1_RX, 1, 1}, + [SLIMBUS_2_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX, + SLIMBUS_2_RX, 1, 1}, + [SLIMBUS_3_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX, + SLIMBUS_3_RX, 1, 1}, + [SLIMBUS_4_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX, + SLIMBUS_4_RX, 1, 1}, + [SLIMBUS_5_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX, + SLIMBUS_5_RX, 1, 1}, + [SLIMBUS_6_RX] = { AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX, + SLIMBUS_6_RX, 1, 1}, }; static struct q6afe_port *afe_find_port(struct q6afe *afe, int token) @@ -323,6 +418,31 @@ int q6afe_port_stop(struct q6afe_port *port) } EXPORT_SYMBOL_GPL(q6afe_port_stop); +/** + * q6afe_slim_port_prepare() - Prepare slim afe port. + * + * @port: Instance of afe port + * @cfg: SLIM configuration for the afe port + * + */ +void q6afe_slim_port_prepare(struct q6afe_port *port, + struct q6afe_slim_cfg *cfg) +{ + union afe_port_config *pcfg = &port->port_cfg; + + pcfg->slim_cfg.sb_cfg_minor_version = AFE_API_VERSION_SLIMBUS_CONFIG; + pcfg->slim_cfg.sample_rate = cfg->sample_rate; + pcfg->slim_cfg.bit_width = cfg->bit_width; + pcfg->slim_cfg.num_channels = cfg->num_channels; + pcfg->slim_cfg.data_format = cfg->data_format; + pcfg->slim_cfg.shared_ch_mapping[0] = cfg->ch_mapping[0]; + pcfg->slim_cfg.shared_ch_mapping[1] = cfg->ch_mapping[1]; + pcfg->slim_cfg.shared_ch_mapping[2] = cfg->ch_mapping[2]; + pcfg->slim_cfg.shared_ch_mapping[3] = cfg->ch_mapping[3]; + +} +EXPORT_SYMBOL_GPL(q6afe_slim_port_prepare); + /** * q6afe_hdmi_port_prepare() - Prepare hdmi afe port. * @@ -426,6 +546,15 @@ struct q6afe_port *q6afe_port_get_from_id(struct device *dev, int id) case AFE_PORT_ID_MULTICHAN_HDMI_RX: cfg_type = AFE_PARAM_ID_HDMI_CONFIG; break; + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_0_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_1_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_2_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_3_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_4_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_5_RX: + case AFE_PORT_ID_SLIMBUS_MULTI_CHAN_6_RX: + cfg_type = AFE_PARAM_ID_SLIMBUS_CONFIG; + break; default: dev_err(dev, "Invalid port id 0x%x\n", port_id); return ERR_PTR(-EINVAL); diff --git a/sound/soc/qcom/qdsp6/q6afe.h b/sound/soc/qcom/qdsp6/q6afe.h index 3bd991a7c42d..5659966c6b1e 100644 --- a/sound/soc/qcom/qdsp6/q6afe.h +++ b/sound/soc/qcom/qdsp6/q6afe.h @@ -11,6 +11,9 @@ #define MSM_AFE_PORT_TYPE_TX 1 #define AFE_MAX_PORTS AFE_PORT_MAX +#define AFE_MAX_CHAN_COUNT 8 +#define AFE_PORT_MAX_AUDIO_CHAN_CNT 0x8 + struct q6afe_hdmi_cfg { u16 datatype; u16 channel_allocation; @@ -18,8 +21,17 @@ struct q6afe_hdmi_cfg { u16 bit_width; }; +struct q6afe_slim_cfg { + u32 sample_rate; + u16 bit_width; + u16 data_format; + u16 num_channels; + u8 ch_mapping[AFE_MAX_CHAN_COUNT]; +}; + struct q6afe_port_config { struct q6afe_hdmi_cfg hdmi; + struct q6afe_slim_cfg slim; }; struct q6afe_port; @@ -31,5 +43,7 @@ void q6afe_port_put(struct q6afe_port *port); int q6afe_get_port_id(int index); void q6afe_hdmi_port_prepare(struct q6afe_port *port, struct q6afe_hdmi_cfg *cfg); +void q6afe_slim_port_prepare(struct q6afe_port *port, + struct q6afe_slim_cfg *cfg); #endif /* __Q6AFE_H__ */ From patchwork Wed May 9 12:56:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135276 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5615147lji; Wed, 9 May 2018 06:04:35 -0700 (PDT) X-Google-Smtp-Source: AB8JxZoUJxz7ecQhKYlmqKDZEwiBtLJW4xu88afJCm9pCZNE8LjdgC+vLV/10YbxxOqXSEyc/cd2 X-Received: by 2002:a63:78cf:: with SMTP id t198-v6mr167940pgc.382.1525871075719; Wed, 09 May 2018 06:04:35 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871075; cv=none; d=google.com; s=arc-20160816; b=wcIKHXvQKYhj62ABTE0+g27jGS0aBlyZ7LLJpRbOqTDaVm1/KrhMVt8EM58iBwz8bV DjT5Qeifm/LWI7Bx2O4hcnEHCi5uULKlWnSgsATLMUzKRE3HQgIzW/HNxbDlAOMWrEd+ KLSkRDJDboFs6svJQ9Z6aMzQP4+WioEYcVEMl2ZXZOvJEQal/p6QTUGe/p6Qqf8rOmgS /t7qwShUUDJGZa20fLaFD7HMhtRwsr0Fh0oNP6QG/X87AckHO9lDrQCjWP4sBBol1SL+ xNvx7h93ta6mtpB+07iTKrb238P1Ep1it+r2zqJzVRLYm6Uy/RMgnBGRP1/495EH3+Q6 Ppog== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=Qlk2gtGt8kFluSQ5vmPQXN6rttfF48r6O0ibY5TV18Q=; b=MMtTjZhFT7RsZgQYbGIs0WjwCv+h8C+qvVnfcNaI4hVdL30GvAZoha8/5TnlrzmA2u QsUhTkD6ZIjOIpo/RW3F588d9m7u8tOF2rNAu6z8fcdzVS9GAxKxM3dFTDzJ2z22waHg DZ5uXB/WQJ/c/kUctB3H+4qfoaXrDLWxvus8ibhq1BUCRxpuzDrHsEKy8oEkoChT3ATK WRAgTKalsUWrx8Id1ElnvK7iNTdbmajmNg6tzyeRzkqxbFtk53U1YjUWg3OwdMUtLbtX ONTQzcRWFLiHfl/w4b8+VHGadIm6F4mYyzfhX5mhjzmrcNNxFFAn/K96pq4kDrzj/uuc oRmQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=P6xCAiP5; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t9-v6si25128783plo.592.2018.05.09.06.04.35; Wed, 09 May 2018 06:04:35 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=P6xCAiP5; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935255AbeEINEc (ORCPT + 29 others); Wed, 9 May 2018 09:04:32 -0400 Received: from mail-wr0-f194.google.com ([209.85.128.194]:41845 "EHLO mail-wr0-f194.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935117AbeEINA5 (ORCPT ); Wed, 9 May 2018 09:00:57 -0400 Received: by mail-wr0-f194.google.com with SMTP id g21-v6so35539973wrb.8 for ; Wed, 09 May 2018 06:00:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Qlk2gtGt8kFluSQ5vmPQXN6rttfF48r6O0ibY5TV18Q=; b=P6xCAiP5brtHXxxOdc+V/qor9n/M6xa2MMnYoh7PM1L14zNS8h7okxTC+r8JKdrcAx Kig8oCzE60nWSh7PAZfmRH8xt1OoPwLjfljz1QpT92ZoRp6rkwzZKmztUPiKj5ODq9ro /7RvIB3XVPTCQ2K/e8hRWo3XnO3KqLmKzUJsQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Qlk2gtGt8kFluSQ5vmPQXN6rttfF48r6O0ibY5TV18Q=; b=peWRRpWo/XFPJpMVtWjvb3ncJxY92aslMmpP0JmlrcpFmRhe3afT0f+ygixZxtCQ5Q wWD9iTXOfllpufNP8gyN1vNEyZZ1TOljGuDfHCMqyw67qi02q2/CUXgzX+UFb13FZ3Y8 +8i6IE6FJk2Gl0Gg7VUO+m2cIzgS5X06TpDv2gyhuoX/QTyHltqtGTPBq2G7W++um/Ru RtFYVurm5ZbOrVqBJdS+KIroYn1KxNXw5xUBJ9QShNrs0ThQbRBISAB6z1sxcGWLgspu PigO5fRYT9MmSx1MJg+lEi4/ifus6xnMAuTZDQHGZw//6PGtJzG9jKdBF/t0hHEP/p8T pyXA== X-Gm-Message-State: ALQs6tAsEI00cABn+TQzD7pzyGS0npO7ZlmtwgIhvER07L2ztnZZr57U EbI1Xialb3tHmxJ5Rbv1LU3lng== X-Received: by 2002:adf:dc90:: with SMTP id r16-v6mr34688830wrj.218.1525870855989; Wed, 09 May 2018 06:00:55 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:55 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 13/24] ASoC: qdsp6: q6adm: Add q6adm driver Date: Wed, 9 May 2018 13:56:24 +0100 Message-Id: <20180509125635.5653-14-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to Q6ADM (Audio Device Manager) module in q6dsp. ADM performs routing between audio streams and AFE ports. It does Rate matching for streams going to devices driven by different clocks, it handles volume ramping, Mixing with channel and bit-width. ADM creates and destroys dynamic COPP services for device-related audio processing as needed. This patch adds basic support to ADM. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6adm.c | 633 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6adm.h | 25 ++ 4 files changed, 663 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6adm.c create mode 100644 sound/soc/qcom/qdsp6/q6adm.h -- 2.16.2 diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index bb0a2afb0563..971127edbc23 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -50,12 +50,16 @@ config SND_SOC_QDSP6_CORE config SND_SOC_QDSP6_AFE tristate +config SND_SOC_QDSP6_ADM + tristate + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" depends on QCOM_APR && HAS_DMA select SND_SOC_QDSP6_COMMON select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE + select SND_SOC_QDSP6_ADM help To add support for MSM QDSP6 Soc Audio. This will enable sound soc platform specific diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 7ff666bd10ca..95cdb3a12694 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o +obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o diff --git a/sound/soc/qcom/qdsp6/q6adm.c b/sound/soc/qcom/qdsp6/q6adm.c new file mode 100644 index 000000000000..88183d6eb053 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6adm.c @@ -0,0 +1,633 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6adm.h" +#include "q6afe.h" +#include "q6core.h" +#include "q6dsp-errno.h" +#include "q6dsp-common.h" + +#define ADM_CMD_DEVICE_OPEN_V5 0x00010326 +#define ADM_CMDRSP_DEVICE_OPEN_V5 0x00010329 +#define ADM_CMD_DEVICE_CLOSE_V5 0x00010327 +#define ADM_CMD_MATRIX_MAP_ROUTINGS_V5 0x00010325 + +#define TIMEOUT_MS 1000 +#define RESET_COPP_ID 99 +#define INVALID_COPP_ID 0xFF +/* Definition for a legacy device session. */ +#define ADM_LEGACY_DEVICE_SESSION 0 +#define ADM_MATRIX_ID_AUDIO_RX 0 +#define ADM_MATRIX_ID_AUDIO_TX 1 + +struct q6copp { + int afe_port; + int copp_idx; + int id; + int topology; + int mode; + int rate; + int bit_width; + int channels; + int app_type; + int acdb_id; + + struct aprv2_ibasic_rsp_result_t result; + struct kref refcount; + wait_queue_head_t wait; + struct list_head node; + struct q6adm *adm; +}; + +struct q6adm { + struct apr_device *apr; + struct device *dev; + struct q6core_svc_api_info ainfo; + unsigned long copp_bitmap[AFE_MAX_PORTS]; + struct list_head copps_list; + spinlock_t copps_list_lock; + struct aprv2_ibasic_rsp_result_t result; + struct mutex lock; + wait_queue_head_t matrix_map_wait; + struct platform_device *pdev_routing; +}; + +struct q6adm_cmd_device_open_v5 { + u16 flags; + u16 mode_of_operation; + u16 endpoint_id_1; + u16 endpoint_id_2; + u32 topology_id; + u16 dev_num_channel; + u16 bit_width; + u32 sample_rate; + u8 dev_channel_mapping[8]; +} __packed; + +struct q6adm_cmd_matrix_map_routings_v5 { + u32 matrix_id; + u32 num_sessions; +} __packed; + +struct q6adm_session_map_node_v5 { + u16 session_id; + u16 num_copps; +} __packed; + +static struct q6copp *adm_find_copp(struct q6adm *adm, int port_idx, + int copp_idx) +{ + struct q6copp *c = NULL; + struct q6copp *ret = NULL; + unsigned long flags; + + spin_lock_irqsave(&adm->copps_list_lock, flags); + list_for_each_entry(c, &adm->copps_list, node) { + if ((port_idx == c->afe_port) && (copp_idx == c->copp_idx)) { + ret = c; + break; + } + } + + spin_unlock_irqrestore(&adm->copps_list_lock, flags); + + return ret; + +} + +static int q6adm_callback(struct apr_device *adev, struct apr_resp_pkt *data) +{ + struct aprv2_ibasic_rsp_result_t *result = data->payload; + int port_idx, copp_idx; + struct apr_hdr *hdr = &data->hdr; + struct q6copp *copp; + struct q6adm *adm = dev_get_drvdata(&adev->dev); + + if (!data->payload_size) + return 0; + + + copp_idx = (hdr->token) & 0XFF; + port_idx = ((hdr->token) >> 16) & 0xFF; + if (port_idx < 0 || port_idx >= AFE_MAX_PORTS) { + dev_err(&adev->dev, "Invalid port idx %d token %d\n", + port_idx, hdr->token); + return 0; + } + if (copp_idx < 0 || copp_idx >= MAX_COPPS_PER_PORT) { + dev_err(&adev->dev, "Invalid copp idx %d token %d\n", + copp_idx, hdr->token); + return 0; + } + + switch (hdr->opcode) { + case APR_BASIC_RSP_RESULT: { + if (result->status != 0) { + dev_err(&adev->dev, "cmd = 0x%x return error = 0x%x\n", + result->opcode, result->status); + } + switch (result->opcode) { + case ADM_CMD_DEVICE_OPEN_V5: + case ADM_CMD_DEVICE_CLOSE_V5: + copp = adm_find_copp(adm, port_idx, copp_idx); + if (!copp) + return 0; + + copp->result = *result; + wake_up(&copp->wait); + break; + case ADM_CMD_MATRIX_MAP_ROUTINGS_V5: + adm->result = *result; + wake_up(&adm->matrix_map_wait); + break; + + default: + dev_err(&adev->dev, "Unknown Cmd: 0x%x\n", + result->opcode); + break; + } + return 0; + } + case ADM_CMDRSP_DEVICE_OPEN_V5: { + struct adm_cmd_rsp_device_open_v5 { + u32 status; + u16 copp_id; + u16 reserved; + } __packed * open = data->payload; + + copp = adm_find_copp(adm, port_idx, copp_idx); + if (!copp) + return 0; + + if (open->copp_id == INVALID_COPP_ID) { + dev_err(&adev->dev, "Invalid coppid rxed %d\n", + open->copp_id); + copp->result.status = ADSP_EBADPARAM; + wake_up(&copp->wait); + break; + } + copp->result.opcode = hdr->opcode; + copp->id = open->copp_id; + wake_up(&copp->wait); + } + break; + default: + dev_err(&adev->dev, "Unknown cmd:0x%x\n", + hdr->opcode); + break; + } + + return 0; +} + +static struct q6copp *adm_alloc_copp(struct q6adm *adm, int port_idx) +{ + struct q6copp *c; + int idx; + + idx = find_first_zero_bit(&adm->copp_bitmap[port_idx], + MAX_COPPS_PER_PORT); + + if (idx > MAX_COPPS_PER_PORT) + return ERR_PTR(-EBUSY); + + c = kzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + return ERR_PTR(-ENOMEM); + + set_bit(idx, &adm->copp_bitmap[port_idx]); + c->copp_idx = idx; + c->afe_port = port_idx; + c->adm = adm; + + init_waitqueue_head(&c->wait); + + return c; +} + +static int q6adm_apr_send_copp_pkt(struct q6adm *adm, struct q6copp *copp, + struct apr_pkt *pkt, uint32_t rsp_opcode) +{ + struct device *dev = adm->dev; + uint32_t opcode = pkt->hdr.opcode; + int ret; + + mutex_lock(&adm->lock); + copp->result.opcode = 0; + copp->result.status = 0; + ret = apr_send_pkt(adm->apr, pkt); + if (ret < 0) { + dev_err(dev, "Failed to send APR packet\n"); + ret = -EINVAL; + goto err; + } + + /* Wait for the callback with copp id */ + if (rsp_opcode) + ret = wait_event_timeout(copp->wait, + (copp->result.opcode == opcode) || + (copp->result.opcode == rsp_opcode), + msecs_to_jiffies(TIMEOUT_MS)); + else + ret = wait_event_timeout(copp->wait, + (copp->result.opcode == opcode), + msecs_to_jiffies(TIMEOUT_MS)); + + if (!ret) { + dev_err(dev, "ADM copp cmd timedout\n"); + ret = -ETIMEDOUT; + } else if (copp->result.status > 0) { + dev_err(dev, "DSP returned error[%d]\n", + copp->result.status); + ret = -EINVAL; + } + +err: + mutex_unlock(&adm->lock); + return ret; +} + +static int q6adm_device_close(struct q6adm *adm, struct q6copp *copp, + int port_id, int copp_idx) +{ + struct apr_pkt close; + + close.hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + close.hdr.pkt_size = sizeof(close); + close.hdr.src_port = port_id; + close.hdr.dest_port = copp->id; + close.hdr.token = port_id << 16 | copp_idx; + close.hdr.opcode = ADM_CMD_DEVICE_CLOSE_V5; + + return q6adm_apr_send_copp_pkt(adm, copp, &close, 0); +} + +static void adm_free_copp(struct kref *ref) +{ + struct q6copp *c = container_of(ref, struct q6copp, refcount); + struct q6adm *adm = c->adm; + int port_idx = c->afe_port; + int copp_idx = c->copp_idx; + unsigned long flags; + int ret; + + ret = q6adm_device_close(adm, c, port_idx, copp_idx); + if (ret < 0) + dev_err(adm->dev, "Failed to close copp %d\n", ret); + + clear_bit(c->copp_idx, &adm->copp_bitmap[port_idx]); + spin_lock_irqsave(&adm->copps_list_lock, flags); + list_del(&c->node); + spin_unlock_irqrestore(&adm->copps_list_lock, flags); + kfree(c); +} + +static struct q6copp *adm_find_matching_copp(struct q6adm *adm, + int port_id, int topology, + int mode, int rate, int channel_mode, + int bit_width, int app_type) +{ + unsigned long flags; + struct q6copp *c; + + spin_lock_irqsave(&adm->copps_list_lock, flags); + + list_for_each_entry(c, &adm->copps_list, node) { + if ((port_id == c->afe_port) && (topology == c->topology) && + (mode == c->mode) && (rate == c->rate) && + (bit_width == c->bit_width) && (app_type == c->app_type)) { + spin_unlock_irqrestore(&adm->copps_list_lock, flags); + kref_get(&c->refcount); + return c; + } + } + spin_unlock_irqrestore(&adm->copps_list_lock, flags); + + c = adm_alloc_copp(adm, port_id); + if (IS_ERR_OR_NULL(c)) + return ERR_CAST(c); + + kref_init(&c->refcount); + c->topology = topology; + c->mode = mode; + c->rate = rate; + c->channels = channel_mode; + c->bit_width = bit_width; + c->app_type = app_type; + + spin_lock_irqsave(&adm->copps_list_lock, flags); + list_add_tail(&c->node, &adm->copps_list); + spin_unlock_irqrestore(&adm->copps_list_lock, flags); + + return c; +} + +static int q6adm_device_open(struct q6adm *adm, struct q6copp *copp, + int port_id, int path, int topology, + int channel_mode, int bit_width, int rate) +{ + struct q6adm_cmd_device_open_v5 *open; + int afe_port = q6afe_get_port_id(port_id); + struct apr_pkt *pkt; + void *p; + int ret, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*open); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + open = p + APR_HDR_SIZE; + pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.src_port = afe_port; + pkt->hdr.dest_port = afe_port; + pkt->hdr.token = port_id << 16 | copp->copp_idx; + pkt->hdr.opcode = ADM_CMD_DEVICE_OPEN_V5; + open->flags = ADM_LEGACY_DEVICE_SESSION; + open->mode_of_operation = path; + open->endpoint_id_1 = afe_port; + open->topology_id = topology; + open->dev_num_channel = channel_mode & 0x00FF; + open->bit_width = bit_width; + open->sample_rate = rate; + + ret = q6dsp_map_channels(&open->dev_channel_mapping[0], + channel_mode); + if (ret) + goto err; + + ret = q6adm_apr_send_copp_pkt(adm, copp, pkt, + ADM_CMDRSP_DEVICE_OPEN_V5); + +err: + kfree(pkt); + return ret; +} + +/** + * q6adm_open() - open adm and grab a free copp + * + * @dev: Pointer to adm child device. + * @port_id: port id + * @path: playback or capture path. + * @rate: rate at which copp is required. + * @channel_mode: channel mode + * @topology: adm topology id + * @perf_mode: performace mode. + * @bit_width: audio sample bit width + * @app_type: Application type. + * @acdb_id: ACDB id + * + * Return: Will be an negative on error or a valid copp index on success. + */ +int q6adm_open(struct device *dev, int port_id, int path, int rate, + int channel_mode, int topology, int perf_mode, + uint16_t bit_width, int app_type, int acdb_id) +{ + struct q6adm *adm = dev_get_drvdata(dev->parent); + struct q6copp *copp; + int ret = 0; + + if (port_id < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", port_id); + return -EINVAL; + } + + copp = adm_find_matching_copp(adm, port_id, topology, perf_mode, + rate, channel_mode, bit_width, app_type); + if (kref_read(&copp->refcount) == 1) { + /* not initialized yet */ + ret = q6adm_device_open(adm, copp, port_id, path, topology, + channel_mode, bit_width, rate); + if (ret < 0) + return ret; + } + + return copp->copp_idx; +} +EXPORT_SYMBOL_GPL(q6adm_open); + +/** + * q6adm_matrix_map() - Map asm streams and afe ports using payload + * + * @dev: Pointer to adm child device. + * @path: playback or capture path. + * @payload_map: map between session id and afe ports. + * @perf_mode: Performace mode. + * + * Return: Will be an negative on error or a zero on success. + */ +int q6adm_matrix_map(struct device *dev, int path, + struct route_payload payload_map, int perf_mode) +{ + struct q6adm *adm = dev_get_drvdata(dev->parent); + struct q6adm_cmd_matrix_map_routings_v5 *route; + struct q6adm_session_map_node_v5 *node; + struct apr_pkt *pkt; + uint16_t *copps_list; + int pkt_size, ret, i, copp_idx; + void *matrix_map = NULL; + struct q6copp *copp; + + /* Assumes port_ids have already been validated during adm_open */ + pkt_size = (APR_HDR_SIZE + sizeof(*route) + sizeof(*node) + + (sizeof(uint32_t) * payload_map.num_copps)); + + matrix_map = kzalloc(pkt_size, GFP_KERNEL); + if (!matrix_map) + return -ENOMEM; + + pkt = matrix_map; + route = matrix_map + APR_HDR_SIZE; + node = matrix_map + APR_HDR_SIZE + sizeof(*route); + copps_list = matrix_map + APR_HDR_SIZE + sizeof(*route) + sizeof(*node); + + pkt->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.token = 0; + pkt->hdr.opcode = ADM_CMD_MATRIX_MAP_ROUTINGS_V5; + route->num_sessions = 1; + + switch (path) { + case ADM_PATH_PLAYBACK: + route->matrix_id = ADM_MATRIX_ID_AUDIO_RX; + break; + case ADM_PATH_LIVE_REC: + route->matrix_id = ADM_MATRIX_ID_AUDIO_TX; + break; + default: + dev_err(dev, "Wrong path set[%d]\n", path); + break; + } + + node->session_id = payload_map.session_id; + node->num_copps = payload_map.num_copps; + + for (i = 0; i < payload_map.num_copps; i++) { + int port_idx = payload_map.port_id[i]; + + if (port_idx < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", + payload_map.port_id[i]); + kfree(pkt); + return -EINVAL; + } + copp_idx = payload_map.copp_idx[i]; + + copp = adm_find_copp(adm, port_idx, copp_idx); + if (!copp) { + kfree(pkt); + return -EINVAL; + } + + copps_list[i] = copp->id; + } + + mutex_lock(&adm->lock); + adm->result.status = 0; + adm->result.opcode = 0; + + ret = apr_send_pkt(adm->apr, pkt); + if (ret < 0) { + dev_err(dev, "routing for stream %d failed ret %d\n", + payload_map.session_id, ret); + goto fail_cmd; + } + ret = wait_event_timeout(adm->matrix_map_wait, + adm->result.opcode == pkt->hdr.opcode, + msecs_to_jiffies(TIMEOUT_MS)); + if (!ret) { + dev_err(dev, "routing for stream %d failed\n", + payload_map.session_id); + ret = -ETIMEDOUT; + goto fail_cmd; + } else if (adm->result.status > 0) { + dev_err(dev, "DSP returned error[%d]\n", + adm->result.status); + ret = -EINVAL; + goto fail_cmd; + } + +fail_cmd: + mutex_unlock(&adm->lock); + kfree(pkt); + return ret; +} +EXPORT_SYMBOL_GPL(q6adm_matrix_map); + +/** + * q6adm_close() - Close adm copp + * + * @dev: Pointer to adm child device. + * @port_id: afe port id. + * @copp_idx: copp index to close + * + * Return: Will be an negative on error or a zero on success. + */ +int q6adm_close(struct device *dev, int port_id, int copp_idx) +{ + struct q6adm *adm = dev_get_drvdata(dev->parent); + struct q6copp *copp; + + if (port_id < 0) { + dev_err(dev, "Invalid port_id 0x%x\n", port_id); + return -EINVAL; + } + + if ((copp_idx < 0) || (copp_idx >= MAX_COPPS_PER_PORT)) { + dev_err(dev, "Invalid copp idx: %d\n", copp_idx); + return -EINVAL; + } + + copp = adm_find_copp(adm, port_id, copp_idx); + if (!copp) + return -EINVAL; + + kref_put(&copp->refcount, adm_free_copp); + + return 0; +} +EXPORT_SYMBOL_GPL(q6adm_close); + +static int q6adm_probe(struct apr_device *adev) +{ + struct device *dev = &adev->dev; + struct device_node *dais_np; + struct q6adm *adm; + + adm = devm_kzalloc(&adev->dev, sizeof(*adm), GFP_KERNEL); + if (!adm) + return -ENOMEM; + + adm->apr = adev; + dev_set_drvdata(&adev->dev, adm); + adm->dev = dev; + q6core_get_svc_api_info(adev->svc_id, &adm->ainfo); + mutex_init(&adm->lock); + init_waitqueue_head(&adm->matrix_map_wait); + + INIT_LIST_HEAD(&adm->copps_list); + spin_lock_init(&adm->copps_list_lock); + + dais_np = of_get_child_by_name(dev->of_node, "routing"); + if (dais_np) { + adm->pdev_routing = of_platform_device_create(dais_np, + "q6routing", dev); + of_node_put(dais_np); + } + + return 0; +} + +static int q6adm_remove(struct apr_device *adev) +{ + struct q6adm *adm = dev_get_drvdata(&adev->dev); + + if (adm->pdev_routing) + of_platform_device_destroy(&adm->pdev_routing->dev, NULL); + + return 0; +} + +static const struct of_device_id q6adm_device_id[] = { + { .compatible = "qcom,q6adm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6adm_device_id); + +static struct apr_driver qcom_q6adm_driver = { + .probe = q6adm_probe, + .remove = q6adm_remove, + .callback = q6adm_callback, + .driver = { + .name = "qcom-q6adm", + .of_match_table = of_match_ptr(q6adm_device_id), + }, +}; + +module_apr_driver(qcom_q6adm_driver); +MODULE_DESCRIPTION("Q6 Audio Device Manager"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6adm.h b/sound/soc/qcom/qdsp6/q6adm.h new file mode 100644 index 000000000000..9da655d102af --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6adm.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6_ADM_V2_H__ +#define __Q6_ADM_V2_H__ + +#define ADM_PATH_PLAYBACK 0x1 +#define ADM_PATH_LIVE_REC 0x2 +#define MAX_COPPS_PER_PORT 8 +#define NULL_COPP_TOPOLOGY 0x00010312 + +/* multiple copp per stream. */ +struct route_payload { + int num_copps; + int session_id; + int copp_idx[MAX_COPPS_PER_PORT]; + int port_id[MAX_COPPS_PER_PORT]; +}; + +int q6adm_open(struct device *dev, int port_id, int path, int rate, + int channel_mode, int topology, int perf_mode, + uint16_t bit_width, int app_type, int acdb_id); +int q6adm_close(struct device *dev, int port_id, int copp_idx); +int q6adm_matrix_map(struct device *dev, int path, + struct route_payload payload_map, int perf_mode); + +#endif /* __Q6_ADM_V2_H__ */ From patchwork Wed May 9 12:56:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135275 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5614715lji; Wed, 9 May 2018 06:04:14 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqBHlVvhZH49N3MNrPIGzK/2pFuT0Eoz0b9T8j7nYY958cFYb1eZKNLSxAkjuxYG7Qadksd X-Received: by 2002:a17:902:362:: with SMTP id 89-v6mr46319997pld.270.1525871054753; Wed, 09 May 2018 06:04:14 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871054; cv=none; d=google.com; s=arc-20160816; b=bZpJFH3od/P7km4M+kJ1GR7iVSl3hIJCADe4SPnsF5xCzWg+dURp8v9+9cmCMhLf0h mIaRUciHbEZx42dt061/839xQ8VGUekNW5+yTaPKGm/jyS73ylGv2KVKIUgaFVXC1j3p B4Xoo/y8S8AFn4NbhE0ItFW3DmPWxfQoN9ZBUS55PdJcG5hm9Ude71v3Cpc8p1DgyTKx yyTBBTzyQVlRwaTcr/oJjCE/+jWr5ShEx1LdovMhX7OMsDwoonbv+3CzQUGISQcEI9D2 F+NXe/72F5YREoy760/JMsym8HEtJBTf40dM8cBtlgbkWMuqZQgqWvcdDAC6MxV1lNMU UsOQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=Pz2rjvs+u56f207IJitkwNDLOaoitcNF7rUPUv1boCA=; b=Gkp0+NNBaaqHGkxRctzLlegfuokjacc+zo8bdNSsZNL9Zc6llifY37uLyqCCN+Tt9l q/86B0L9fQheW9DyW2SXbCqryzg017ffEXG+Y5hSViA58ulH/njIUACMNThky/K6Eb/B RuFHmH0EWueX/+S+75yL2cC+hbMHYTEqa1+i4K7QL0wRVlaKmeg2zoQurk+Bbeo7vnRR NMuTSYKJOIYbKWSf3L0IzaAtIsdiZwcXeRQWCN2aduyP0X8Wme3e/IPZlm/6E635xvE8 NrpjYaZAtCL4ZpibTwkRLteSV69dodxFHbcO0cjTT0W7KY0Z6NzIS4TVF3Cv6f3DVd3z 56+g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Kug9aPRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id q4-v6si26066446plb.251.2018.05.09.06.04.14; Wed, 09 May 2018 06:04:14 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=Kug9aPRc; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935203AbeEINEM (ORCPT + 29 others); Wed, 9 May 2018 09:04:12 -0400 Received: from mail-wr0-f196.google.com ([209.85.128.196]:39362 "EHLO mail-wr0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935082AbeEINA7 (ORCPT ); Wed, 9 May 2018 09:00:59 -0400 Received: by mail-wr0-f196.google.com with SMTP id q3-v6so35564796wrj.6 for ; Wed, 09 May 2018 06:00:58 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Pz2rjvs+u56f207IJitkwNDLOaoitcNF7rUPUv1boCA=; b=Kug9aPRclqo3ntrA+pY8PUeB3w1NUi6kh51dK9u43hRunFREZIvZn8gLeo/y5d04W7 1HJQbuSzq6B1EO3AIH0q7ylRKQ3ygLXjlWsv5WbKrJ0aBP7GAPTYKUAjAswY8+MP+95t s8IYDwTucnU5L/I+EiTd8iJFavegmHwod5SzA= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Pz2rjvs+u56f207IJitkwNDLOaoitcNF7rUPUv1boCA=; b=NHmteQVLXj5DpAurIyU8UTXa+aqf1GKPB/RzSCahVs2PF4p7IhuUQTGER+q2C9YslE 78cwOWHFPkIN2cn/ciHkxg+faqi+MIfW/gVZAEMqBBeCSr14tKH2OVfk98wjQkrv59Qh gs2Ng7YzTuqNbAD0vt9veOiluEK/3XyqFA4SP/3NgrCuyGbWBNp5PASr1Kr1RbzWa2wW FmNQm/4rPBrQGjQ82FWlJ1B2TpNHlBrB3Tvnz6iHFMWZ7/fNuhGbIfVj3jFMQlyW60fk IFxrm0Bbwclr3OlIXyeU6uCNDNRiH020yOH02Cqvzzym3pMr8F0WSbbz/sjyePgYwVKT EAvA== X-Gm-Message-State: ALQs6tCm9lcoPkDPF7v+WOWqEpzv/k61Pu9SVFsgOxVOquiNmZLP0uZ0 Ad6pRYfDIQ9UfLLaLyTED5EyFA== X-Received: by 2002:adf:8644:: with SMTP id 4-v6mr39346811wrw.73.1525870857833; Wed, 09 May 2018 06:00:57 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.56 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:56 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 14/24] ASoC: qdsp6: q6asm: Add q6asm driver Date: Wed, 9 May 2018 13:56:25 +0100 Message-Id: <20180509125635.5653-15-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds basic support to Q6 ASM (Audio Stream Manager) module on Q6DSP. ASM supports up to 8 concurrent streams. each stream can be setup as playback/capture. ASM provides top control functions like Pause/flush/resume for playback and record. ASM can Create/destroy encoder, decoder and also provides POPP dynamic services. This patch adds support to basic features to allow hdmi playback. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6asm.c | 215 ++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 15 +++ 4 files changed, 235 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6asm.c create mode 100644 sound/soc/qcom/qdsp6/q6asm.h -- 2.16.2 diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 971127edbc23..941774abd94f 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -53,6 +53,9 @@ config SND_SOC_QDSP6_AFE config SND_SOC_QDSP6_ADM tristate +config SND_SOC_QDSP6_ASM + tristate + config SND_SOC_QDSP6 tristate "SoC ALSA audio driver for QDSP6" depends on QCOM_APR && HAS_DMA @@ -60,6 +63,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE select SND_SOC_QDSP6_ADM + select SND_SOC_QDSP6_ASM help To add support for MSM QDSP6 Soc Audio. This will enable sound soc platform specific diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 95cdb3a12694..01d9dcf3375c 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o +obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c new file mode 100644 index 000000000000..09f62e90ab00 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6asm.h" +#include "q6core.h" +#include "q6dsp-errno.h" +#include "q6dsp-common.h" + +#define ASM_SYNC_IO_MODE 0x0001 +#define ASM_ASYNC_IO_MODE 0x0002 +#define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ +#define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */ + +struct audio_client { + int session; + q6asm_cb cb; + void *priv; + uint32_t io_mode; + struct apr_device *adev; + struct mutex lock; + spinlock_t buf_lock; + wait_queue_head_t cmd_wait; + struct aprv2_ibasic_rsp_result_t result; + int perf_mode; + int stream_id; + struct device *dev; +}; + +struct q6asm { + struct apr_device *adev; + struct device *dev; + struct q6core_svc_api_info ainfo; + wait_queue_head_t mem_wait; + struct platform_device *pcmdev; + struct audio_client *session[MAX_SESSIONS + 1]; + struct platform_device *pdev_dais; +}; + +/** + * q6asm_audio_client_free() - Freee allocated audio client + * + * @ac: audio client to free + */ +void q6asm_audio_client_free(struct audio_client *ac) +{ + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + + a->session[ac->session] = NULL; + kfree(ac); +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_free); + +static struct audio_client *q6asm_get_audio_client(struct q6asm *a, + int session_id) +{ + if ((session_id <= 0) || (session_id > MAX_SESSIONS)) { + dev_err(a->dev, "invalid session: %d\n", session_id); + return NULL; + } + + if (!a->session[session_id]) { + dev_err(a->dev, "session not active: %d\n", session_id); + return NULL; + } + + return a->session[session_id]; +} + +static int q6asm_srvc_callback(struct apr_device *adev, + struct apr_resp_pkt *data) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct audio_client *ac = NULL; + struct apr_hdr *hdr = &data->hdr; + uint32_t sid = 0; + + sid = (hdr->token >> 8) & 0x0F; + ac = q6asm_get_audio_client(q6asm, sid); + if (!ac) { + dev_err(&adev->dev, "Audio Client not active\n"); + return 0; + } + + if (ac->cb) + ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv); + + return 0; +} + +/** + * q6asm_get_session_id() - get session id for audio client + * + * @c: audio client pointer + * + * Return: Will be an session id of the audio client. + */ +int q6asm_get_session_id(struct audio_client *c) +{ + return c->session; +} +EXPORT_SYMBOL_GPL(q6asm_get_session_id); + +/** + * q6asm_audio_client_alloc() - Allocate a new audio client + * + * @dev: Pointer to asm child device. + * @cb: event callback. + * @priv: private data associated with this client. + * @stream_id: stream id + * @perf_mode: performace mode for this client + * + * Return: Will be an error pointer on error or a valid audio client + * on success. + */ +struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, + void *priv, int stream_id, + int perf_mode) +{ + struct q6asm *a = dev_get_drvdata(dev->parent); + struct audio_client *ac; + + if (stream_id + 1 > MAX_SESSIONS) + return ERR_PTR(-EINVAL); + + ac = kzalloc(sizeof(*ac), GFP_KERNEL); + if (!ac) + return ERR_PTR(-ENOMEM); + + a->session[stream_id + 1] = ac; + ac->session = stream_id + 1; + ac->cb = cb; + ac->dev = dev; + ac->priv = priv; + ac->io_mode = ASM_SYNC_IO_MODE; + ac->perf_mode = perf_mode; + /* DSP expects stream id from 1 */ + ac->stream_id = 1; + ac->adev = a->adev; + + init_waitqueue_head(&ac->cmd_wait); + mutex_init(&ac->lock); + spin_lock_init(&ac->buf_lock); + + return ac; +} +EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); + + +static int q6asm_probe(struct apr_device *adev) +{ + struct device *dev = &adev->dev; + struct device_node *dais_np; + struct q6asm *q6asm; + + q6asm = devm_kzalloc(dev, sizeof(*q6asm), GFP_KERNEL); + if (!q6asm) + return -ENOMEM; + + q6core_get_svc_api_info(adev->svc_id, &q6asm->ainfo); + + q6asm->dev = dev; + q6asm->adev = adev; + init_waitqueue_head(&q6asm->mem_wait); + dev_set_drvdata(dev, q6asm); + + dais_np = of_get_child_by_name(dev->of_node, "dais"); + if (dais_np) { + q6asm->pdev_dais = of_platform_device_create(dais_np, + "q6asm-dai", dev); + of_node_put(dais_np); + } + + return 0; +} + +static int q6asm_remove(struct apr_device *adev) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + + if (q6asm->pdev_dais) + of_platform_device_destroy(&q6asm->pdev_dais->dev, NULL); + + return 0; +} +static const struct of_device_id q6asm_device_id[] = { + { .compatible = "qcom,q6asm" }, + {}, +}; +MODULE_DEVICE_TABLE(of, q6asm_device_id); + +static struct apr_driver qcom_q6asm_driver = { + .probe = q6asm_probe, + .remove = q6asm_remove, + .callback = q6asm_srvc_callback, + .driver = { + .name = "qcom-q6asm", + .of_match_table = of_match_ptr(q6asm_device_id), + }, +}; + +module_apr_driver(qcom_q6asm_driver); +MODULE_DESCRIPTION("Q6 Audio Stream Manager driver"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h new file mode 100644 index 000000000000..b7816e6384e7 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -0,0 +1,15 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __Q6_ASM_H__ +#define __Q6_ASM_H__ + +#define MAX_SESSIONS 8 + +typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, + void *payload, void *priv); +struct audio_client; +struct audio_client *q6asm_audio_client_alloc(struct device *dev, + q6asm_cb cb, void *priv, + int session_id, int perf_mode); +void q6asm_audio_client_free(struct audio_client *ac); +int q6asm_get_session_id(struct audio_client *ac); +#endif /* __Q6_ASM_H__ */ From patchwork Wed May 9 12:56:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135265 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5609991lji; Wed, 9 May 2018 06:01:14 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpKibUVWmeJxsYx3EbLN/o85Pkp6zAdSsgp5Y8D1wkdq/om05v6JoVPw9KnqF8THTqANz2l X-Received: by 2002:a65:65ce:: with SMTP id y14-v6mr35968833pgv.137.1525870873756; Wed, 09 May 2018 06:01:13 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525870873; cv=none; d=google.com; s=arc-20160816; b=CW8DkukVKEB4YMjpw8JQ4yfRjU+mxB943/tlxc2DaD7LzbPVTCdxicmP1wVquKY23N nPT3TVkpULAiTp05fs/YQ25cu+T5afYlPoIYf0zHLngLMtWL+52ZYYSqyKpT6/KYzv5N zFWdSNYSBYWryjsaaVu776fkpDF866XAg3pmKhMLb46cUzCQiPMXtpGEw2SMhB8lhrLy kEiP1I29/s9feUmHqTQwR0HmnVohZAYjbN5kVrf1LWi2x+Tohe9/LqSnQPIBHlBSqMmb iAzVtnIjRpt3vU9a8HjKI14EuP0/ervt7Tbi4iKfM1fE6moNLPuyHfg9KSRXzoicUevS GVVw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=xVTXSpmPdX9ogkG9touImOUR9iW9380jppVZiH8Oc/Y=; b=jQn3y7Kf0BpTbJCL0uzppXAks1kecJYjbkvkZxAcQZ6b5cMQXp8RFHG74kEqBAuftW OXnuUYLySjr5qa0M1EyXgTKnx941EXt1z8pJpWcFKoIpIcbRWbUVyDlbgZNLGNItHuji 3Lmqita/xJh5KVXkZH+noVhX1wqV9Fpc0Zy/YMJ8vYWj8SdV1MihVEgj2uZHUkuPHygk BnD4AOouQ5A7SfVK/BtqkefR2+9SynwlLop0YYGaLk3Dkdx+msC/P34PozbA+iANrhsJ hxp2gJLzVTv0pw1+HxripXjfB+u5/iSQqjM1GqinGo3AsynmotuT8GpM7ZRFqbPZw/ps m5VQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YZDiGewB; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id r4si27552479pff.24.2018.05.09.06.01.13; Wed, 09 May 2018 06:01:13 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=YZDiGewB; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935156AbeEINBJ (ORCPT + 29 others); Wed, 9 May 2018 09:01:09 -0400 Received: from mail-wm0-f66.google.com ([74.125.82.66]:39230 "EHLO mail-wm0-f66.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935136AbeEINBB (ORCPT ); Wed, 9 May 2018 09:01:01 -0400 Received: by mail-wm0-f66.google.com with SMTP id f8-v6so27694063wmc.4 for ; Wed, 09 May 2018 06:01:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=xVTXSpmPdX9ogkG9touImOUR9iW9380jppVZiH8Oc/Y=; b=YZDiGewBMmQCgp4RNiDAiSz1zT3smwG7P7GQ7xvefaTgF4zeUZQRNv2hiKE7rJdPbE 9Zajwi1T5jXIJPatii5NZdSLHeLqXpi5txqAjxjFz3z5xFFe7G3gzcFJUY/mvkrUnZPN AC/pRt1Ro1vMx4Kl8Ca7Fm0dFwR3BYw6d112Y= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=xVTXSpmPdX9ogkG9touImOUR9iW9380jppVZiH8Oc/Y=; b=Vv7wdL/UIQm0vnxLG79J3dFL8iqVUfu6Hf2hORD2TU4Co5allIpVNnnGxhblgh9gkz czSO3SMAvKDxPBQIzakv9sip/I2Yeco3dhpMBwBC5o/WNLI+soei4NGNOw4Ung8qZ55x lalNPoWh4BvgTev3VQp2aoJM7QS/BEAMBRk3qgmDpfy4XaKzKD53NFHh1Y+hZanbghPm Wbg6H9byZ62NE9tLl/il9OksEgfy8C2V7+rS1QnU5fxgeP5SdO+cBk0FIsxc4nqrZQpv ShMtFLl01a/vPQ7hGaqYK5k+qxcsg5fNgAgwJdt/sSbrXLvYGoPpv1XLXRs7C/L2L2YU z0Lg== X-Gm-Message-State: ALKqPwcbxum5P5ln2mWAzL2Ay+GKhsn7WYk4sA2c+FKVXqW3ddMmAITS xyd2z2dg8rMfIU3o1sqJif0XWQ== X-Received: by 2002:a1c:5d4f:: with SMTP id r76-v6mr5664460wmb.55.1525870859671; Wed, 09 May 2018 06:00:59 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:00:58 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 15/24] ASoC: qdsp6: q6asm: Add support to memory map and unmap Date: Wed, 9 May 2018 13:56:26 +0100 Message-Id: <20180509125635.5653-16-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to memory map and unmap regions commands in q6asm module. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6asm.c | 351 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6asm.h | 5 + 2 files changed, 356 insertions(+) -- 2.16.2 diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 09f62e90ab00..044ad57d15a0 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -18,10 +18,45 @@ #include "q6dsp-errno.h" #include "q6dsp-common.h" +#define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92 +#define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93 +#define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94 + #define ASM_SYNC_IO_MODE 0x0001 #define ASM_ASYNC_IO_MODE 0x0002 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ #define ASM_TUN_WRITE_IO_MODE 0x0008 /* tunnel read write mode */ +#define ASM_SHIFT_GAPLESS_MODE_FLAG 31 +#define ADSP_MEMORY_MAP_SHMEM8_4K_POOL 3 + +struct avs_cmd_shared_mem_map_regions { + u16 mem_pool_id; + u16 num_regions; + u32 property_flag; +} __packed; + +struct avs_shared_map_region_payload { + u32 shm_addr_lsw; + u32 shm_addr_msw; + u32 mem_size_bytes; +} __packed; + +struct avs_cmd_shared_mem_unmap_regions { + u32 mem_map_handle; +} __packed; + +struct audio_buffer { + phys_addr_t phys; + uint32_t used; + uint32_t size; /* size of buffer */ +}; + +struct audio_port_data { + struct audio_buffer *buf; + uint32_t num_periods; + uint32_t dsp_buf; + uint32_t mem_map_handle; +}; struct audio_client { int session; @@ -31,6 +66,8 @@ struct audio_client { struct apr_device *adev; struct mutex lock; spinlock_t buf_lock; + /* idx:1 out port, 0: in port */ + struct audio_port_data port[2]; wait_queue_head_t cmd_wait; struct aprv2_ibasic_rsp_result_t result; int perf_mode; @@ -48,6 +85,279 @@ struct q6asm { struct platform_device *pdev_dais; }; +static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, + uint32_t pkt_size, bool cmd_flg, + uint32_t stream_id) +{ + hdr->hdr_field = APR_SEQ_CMD_HDR_FIELD; + hdr->src_port = ((ac->session << 8) & 0xFF00) | (stream_id); + hdr->dest_port = ((ac->session << 8) & 0xFF00) | (stream_id); + hdr->pkt_size = pkt_size; + if (cmd_flg) + hdr->token = ac->session; +} + +static int q6asm_apr_send_session_pkt(struct q6asm *a, struct audio_client *ac, + struct apr_pkt *pkt, uint32_t rsp_opcode) +{ + struct apr_hdr *hdr = &pkt->hdr; + int rc; + + mutex_lock(&ac->lock); + ac->result.opcode = 0; + ac->result.status = 0; + rc = apr_send_pkt(a->adev, pkt); + if (rc < 0) + goto err; + + if (rsp_opcode) + rc = wait_event_timeout(a->mem_wait, + (ac->result.opcode == hdr->opcode) || + (ac->result.opcode == rsp_opcode), + 5 * HZ); + else + rc = wait_event_timeout(a->mem_wait, + (ac->result.opcode == hdr->opcode), + 5 * HZ); + + if (!rc) { + dev_err(a->dev, "CMD timeout\n"); + rc = -ETIMEDOUT; + } else if (ac->result.status > 0) { + dev_err(a->dev, "DSP returned error[%x]\n", + ac->result.status); + rc = -EINVAL; + } + +err: + mutex_unlock(&ac->lock); + return rc; +} + +static int __q6asm_memory_unmap(struct audio_client *ac, + phys_addr_t buf_add, int dir) +{ + struct avs_cmd_shared_mem_unmap_regions *mem_unmap; + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + struct apr_pkt *pkt; + int rc, pkt_size; + void *p; + + if (ac->port[dir].mem_map_handle == 0) { + dev_err(ac->dev, "invalid mem handle\n"); + return -EINVAL; + } + pkt_size = APR_HDR_SIZE + sizeof(*mem_unmap); + + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + mem_unmap = p + APR_HDR_SIZE; + + pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; + pkt->hdr.src_port = 0; + pkt->hdr.dest_port = 0; + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.token = ((ac->session << 8) | dir); + + pkt->hdr.opcode = ASM_CMD_SHARED_MEM_UNMAP_REGIONS; + mem_unmap->mem_map_handle = ac->port[dir].mem_map_handle; + + rc = q6asm_apr_send_session_pkt(a, ac, pkt, 0); + if (rc < 0) { + kfree(pkt); + return rc; + } + + ac->port[dir].mem_map_handle = 0; + + kfree(pkt); + return 0; +} + + +static void q6asm_audio_client_free_buf(struct audio_client *ac, + struct audio_port_data *port) +{ + unsigned long flags; + + spin_lock_irqsave(&ac->buf_lock, flags); + + port->num_periods = 0; + kfree(port->buf); + port->buf = NULL; + + spin_unlock_irqrestore(&ac->buf_lock, flags); +} + +/** + * q6asm_unmap_memory_regions() - unmap memory regions in the dsp. + * + * @dir: direction of audio stream + * @ac: audio client instanace + * + * Return: Will be an negative value on failure or zero on success + */ +int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac) +{ + struct audio_port_data *port; + int cnt = 0; + int rc = 0; + + port = &ac->port[dir]; + if (!port->buf) { + rc = -EINVAL; + goto err; + } + + cnt = port->num_periods - 1; + if (cnt >= 0) { + rc = __q6asm_memory_unmap(ac, port->buf[dir].phys, dir); + if (rc < 0) { + dev_err(ac->dev, "%s: Memory_unmap_regions failed %d\n", + __func__, rc); + goto err; + } + } + + q6asm_audio_client_free_buf(ac, port); + +err: + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_unmap_memory_regions); + +static int __q6asm_memory_map_regions(struct audio_client *ac, int dir, + size_t period_sz, unsigned int periods, + bool is_contiguous) +{ + struct avs_cmd_shared_mem_map_regions *cmd = NULL; + struct avs_shared_map_region_payload *mregions = NULL; + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + struct audio_port_data *port = NULL; + struct audio_buffer *ab = NULL; + struct apr_pkt *pkt; + void *p; + unsigned long flags; + uint32_t num_regions, buf_sz; + int rc, i, pkt_size; + + if (is_contiguous) { + num_regions = 1; + buf_sz = period_sz * periods; + } else { + buf_sz = period_sz; + num_regions = periods; + } + + /* DSP expects size should be aligned to 4K */ + buf_sz = ALIGN(buf_sz, 4096); + + pkt_size = APR_HDR_SIZE + sizeof(*cmd) + + (sizeof(*mregions) * num_regions); + + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + cmd = p + APR_HDR_SIZE; + mregions = p + APR_HDR_SIZE + sizeof(*cmd); + + pkt->hdr.hdr_field = APR_SEQ_CMD_HDR_FIELD; + pkt->hdr.src_port = 0; + pkt->hdr.dest_port = 0; + pkt->hdr.pkt_size = pkt_size; + pkt->hdr.token = ((ac->session << 8) | dir); + pkt->hdr.opcode = ASM_CMD_SHARED_MEM_MAP_REGIONS; + + cmd->mem_pool_id = ADSP_MEMORY_MAP_SHMEM8_4K_POOL; + cmd->num_regions = num_regions; + cmd->property_flag = 0x00; + + port = &ac->port[dir]; + + spin_lock_irqsave(&ac->buf_lock, flags); + for (i = 0; i < num_regions; i++) { + ab = &port->buf[i]; + mregions->shm_addr_lsw = lower_32_bits(ab->phys); + mregions->shm_addr_msw = upper_32_bits(ab->phys); + mregions->mem_size_bytes = buf_sz; + ++mregions; + } + spin_unlock_irqrestore(&ac->buf_lock, flags); + + rc = q6asm_apr_send_session_pkt(a, ac, pkt, + ASM_CMDRSP_SHARED_MEM_MAP_REGIONS); + + kfree(pkt); + + return rc; +} + +/** + * q6asm_map_memory_regions() - map memory regions in the dsp. + * + * @dir: direction of audio stream + * @ac: audio client instanace + * @phys: physcial address that needs mapping. + * @period_sz: audio period size + * @periods: number of periods + * + * Return: Will be an negative value on failure or zero on success + */ +int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, + phys_addr_t phys, + size_t period_sz, unsigned int periods) +{ + struct audio_buffer *buf; + unsigned long flags; + int cnt; + int rc; + + spin_lock_irqsave(&ac->buf_lock, flags); + if (ac->port[dir].buf) { + dev_err(ac->dev, "Buffer already allocated\n"); + spin_unlock_irqrestore(&ac->buf_lock, flags); + return 0; + } + + buf = kzalloc(((sizeof(struct audio_buffer)) * periods), GFP_ATOMIC); + if (!buf) { + spin_unlock_irqrestore(&ac->buf_lock, flags); + return -ENOMEM; + } + + + ac->port[dir].buf = buf; + + buf[0].phys = phys; + buf[0].used = !!dir; + buf[0].size = period_sz; + + for (cnt = 1; cnt < periods; cnt++) { + if (period_sz > 0) { + buf[cnt].phys = buf[0].phys + (cnt * period_sz); + buf[cnt].used = dir ^ 1; + buf[cnt].size = period_sz; + } + } + spin_unlock_irqrestore(&ac->buf_lock, flags); + + ac->port[dir].num_periods = periods; + + rc = __q6asm_memory_map_regions(ac, dir, period_sz, periods, 1); + if (rc < 0) { + dev_err(ac->dev, "Memory_map_regions failed\n"); + q6asm_audio_client_free_buf(ac, &ac->port[dir]); + } + + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_map_memory_regions); + /** * q6asm_audio_client_free() - Freee allocated audio client * @@ -82,9 +392,13 @@ static int q6asm_srvc_callback(struct apr_device *adev, struct apr_resp_pkt *data) { struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct aprv2_ibasic_rsp_result_t *result; + struct audio_port_data *port; struct audio_client *ac = NULL; struct apr_hdr *hdr = &data->hdr; + struct q6asm *a; uint32_t sid = 0; + uint32_t dir = 0; sid = (hdr->token >> 8) & 0x0F; ac = q6asm_get_audio_client(q6asm, sid); @@ -93,6 +407,43 @@ static int q6asm_srvc_callback(struct apr_device *adev, return 0; } + a = dev_get_drvdata(ac->dev->parent); + dir = (hdr->token & 0x0F); + port = &ac->port[dir]; + result = data->payload; + + switch (hdr->opcode) { + case APR_BASIC_RSP_RESULT: + switch (result->opcode) { + case ASM_CMD_SHARED_MEM_MAP_REGIONS: + case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: + ac->result = *result; + wake_up(&a->mem_wait); + break; + default: + dev_err(&adev->dev, "command[0x%x] not expecting rsp\n", + result->opcode); + break; + } + return 0; + case ASM_CMDRSP_SHARED_MEM_MAP_REGIONS: + ac->result.status = 0; + ac->result.opcode = hdr->opcode; + port->mem_map_handle = result->opcode; + wake_up(&a->mem_wait); + break; + case ASM_CMD_SHARED_MEM_UNMAP_REGIONS: + ac->result.opcode = hdr->opcode; + ac->result.status = 0; + port->mem_map_handle = 0; + wake_up(&a->mem_wait); + break; + default: + dev_dbg(&adev->dev, "command[0x%x]success [0x%x]\n", + result->opcode, result->status); + break; + } + if (ac->cb) ac->cb(hdr->opcode, hdr->token, data->payload, ac->priv); diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index b7816e6384e7..8c317b7b63c3 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -12,4 +12,9 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, int session_id, int perf_mode); void q6asm_audio_client_free(struct audio_client *ac); int q6asm_get_session_id(struct audio_client *ac); +int q6asm_map_memory_regions(unsigned int dir, + struct audio_client *ac, + phys_addr_t phys, + size_t bufsz, unsigned int bufcnt); +int q6asm_unmap_memory_regions(unsigned int dir, struct audio_client *ac); #endif /* __Q6_ASM_H__ */ From patchwork Wed May 9 12:56:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135274 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5613681lji; Wed, 9 May 2018 06:03:30 -0700 (PDT) X-Google-Smtp-Source: AB8JxZp+pIHuEbVxywkXtDO/biQWsZ6ArsXSoAeDgdAE0PasTUvof2Hsgym3JbYS+916TfYc7eUy X-Received: by 2002:a17:902:7841:: with SMTP id e1-v6mr46197054pln.197.1525871009952; Wed, 09 May 2018 06:03:29 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871009; cv=none; d=google.com; s=arc-20160816; b=jWNQnz6/FWAiLIr0caqK4up3633gfxa6R3adO5lP0JIdJa9g0MxiKp4JDC3tjjqoFS TVGsfRk2idINNKLA067HJtjyLrRxI0sqfXClpGyy9SgI+ocN03eM204iQRMRpRIbOTgl cXDpFgziA8KfYWsFxXifM9NT86inApdbBk+27TeS1rsa3DZuCQrihekJ/rh8qpxWqK3Y yb3XVu8p6SrYUJqP3fOp/cBSBvF8//5UUEcCn7awPvfQ7BENQrk+DvypU4rgJzwT2z0m rdSUis7HB/NmEyhtewC+BSS6Seokn2KB5CGti1Zj8kKCfdccC77WOsEbDvBJxelKxS1Q PO9Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=sc5NqqjnOucNe38fhHLcUxKc0WyHr0tOJkZEO+fhmh8=; b=zAeczTyjvGXxuxTF7MFgogsgqMUMXVcqdvr5uIqUiCkqVtNWjcEZlKeuybr8IHPhrH +/jvDw87wqqMDdtkkGSt0tJVk/xjfvdMfpaBy8X5Uf2kd8rdkkaPA1r3M7YJYDjkJr7I 5crPf/c/IvxvwWjQn9/7TNCG7Az01AqXqe3QiMbZ65WHg4fBIWOgolYNF9LY36h7Sgvb vaYP5EYTNm8OpZ+JQ/usyOAWKTao9pm1MIlXUug4iA2iRqCfyZMgQpdDpO20Wgzql3kZ H9z3rT5YVDnR+bNwb+fWrdnaiLyzE3vkxIETA3q9WCPQK77bcEZ6cIgsj4InumFp/mr+ KVFw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EuIal/rb; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i14-v6si21173948pgc.250.2018.05.09.06.03.29; Wed, 09 May 2018 06:03:29 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EuIal/rb; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935254AbeEIND1 (ORCPT + 29 others); Wed, 9 May 2018 09:03:27 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:41854 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S934774AbeEINBD (ORCPT ); Wed, 9 May 2018 09:01:03 -0400 Received: by mail-wr0-f195.google.com with SMTP id g21-v6so35540293wrb.8 for ; Wed, 09 May 2018 06:01:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=sc5NqqjnOucNe38fhHLcUxKc0WyHr0tOJkZEO+fhmh8=; b=EuIal/rbvbinz3ItDOYaS1lJJNDn61Bkl81W3flA+IM3Jqdg9CuQ52CqCRJqpy3Cgo i+aEyMk4GmyTmsIryufBlf0sdU/74kQB10ILq5nFymsJVD0IDa3kQELWas7vSTaFf4K5 rQsFOT0rbLcoDuOTlQqlXQQtN6mUtFwEbDJHE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=sc5NqqjnOucNe38fhHLcUxKc0WyHr0tOJkZEO+fhmh8=; b=hMtZgR2+HjL3ghv5uCdwkduQLzGnEfRPCRBlelI0JhDmxbooK2pze91N0FoymNDSpu bSYCEbz+nywdZdg9AiSXbHxYY3xoiVNaeUZ9R2o3wsdOw1Ev1E0pPMyo5LV2JQQDnLFT cgxfTdyXcpz2YKlRmftVyY/L/St2oVaZkWWS6fNZF3OI29YC8zuCsxdoNpqQbTNF7o2L 4tYD3SnWV7brm+8ibew/NCYFC6d9IMRoW+fd9rYDtBV6B1fFk2f2csd/J9wpv+kVy+Xx 71CmB3X3hfrAoJcmN+ki8cuOsmWJTs2ohaJu0wtUQaOgOEKfbrDBJ43QitpuPWtO8Fgg 188A== X-Gm-Message-State: ALKqPwe5VPM9UJ1g2cwsDO+HGPcuoJ2r4736wQQVQoy0QVAVF0t/3apG EA80pXlQpRtv2zCdReNR85EHERx1Cvc= X-Received: by 2002:adf:a512:: with SMTP id i18-v6mr4589875wrb.155.1525870861524; Wed, 09 May 2018 06:01:01 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.00.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:01:00 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 16/24] ASoC: qdsp6: q6asm: Add support to audio stream apis Date: Wed, 9 May 2018 13:56:27 +0100 Message-Id: <20180509125635.5653-17-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to open, write and media format commands in the q6asm module. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/qdsp6/q6asm.c | 834 ++++++++++++++++++++++++++++++++++++++++++- sound/soc/qcom/qdsp6/q6asm.h | 49 +++ 2 files changed, 882 insertions(+), 1 deletion(-) -- 2.16.2 diff --git a/sound/soc/qcom/qdsp6/q6asm.c b/sound/soc/qcom/qdsp6/q6asm.c index 044ad57d15a0..4d70b2267ce2 100644 --- a/sound/soc/qcom/qdsp6/q6asm.c +++ b/sound/soc/qcom/qdsp6/q6asm.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include #include @@ -18,10 +20,36 @@ #include "q6dsp-errno.h" #include "q6dsp-common.h" +#define ASM_STREAM_CMD_CLOSE 0x00010BCD +#define ASM_STREAM_CMD_FLUSH 0x00010BCE +#define ASM_SESSION_CMD_PAUSE 0x00010BD3 +#define ASM_DATA_CMD_EOS 0x00010BDB +#define ASM_NULL_POPP_TOPOLOGY 0x00010C68 +#define ASM_STREAM_CMD_FLUSH_READBUFS 0x00010C09 +#define ASM_STREAM_CMD_SET_ENCDEC_PARAM 0x00010C10 +#define ASM_STREAM_POSTPROC_TOPO_ID_NONE 0x00010C68 #define ASM_CMD_SHARED_MEM_MAP_REGIONS 0x00010D92 #define ASM_CMDRSP_SHARED_MEM_MAP_REGIONS 0x00010D93 #define ASM_CMD_SHARED_MEM_UNMAP_REGIONS 0x00010D94 - +#define ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2 0x00010D98 +#define ASM_DATA_EVENT_WRITE_DONE_V2 0x00010D99 +#define ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2 0x00010DA3 +#define ASM_SESSION_CMD_RUN_V2 0x00010DAA +#define ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2 0x00010DA5 +#define ASM_DATA_CMD_WRITE_V2 0x00010DAB +#define ASM_DATA_CMD_READ_V2 0x00010DAC +#define ASM_SESSION_CMD_SUSPEND 0x00010DEC +#define ASM_STREAM_CMD_OPEN_WRITE_V3 0x00010DB3 +#define ASM_STREAM_CMD_OPEN_READ_V3 0x00010DB4 +#define ASM_DATA_EVENT_READ_DONE_V2 0x00010D9A +#define ASM_STREAM_CMD_OPEN_READWRITE_V2 0x00010D8D + + +#define ASM_LEGACY_STREAM_SESSION 0 +/* Bit shift for the stream_perf_mode subfield. */ +#define ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ 29 +#define ASM_END_POINT_DEVICE_MATRIX 0 +#define ASM_DEFAULT_APP_TYPE 0 #define ASM_SYNC_IO_MODE 0x0001 #define ASM_ASYNC_IO_MODE 0x0002 #define ASM_TUN_READ_IO_MODE 0x0004 /* tunnel read write mode */ @@ -45,6 +73,89 @@ struct avs_cmd_shared_mem_unmap_regions { u32 mem_map_handle; } __packed; +struct asm_data_cmd_media_fmt_update_v2 { + u32 fmt_blk_size; +} __packed; + +struct asm_multi_channel_pcm_fmt_blk_v2 { + struct asm_data_cmd_media_fmt_update_v2 fmt_blk; + u16 num_channels; + u16 bits_per_sample; + u32 sample_rate; + u16 is_signed; + u16 reserved; + u8 channel_mapping[PCM_MAX_NUM_CHANNEL]; +} __packed; + +struct asm_stream_cmd_set_encdec_param { + u32 param_id; + u32 param_size; +} __packed; + +struct asm_enc_cfg_blk_param_v2 { + u32 frames_per_buf; + u32 enc_cfg_blk_size; +} __packed; + +struct asm_multi_channel_pcm_enc_cfg_v2 { + struct asm_stream_cmd_set_encdec_param encdec; + struct asm_enc_cfg_blk_param_v2 encblk; + uint16_t num_channels; + uint16_t bits_per_sample; + uint32_t sample_rate; + uint16_t is_signed; + uint16_t reserved; + uint8_t channel_mapping[8]; +} __packed; + +struct asm_data_cmd_read_v2 { + u32 buf_addr_lsw; + u32 buf_addr_msw; + u32 mem_map_handle; + u32 buf_size; + u32 seq_id; +} __packed; + +struct asm_data_cmd_read_v2_done { + u32 status; + u32 buf_addr_lsw; + u32 buf_addr_msw; +}; + +struct asm_stream_cmd_open_read_v3 { + u32 mode_flags; + u32 src_endpointype; + u32 preprocopo_id; + u32 enc_cfg_id; + u16 bits_per_sample; + u16 reserved; +} __packed; + +struct asm_data_cmd_write_v2 { + u32 buf_addr_lsw; + u32 buf_addr_msw; + u32 mem_map_handle; + u32 buf_size; + u32 seq_id; + u32 timestamp_lsw; + u32 timestamp_msw; + u32 flags; +} __packed; + +struct asm_stream_cmd_open_write_v3 { + uint32_t mode_flags; + uint16_t sink_endpointype; + uint16_t bits_per_sample; + uint32_t postprocopo_id; + uint32_t dec_fmt_id; +} __packed; + +struct asm_session_cmd_run_v2 { + u32 flags; + u32 time_lsw; + u32 time_msw; +} __packed; + struct audio_buffer { phys_addr_t phys; uint32_t used; @@ -85,6 +196,22 @@ struct q6asm { struct platform_device *pdev_dais; }; +static bool q6asm_is_valid_audio_client(struct audio_client *ac) +{ + struct q6asm *a = dev_get_drvdata(ac->dev->parent); + int n; + + if (!ac) + return false; + + for (n = 1; n <= MAX_SESSIONS; n++) { + if (a->session[n] == ac) + return true; + } + + return false; +} + static inline void q6asm_add_hdr(struct audio_client *ac, struct apr_hdr *hdr, uint32_t pkt_size, bool cmd_flg, uint32_t stream_id) @@ -388,6 +515,150 @@ static struct audio_client *q6asm_get_audio_client(struct q6asm *a, return a->session[session_id]; } +static int32_t q6asm_stream_callback(struct apr_device *adev, + struct apr_resp_pkt *data, + int session_id) +{ + struct q6asm *q6asm = dev_get_drvdata(&adev->dev); + struct aprv2_ibasic_rsp_result_t *result; + struct apr_hdr *hdr = &data->hdr; + struct audio_port_data *port; + struct audio_client *ac; + uint32_t token; + uint32_t client_event = 0; + + ac = q6asm_get_audio_client(q6asm, session_id); + if (!ac)/* Audio client might already be freed by now */ + return 0; + + if (!q6asm_is_valid_audio_client(ac)) + return -EINVAL; + + result = data->payload; + + switch (hdr->opcode) { + case APR_BASIC_RSP_RESULT: + token = hdr->token; + switch (result->opcode) { + case ASM_SESSION_CMD_PAUSE: + client_event = ASM_CLIENT_EVENT_CMD_PAUSE_DONE; + break; + case ASM_SESSION_CMD_SUSPEND: + client_event = ASM_CLIENT_EVENT_CMD_SUSPEND_DONE; + break; + case ASM_DATA_CMD_EOS: + client_event = ASM_CLIENT_EVENT_CMD_EOS_DONE; + break; + case ASM_STREAM_CMD_FLUSH: + client_event = ASM_CLIENT_EVENT_CMD_FLUSH_DONE; + break; + case ASM_SESSION_CMD_RUN_V2: + client_event = ASM_CLIENT_EVENT_CMD_RUN_DONE; + break; + case ASM_STREAM_CMD_CLOSE: + client_event = ASM_CLIENT_EVENT_CMD_CLOSE_DONE; + break; + case ASM_STREAM_CMD_FLUSH_READBUFS: + client_event = ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE; + break; + case ASM_STREAM_CMD_OPEN_WRITE_V3: + case ASM_STREAM_CMD_OPEN_READ_V3: + case ASM_STREAM_CMD_OPEN_READWRITE_V2: + case ASM_STREAM_CMD_SET_ENCDEC_PARAM: + case ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2: + if (result->status != 0) { + dev_err(ac->dev, + "cmd = 0x%x returned error = 0x%x\n", + result->opcode, result->status); + ac->result = *result; + wake_up(&ac->cmd_wait); + return 0; + } + break; + default: + dev_err(ac->dev, "command[0x%x] not expecting rsp\n", + result->opcode); + break; + } + + ac->result = *result; + wake_up(&ac->cmd_wait); + + if (ac->cb) + ac->cb(client_event, hdr->token, + data->payload, ac->priv); + + return 0; + + case ASM_DATA_EVENT_WRITE_DONE_V2: + port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; + + client_event = ASM_CLIENT_EVENT_DATA_WRITE_DONE; + + if (ac->io_mode & ASM_SYNC_IO_MODE) { + phys_addr_t phys; + unsigned long flags; + + spin_lock_irqsave(&ac->buf_lock, flags); + if (!port->buf) { + spin_unlock_irqrestore(&ac->buf_lock, flags); + return 0; + } + + phys = port->buf[hdr->token].phys; + + if (lower_32_bits(phys) != result->opcode || + upper_32_bits(phys) != result->status) { + dev_err(ac->dev, "Expected addr %pa\n", + &port->buf[hdr->token].phys); + spin_unlock_irqrestore(&ac->buf_lock, flags); + return -EINVAL; + } + token = hdr->token; + port->buf[token].used = 1; + spin_unlock_irqrestore(&ac->buf_lock, flags); + } + break; + case ASM_DATA_EVENT_READ_DONE_V2: + port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; + client_event = ASM_CLIENT_EVENT_DATA_READ_DONE; + + if (ac->io_mode & ASM_SYNC_IO_MODE) { + struct asm_data_cmd_read_v2_done *done = data->payload; + unsigned long flags; + phys_addr_t phys; + + spin_lock_irqsave(&ac->buf_lock, flags); + if (!port->buf) { + spin_unlock_irqrestore(&ac->buf_lock, flags); + return 0; + } + + phys = port->buf[hdr->token].phys; + token = hdr->token; + port->buf[token].used = 0; + + if (upper_32_bits(phys) != done->buf_addr_msw || + lower_32_bits(phys) != done->buf_addr_lsw) { + dev_err(ac->dev, "Expected addr %pa %08x-%08x\n", + &port->buf[hdr->token].phys, + done->buf_addr_lsw, + done->buf_addr_msw); + spin_unlock_irqrestore(&ac->buf_lock, flags); + return -EINVAL; + } + spin_unlock_irqrestore(&ac->buf_lock, flags); + } + + break; + } + + if (ac->cb) + ac->cb(client_event, hdr->token, data->payload, ac->priv); + + return 0; +} + static int q6asm_srvc_callback(struct apr_device *adev, struct apr_resp_pkt *data) { @@ -399,6 +670,11 @@ static int q6asm_srvc_callback(struct apr_device *adev, struct q6asm *a; uint32_t sid = 0; uint32_t dir = 0; + int session_id; + + session_id = (hdr->dest_port >> 8) & 0xFF; + if (session_id) + return q6asm_stream_callback(adev, data, session_id); sid = (hdr->token >> 8) & 0x0F; ac = q6asm_get_audio_client(q6asm, sid); @@ -508,6 +784,562 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, } EXPORT_SYMBOL_GPL(q6asm_audio_client_alloc); +static int q6asm_ac_send_cmd_sync(struct audio_client *ac, struct apr_pkt *pkt) +{ + struct apr_hdr *hdr = &pkt->hdr; + int rc; + + mutex_lock(&ac->lock); + ac->result.opcode = 0; + ac->result.status = 0; + + rc = apr_send_pkt(ac->adev, pkt); + if (rc < 0) + goto err; + + rc = wait_event_timeout(ac->cmd_wait, + (ac->result.opcode == hdr->opcode), 5 * HZ); + if (!rc) { + dev_err(ac->dev, "CMD timeout\n"); + rc = -ETIMEDOUT; + goto err; + } + + if (ac->result.status > 0) { + dev_err(ac->dev, "DSP returned error[%x]\n", + ac->result.status); + rc = -EINVAL; + } else { + rc = 0; + } + + +err: + mutex_unlock(&ac->lock); + return rc; +} + +/** + * q6asm_open_write() - Open audio client for writing + * + * @ac: audio client pointer + * @format: audio sample format + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_open_write(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + struct asm_stream_cmd_open_write_v3 *open; + struct apr_pkt *pkt; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*open); + + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + open = p + APR_HDR_SIZE; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_WRITE_V3; + open->mode_flags = 0x00; + open->mode_flags |= ASM_LEGACY_STREAM_SESSION; + + /* source endpoint : matrix */ + open->sink_endpointype = ASM_END_POINT_DEVICE_MATRIX; + open->bits_per_sample = bits_per_sample; + open->postprocopo_id = ASM_NULL_POPP_TOPOLOGY; + + switch (format) { + case FORMAT_LINEAR_PCM: + open->dec_fmt_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + default: + dev_err(ac->dev, "Invalid format 0x%x\n", format); + rc = -EINVAL; + goto err; + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + if (rc < 0) + goto err; + + ac->io_mode |= ASM_TUN_WRITE_IO_MODE; + +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_open_write); + +static int __q6asm_run(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts, bool wait) +{ + struct asm_session_cmd_run_v2 *run; + struct apr_pkt *pkt; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*run); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + run = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_SESSION_CMD_RUN_V2; + run->flags = flags; + run->time_lsw = lsw_ts; + run->time_msw = msw_ts; + if (wait) { + rc = q6asm_ac_send_cmd_sync(ac, pkt); + } else { + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + } + + kfree(pkt); + return rc; +} + +/** + * q6asm_run() - start the audio client + * + * @ac: audio client pointer + * @flags: flags associated with write + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_run(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts) +{ + return __q6asm_run(ac, flags, msw_ts, lsw_ts, true); +} +EXPORT_SYMBOL_GPL(q6asm_run); + +/** + * q6asm_run_nowait() - start the audio client withou blocking + * + * @ac: audio client pointer + * @flags: flags associated with write + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, + uint32_t msw_ts, uint32_t lsw_ts) +{ + return __q6asm_run(ac, flags, msw_ts, lsw_ts, false); +} +EXPORT_SYMBOL_GPL(q6asm_run_nowait); + +/** + * q6asm_media_format_block_multi_ch_pcm() - setup pcm configuration + * + * @ac: audio client pointer + * @rate: audio sample rate + * @channels: number of audio channels. + * @channel_map: channel map pointer + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample) +{ + struct asm_multi_channel_pcm_fmt_blk_v2 *fmt; + struct apr_pkt *pkt; + u8 *channel_mapping; + void *p; + int rc, pkt_size; + + pkt_size = APR_HDR_SIZE + sizeof(*fmt); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + fmt = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_DATA_CMD_MEDIA_FMT_UPDATE_V2; + fmt->fmt_blk.fmt_blk_size = sizeof(*fmt) - sizeof(fmt->fmt_blk); + fmt->num_channels = channels; + fmt->bits_per_sample = bits_per_sample; + fmt->sample_rate = rate; + fmt->is_signed = 1; + + channel_mapping = fmt->channel_mapping; + + if (channel_map) { + memcpy(channel_mapping, channel_map, PCM_MAX_NUM_CHANNEL); + } else { + if (q6dsp_map_channels(channel_mapping, channels)) { + dev_err(ac->dev, " map channels failed %d\n", channels); + rc = -EINVAL; + goto err; + } + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_media_format_block_multi_ch_pcm); + +/** + * q6asm_enc_cfg_blk_pcm_format_support() - setup pcm configuration for capture + * + * @ac: audio client pointer + * @rate: audio sample rate + * @channels: number of audio channels. + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, + uint32_t rate, uint32_t channels, uint16_t bits_per_sample) +{ + struct asm_multi_channel_pcm_enc_cfg_v2 *enc_cfg; + struct apr_pkt *pkt; + u8 *channel_mapping; + u32 frames_per_buf = 0; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*enc_cfg); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + enc_cfg = p + APR_HDR_SIZE; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + + pkt->hdr.opcode = ASM_STREAM_CMD_SET_ENCDEC_PARAM; + enc_cfg->encdec.param_id = ASM_PARAM_ID_ENCDEC_ENC_CFG_BLK_V2; + enc_cfg->encdec.param_size = sizeof(*enc_cfg) - sizeof(enc_cfg->encdec); + enc_cfg->encblk.frames_per_buf = frames_per_buf; + enc_cfg->encblk.enc_cfg_blk_size = enc_cfg->encdec.param_size - + sizeof(struct asm_enc_cfg_blk_param_v2); + + enc_cfg->num_channels = channels; + enc_cfg->bits_per_sample = bits_per_sample; + enc_cfg->sample_rate = rate; + enc_cfg->is_signed = 1; + channel_mapping = enc_cfg->channel_mapping; + + if (q6dsp_map_channels(channel_mapping, channels)) { + rc = -EINVAL; + goto err; + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); +err: + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_enc_cfg_blk_pcm_format_support); + +/** + * q6asm_read() - read data of period size from audio client + * + * @ac: audio client pointer + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_read(struct audio_client *ac) +{ + struct asm_data_cmd_read_v2 *read; + struct audio_port_data *port; + struct audio_buffer *ab; + struct apr_pkt *pkt; + int pkt_size; + int rc = 0; + void *p; + + if (!(ac->io_mode & ASM_SYNC_IO_MODE)) + return 0; + + pkt_size = APR_HDR_SIZE + sizeof(*read); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + read = p + APR_HDR_SIZE; + + port = &ac->port[SNDRV_PCM_STREAM_CAPTURE]; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + ab = &port->buf[port->dsp_buf]; + pkt->hdr.opcode = ASM_DATA_CMD_READ_V2; + read->buf_addr_lsw = lower_32_bits(ab->phys); + read->buf_addr_msw = upper_32_bits(ab->phys); + read->mem_map_handle = port->mem_map_handle; + + read->buf_size = ab->size; + read->seq_id = port->dsp_buf; + pkt->hdr.token = port->dsp_buf; + + port->dsp_buf++; + + if (port->dsp_buf >= port->num_periods) + port->dsp_buf = 0; + + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + else + pr_err("read op[0x%x]rc[%d]\n", pkt->hdr.opcode, rc); + + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_read); + +static int __q6asm_open_read(struct audio_client *ac, + uint32_t format, uint16_t bits_per_sample) +{ + struct asm_stream_cmd_open_read_v3 *open; + struct apr_pkt *pkt; + int pkt_size, rc; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*open); + p = kzalloc(pkt_size, GFP_KERNEL); + if (!p) + return -ENOMEM; + + pkt = p; + open = p + APR_HDR_SIZE; + + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, true, ac->stream_id); + pkt->hdr.opcode = ASM_STREAM_CMD_OPEN_READ_V3; + /* Stream prio : High, provide meta info with encoded frames */ + open->src_endpointype = ASM_END_POINT_DEVICE_MATRIX; + + open->preprocopo_id = ASM_STREAM_POSTPROC_TOPO_ID_NONE; + open->bits_per_sample = bits_per_sample; + open->mode_flags = 0x0; + + open->mode_flags |= ASM_LEGACY_STREAM_SESSION << + ASM_SHIFT_STREAM_PERF_MODE_FLAG_IN_OPEN_READ; + + switch (format) { + case FORMAT_LINEAR_PCM: + open->mode_flags |= 0x00; + open->enc_cfg_id = ASM_MEDIA_FMT_MULTI_CHANNEL_PCM_V2; + break; + default: + pr_err("Invalid format[%d]\n", format); + } + + rc = q6asm_ac_send_cmd_sync(ac, pkt); + + kfree(pkt); + return rc; +} + +/** + * q6asm_open_read() - Open audio client for reading + * + * @ac: audio client pointer + * @format: audio sample format + * @bits_per_sample: bits per sample + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_open_read(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample) +{ + return __q6asm_open_read(ac, format, bits_per_sample); +} +EXPORT_SYMBOL_GPL(q6asm_open_read); + +/** + * q6asm_write_async() - non blocking write + * + * @ac: audio client pointer + * @len: lenght in bytes + * @msw_ts: timestamp msw + * @lsw_ts: timestamp lsw + * @flags: flags associated with write + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, + uint32_t lsw_ts, uint32_t flags) +{ + struct asm_data_cmd_write_v2 *write; + struct audio_port_data *port; + struct audio_buffer *ab; + struct apr_pkt *pkt; + int pkt_size; + int rc = 0; + void *p; + + pkt_size = APR_HDR_SIZE + sizeof(*write); + p = kzalloc(pkt_size, GFP_ATOMIC); + if (!p) + return -ENOMEM; + + pkt = p; + write = p + APR_HDR_SIZE; + + if (!(ac->io_mode & ASM_SYNC_IO_MODE)) + return 0; + + port = &ac->port[SNDRV_PCM_STREAM_PLAYBACK]; + q6asm_add_hdr(ac, &pkt->hdr, pkt_size, false, ac->stream_id); + + ab = &port->buf[port->dsp_buf]; + + pkt->hdr.token = port->dsp_buf; + pkt->hdr.opcode = ASM_DATA_CMD_WRITE_V2; + write->buf_addr_lsw = lower_32_bits(ab->phys); + write->buf_addr_msw = upper_32_bits(ab->phys); + write->buf_size = len; + write->seq_id = port->dsp_buf; + write->timestamp_lsw = lsw_ts; + write->timestamp_msw = msw_ts; + write->mem_map_handle = + ac->port[SNDRV_PCM_STREAM_PLAYBACK].mem_map_handle; + + if (flags == NO_TIMESTAMP) + write->flags = (flags & 0x800000FF); + else + write->flags = (0x80000000 | flags); + + port->dsp_buf++; + + if (port->dsp_buf >= port->num_periods) + port->dsp_buf = 0; + + rc = apr_send_pkt(ac->adev, pkt); + if (rc == pkt_size) + rc = 0; + + kfree(pkt); + return rc; +} +EXPORT_SYMBOL_GPL(q6asm_write_async); + +static void q6asm_reset_buf_state(struct audio_client *ac) +{ + struct audio_port_data *port = NULL; + unsigned long flags; + int loopcnt = 0; + int cnt = 0; + int used; + + if (!(ac->io_mode & ASM_SYNC_IO_MODE)) + return; + + used = (ac->io_mode & ASM_TUN_WRITE_IO_MODE ? 1 : 0); + spin_lock_irqsave(&ac->buf_lock, flags); + for (loopcnt = 0; loopcnt <= SNDRV_PCM_STREAM_CAPTURE; loopcnt++) { + port = &ac->port[loopcnt]; + cnt = port->num_periods - 1; + port->dsp_buf = 0; + while (cnt >= 0) { + if (!port->buf) + continue; + port->buf[cnt].used = used; + cnt--; + } + } + spin_unlock_irqrestore(&ac->buf_lock, flags); +} + +static int __q6asm_cmd(struct audio_client *ac, int cmd, bool wait) +{ + int stream_id = ac->stream_id; + struct apr_pkt pkt; + int rc; + + q6asm_add_hdr(ac, &pkt.hdr, APR_HDR_SIZE, true, stream_id); + + switch (cmd) { + case CMD_PAUSE: + pkt.hdr.opcode = ASM_SESSION_CMD_PAUSE; + break; + case CMD_SUSPEND: + pkt.hdr.opcode = ASM_SESSION_CMD_SUSPEND; + break; + case CMD_FLUSH: + pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH; + break; + case CMD_OUT_FLUSH: + pkt.hdr.opcode = ASM_STREAM_CMD_FLUSH_READBUFS; + break; + case CMD_EOS: + pkt.hdr.opcode = ASM_DATA_CMD_EOS; + break; + case CMD_CLOSE: + pkt.hdr.opcode = ASM_STREAM_CMD_CLOSE; + break; + default: + return -EINVAL; + } + + if (wait) + rc = q6asm_ac_send_cmd_sync(ac, &pkt); + else + return apr_send_pkt(ac->adev, &pkt); + + if (rc < 0) + return rc; + + if (cmd == CMD_FLUSH) + q6asm_reset_buf_state(ac); + + return 0; +} + +/** + * q6asm_cmd() - run cmd on audio client + * + * @ac: audio client pointer + * @cmd: command to run on audio client. + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_cmd(struct audio_client *ac, int cmd) +{ + return __q6asm_cmd(ac, cmd, true); +} +EXPORT_SYMBOL_GPL(q6asm_cmd); + +/** + * q6asm_cmd_nowait() - non blocking, run cmd on audio client + * + * @ac: audio client pointer + * @cmd: command to run on audio client. + * + * Return: Will be an negative value on error or zero on success + */ +int q6asm_cmd_nowait(struct audio_client *ac, int cmd) +{ + return __q6asm_cmd(ac, cmd, false); +} +EXPORT_SYMBOL_GPL(q6asm_cmd_nowait); static int q6asm_probe(struct apr_device *adev) { diff --git a/sound/soc/qcom/qdsp6/q6asm.h b/sound/soc/qcom/qdsp6/q6asm.h index 8c317b7b63c3..9f5fb573e4a0 100644 --- a/sound/soc/qcom/qdsp6/q6asm.h +++ b/sound/soc/qcom/qdsp6/q6asm.h @@ -1,8 +1,36 @@ /* SPDX-License-Identifier: GPL-2.0 */ #ifndef __Q6_ASM_H__ #define __Q6_ASM_H__ +#include "q6dsp-common.h" +#include + +/* ASM client callback events */ +#define CMD_PAUSE 0x0001 +#define ASM_CLIENT_EVENT_CMD_PAUSE_DONE 0x1001 +#define CMD_FLUSH 0x0002 +#define ASM_CLIENT_EVENT_CMD_FLUSH_DONE 0x1002 +#define CMD_EOS 0x0003 +#define ASM_CLIENT_EVENT_CMD_EOS_DONE 0x1003 +#define CMD_CLOSE 0x0004 +#define ASM_CLIENT_EVENT_CMD_CLOSE_DONE 0x1004 +#define CMD_OUT_FLUSH 0x0005 +#define ASM_CLIENT_EVENT_CMD_OUT_FLUSH_DONE 0x1005 +#define CMD_SUSPEND 0x0006 +#define ASM_CLIENT_EVENT_CMD_SUSPEND_DONE 0x1006 +#define ASM_CLIENT_EVENT_CMD_RUN_DONE 0x1008 +#define ASM_CLIENT_EVENT_DATA_WRITE_DONE 0x1009 +#define ASM_CLIENT_EVENT_DATA_READ_DONE 0x100a + +enum { + LEGACY_PCM_MODE = 0, + LOW_LATENCY_PCM_MODE, + ULTRA_LOW_LATENCY_PCM_MODE, + ULL_POST_PROCESSING_PCM_MODE, +}; #define MAX_SESSIONS 8 +#define NO_TIMESTAMP 0xFF00 +#define FORMAT_LINEAR_PCM 0x0000 typedef void (*q6asm_cb) (uint32_t opcode, uint32_t token, void *payload, void *priv); @@ -11,6 +39,27 @@ struct audio_client *q6asm_audio_client_alloc(struct device *dev, q6asm_cb cb, void *priv, int session_id, int perf_mode); void q6asm_audio_client_free(struct audio_client *ac); +int q6asm_write_async(struct audio_client *ac, uint32_t len, uint32_t msw_ts, + uint32_t lsw_ts, uint32_t flags); +int q6asm_open_write(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); + +int q6asm_open_read(struct audio_client *ac, uint32_t format, + uint16_t bits_per_sample); +int q6asm_enc_cfg_blk_pcm_format_support(struct audio_client *ac, + uint32_t rate, uint32_t channels, uint16_t bits_per_sample); +int q6asm_read(struct audio_client *ac); + +int q6asm_media_format_block_multi_ch_pcm(struct audio_client *ac, + uint32_t rate, uint32_t channels, + u8 channel_map[PCM_MAX_NUM_CHANNEL], + uint16_t bits_per_sample); +int q6asm_run(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, + uint32_t lsw_ts); +int q6asm_run_nowait(struct audio_client *ac, uint32_t flags, uint32_t msw_ts, + uint32_t lsw_ts); +int q6asm_cmd(struct audio_client *ac, int cmd); +int q6asm_cmd_nowait(struct audio_client *ac, int cmd); int q6asm_get_session_id(struct audio_client *ac); int q6asm_map_memory_regions(unsigned int dir, struct audio_client *ac, From patchwork Wed May 9 12:56:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135273 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5613643lji; Wed, 9 May 2018 06:03:28 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqwjRoXRWEHYN1n7om9ifTjyh4Bja5rgLkmPAknIL9GjLM1oKGNkj0BTNTaf4oBhUuzx249 X-Received: by 2002:a17:902:2924:: with SMTP id g33-v6mr45911241plb.26.1525871008699; Wed, 09 May 2018 06:03:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525871008; cv=none; d=google.com; s=arc-20160816; b=AqtQL1Chf+bJB9cCxj3eqcB/7LDwJNZsleRvfwtFjL6EM1a2x0zBLQzV/M0bJHrI/o W2rvQHuR+6YhYQRRy1XyeRaMirxjQBsWiRulLWDqPIQ+bNooZMARjojTJKPXYxa+pu/9 0BVWYka3zB7oIJ6LK4OPyh5QhJMDA2ySYqe0lnBCarp6tpCp5+Xs7zLUflrAPWkSOK1W I4D3mVz34uppPTLR3sOlyLts//40RuAahCDGPZ/BrnnyM24kNpJ9dd5erTL6ArFd2mIK CoewJJevt+MZF0SkSbDNCXr2PrK+8TqQUAjZaTUKrfefxwEemJH/OpwAIfznJxByhnRA j9zg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=wfEIW5AIMBO8SFKDTYxtILtgWdRSASEPNOwZFU2ZK0M=; b=Dd+1dktdJgLMURWWXYT4En+Lf6EPYOA30oLYiXtkf9rPN69N/Jd+y7FpRB8PXsKtnS yFCFRLpIZHlLXidPe7yDOVfXlmde20w5kF6rfDAHne+VbXHS/eudcvb9PsPRU7Nd6Gox +AnanFu403UsTLP+8Euv6nyaepr+iFdcZt8DRu5Fowo7WAlcbKeObD2w25pE7pnigrtx Fn/98bGOkw5oFNFXst+HBErE7emKzOw5fCxVVbgMTqMvGP2Mb/uNULOZGn6SyYah/9Aj fz4ZwGTuGi9OaFZLd6/OtLL/wGsGOL6OIz57MEE8NPnHoTJN9MDlfn/GulveLlStmBYm HcpQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WX3RX3Qx; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id i14-v6si21173948pgc.250.2018.05.09.06.03.28; Wed, 09 May 2018 06:03:28 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=WX3RX3Qx; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935241AbeEINDZ (ORCPT + 29 others); Wed, 9 May 2018 09:03:25 -0400 Received: from mail-wm0-f68.google.com ([74.125.82.68]:37928 "EHLO mail-wm0-f68.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935137AbeEINBF (ORCPT ); Wed, 9 May 2018 09:01:05 -0400 Received: by mail-wm0-f68.google.com with SMTP id y189-v6so9464972wmc.3 for ; Wed, 09 May 2018 06:01:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=wfEIW5AIMBO8SFKDTYxtILtgWdRSASEPNOwZFU2ZK0M=; b=WX3RX3Qx3ScCJn7zHGnxor5lLlwAfq6UQ7STtFQYPMqARCJVUqYGtWgp88SMzw+Uwm 95gxFr0sJQo4aWqHgVSeAcEdgoETtxkeDZ9Dzq622je4lULRDskSPRNZynWgV4w80Ofu CBpyhOx3/W6kBIUHaEDLtbVGQJGQ2HELMciv0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=wfEIW5AIMBO8SFKDTYxtILtgWdRSASEPNOwZFU2ZK0M=; b=P7uatz9mxWc50T3y61aYzPHt+VAApB6vxulHBkBj95J89lw1E+LyQgZzcDeR9W4FPk beod9mGG5jzOiWOStwzdwp+Bm2If/kA6Dnet89kO9B10oqQAl8A1y496u3uj1aKqvS8v NJwXjl3sTZzl2KKoRYPAkXN2fSxvVtHcKcTa4+2+0dyFmg2cmvvPFq0kUIMBsbVnd1H2 +fn28EHfodfx/TzaZNukoyKLxVccQWGPy2X+SliLp4O0k/XKDGY0OQy9xJE14KgknsAp 0fjyWdc9/WxNAwWSnYYk+VzOdokhOopxLjvVCY1mbPryMAxzCUWYS8RJbPE+ArxXOUyl XA6Q== X-Gm-Message-State: ALKqPweiBY5LssAJLFdgbeK/VSNwFbVIJXlL/ir0BIJOTjTlcRcZgDmv ev234a65hiQ6ZW4pLtlleX9wqw== X-Received: by 2002:a1c:eed9:: with SMTP id j86-v6mr5412828wmi.97.1525870863832; Wed, 09 May 2018 06:01:03 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.01.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:01:02 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 17/24] ASoC: qdsp6: q6routing: Add q6routing driver Date: Wed, 9 May 2018 13:56:28 +0100 Message-Id: <20180509125635.5653-18-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to q6 routing driver which configures route between ASM and AFE module using ADM apis. This driver uses dapm widgets to setup the matrix between AFE ports and ASM streams. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6routing.c | 392 +++++++++++++++++++++++++++++++++++++++ sound/soc/qcom/qdsp6/q6routing.h | 9 + 4 files changed, 406 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6routing.c create mode 100644 sound/soc/qcom/qdsp6/q6routing.h -- 2.16.2 diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 941774abd94f..43f9ed85efa8 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -53,6 +53,9 @@ config SND_SOC_QDSP6_AFE config SND_SOC_QDSP6_ADM tristate +config SND_SOC_QDSP6_ROUTING + tristate + config SND_SOC_QDSP6_ASM tristate @@ -63,6 +66,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE select SND_SOC_QDSP6_ADM + select SND_SOC_QDSP6_ROUTING select SND_SOC_QDSP6_ASM help To add support for MSM QDSP6 Soc Audio. diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 01d9dcf3375c..0e8e2febb7ec 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -2,4 +2,5 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o +obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6routing.c b/sound/soc/qcom/qdsp6/q6routing.c new file mode 100644 index 000000000000..f7ee9a1a29b2 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6routing.c @@ -0,0 +1,392 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" +#include "q6asm.h" +#include "q6adm.h" +#include "q6routing.h" + +#define DRV_NAME "q6routing-component" + +struct session_data { + int state; + int port_id; + int path_type; + int app_type; + int acdb_id; + int sample_rate; + int bits_per_sample; + int channels; + int perf_mode; + int numcopps; + int fedai_id; + unsigned long copp_map; +}; + +struct msm_routing_data { + struct session_data sessions[MAX_SESSIONS]; + struct session_data port_data[AFE_MAX_PORTS]; + struct device *dev; + struct mutex lock; +}; + +static struct msm_routing_data *routing_data; + +/** + * q6routing_stream_open() - Register a new stream for route setup + * + * @fedai_id: Frontend dai id. + * @perf_mode: Performance mode. + * @stream_id: ASM stream id to map. + * @stream_type: Direction of stream + * + * Return: Will be an negative on error or a zero on success. + */ +int q6routing_stream_open(int fedai_id, int perf_mode, + int stream_id, int stream_type) +{ + int j, topology, num_copps = 0; + struct route_payload payload; + int copp_idx; + struct session_data *session, *pdata; + + if (!routing_data) { + pr_err("Routing driver not yet ready\n"); + return -EINVAL; + } + + session = &routing_data->sessions[stream_id - 1]; + pdata = &routing_data->port_data[session->port_id]; + + mutex_lock(&routing_data->lock); + session->fedai_id = fedai_id; + + session->path_type = pdata->path_type; + session->sample_rate = pdata->sample_rate; + session->channels = pdata->channels; + session->bits_per_sample = pdata->bits_per_sample; + + payload.num_copps = 0; /* only RX needs to use payload */ + topology = NULL_COPP_TOPOLOGY; + copp_idx = q6adm_open(routing_data->dev, session->port_id, + session->path_type, session->sample_rate, + session->channels, topology, perf_mode, + session->bits_per_sample, 0, 0); + + if (copp_idx < 0) { + mutex_unlock(&routing_data->lock); + return -EINVAL; + } + + set_bit(copp_idx, &session->copp_map); + + for_each_set_bit(j, &session->copp_map, MAX_COPPS_PER_PORT) { + payload.port_id[num_copps] = session->port_id; + payload.copp_idx[num_copps] = j; + num_copps++; + } + + if (num_copps) { + payload.num_copps = num_copps; + payload.session_id = stream_id; + q6adm_matrix_map(routing_data->dev, session->path_type, + payload, perf_mode); + } + mutex_unlock(&routing_data->lock); + + return 0; +} +EXPORT_SYMBOL_GPL(q6routing_stream_open); + +static struct session_data *get_session_from_id(struct msm_routing_data *data, + int fedai_id) +{ + int i; + + for (i = 0; i < MAX_SESSIONS; i++) { + if (fedai_id == data->sessions[i].fedai_id) + return &data->sessions[i]; + } + + return NULL; +} +/** + * q6routing_stream_close() - Deregister a stream + * + * @fedai_id: Frontend dai id. + * @stream_type: Direction of stream + * + * Return: Will be an negative on error or a zero on success. + */ +void q6routing_stream_close(int fedai_id, int stream_type) +{ + struct session_data *session; + int idx; + + session = get_session_from_id(routing_data, fedai_id); + if (!session) + return; + + for_each_set_bit(idx, &session->copp_map, MAX_COPPS_PER_PORT) + q6adm_close(routing_data->dev, session->port_id, idx); + + session->fedai_id = -1; + session->copp_map = 0; +} +EXPORT_SYMBOL_GPL(q6routing_stream_close); + +static int msm_routing_get_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + int session_id = mc->shift; + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct msm_routing_data *priv = dev_get_drvdata(c->dev); + struct session_data *session = &priv->sessions[session_id]; + + if (session->port_id == mc->reg) + ucontrol->value.integer.value[0] = 1; + else + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +static int msm_routing_put_audio_mixer(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = + snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_component *c = snd_soc_dapm_to_component(dapm); + struct msm_routing_data *data = dev_get_drvdata(c->dev); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct snd_soc_dapm_update *update = NULL; + int be_id = mc->reg; + int session_id = mc->shift; + struct session_data *session = &data->sessions[session_id]; + + if (ucontrol->value.integer.value[0]) { + session->port_id = be_id; + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 1, update); + } else { + session->port_id = -1; + snd_soc_dapm_mixer_update_power(dapm, kcontrol, 0, update); + } + + return 1; +} + +static const struct snd_kcontrol_new hdmi_mixer_controls[] = { + SOC_SINGLE_EXT("MultiMedia1", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA1, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia2", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA2, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia3", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA3, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia4", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA4, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia5", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA5, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia6", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA6, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia7", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA7, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), + SOC_SINGLE_EXT("MultiMedia8", HDMI_RX, + MSM_FRONTEND_DAI_MULTIMEDIA8, 1, 0, + msm_routing_get_audio_mixer, + msm_routing_put_audio_mixer), +}; + +static const struct snd_soc_dapm_widget msm_qdsp6_widgets[] = { + /* Frontend AIF */ + SND_SOC_DAPM_AIF_IN("MM_DL1", "MultiMedia1 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL2", "MultiMedia2 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL3", "MultiMedia3 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL4", "MultiMedia4 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL5", "MultiMedia5 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL6", "MultiMedia6 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL7", "MultiMedia7 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("MM_DL8", "MultiMedia8 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL1", "MultiMedia1 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL2", "MultiMedia2 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL3", "MultiMedia3 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL4", "MultiMedia4 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL5", "MultiMedia5 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL6", "MultiMedia6 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL7", "MultiMedia7 Capture", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("MM_UL8", "MultiMedia8 Capture", 0, 0, 0, 0), + + /* Mixer definitions */ + SND_SOC_DAPM_MIXER("HDMI Mixer", SND_SOC_NOPM, 0, 0, + hdmi_mixer_controls, + ARRAY_SIZE(hdmi_mixer_controls)), +}; + +static const struct snd_soc_dapm_route intercon[] = { + {"HDMI Mixer", "MultiMedia1", "MM_DL1"}, + {"HDMI Mixer", "MultiMedia2", "MM_DL2"}, + {"HDMI Mixer", "MultiMedia3", "MM_DL3"}, + {"HDMI Mixer", "MultiMedia4", "MM_DL4"}, + {"HDMI Mixer", "MultiMedia5", "MM_DL5"}, + {"HDMI Mixer", "MultiMedia6", "MM_DL6"}, + {"HDMI Mixer", "MultiMedia7", "MM_DL7"}, + {"HDMI Mixer", "MultiMedia8", "MM_DL8"}, + {"HDMI_RX", NULL, "HDMI Mixer"}, +}; + +static int routing_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params) +{ + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_component *c = snd_soc_rtdcom_lookup(rtd, DRV_NAME); + struct msm_routing_data *data = dev_get_drvdata(c->dev); + unsigned int be_id = rtd->cpu_dai->id; + struct session_data *session; + int path_type; + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) + path_type = ADM_PATH_PLAYBACK; + else + path_type = ADM_PATH_LIVE_REC; + + if (be_id > AFE_MAX_PORTS) + return -EINVAL; + + session = &data->port_data[be_id]; + + mutex_lock(&data->lock); + + session->path_type = path_type; + session->sample_rate = params_rate(params); + session->channels = params_channels(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + session->bits_per_sample = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + session->bits_per_sample = 24; + break; + default: + break; + } + + mutex_unlock(&data->lock); + return 0; +} + +static struct snd_pcm_ops q6pcm_routing_ops = { + .hw_params = routing_hw_params, +}; + +static int msm_routing_probe(struct snd_soc_component *c) +{ + int i; + + for (i = 0; i < MAX_SESSIONS; i++) + routing_data->sessions[i].port_id = -1; + + return 0; +} + +static const struct snd_soc_component_driver msm_soc_routing_component = { + .ops = &q6pcm_routing_ops, + .probe = msm_routing_probe, + .name = DRV_NAME, + .dapm_widgets = msm_qdsp6_widgets, + .num_dapm_widgets = ARRAY_SIZE(msm_qdsp6_widgets), + .dapm_routes = intercon, + .num_dapm_routes = ARRAY_SIZE(intercon), +}; + +static int q6routing_dai_bind(struct device *dev, struct device *master, + void *data) +{ + routing_data = kzalloc(sizeof(*routing_data), GFP_KERNEL); + if (!routing_data) + return -ENOMEM; + + routing_data->dev = dev; + + mutex_init(&routing_data->lock); + dev_set_drvdata(dev, routing_data); + + return snd_soc_register_component(dev, &msm_soc_routing_component, + NULL, 0); +} + +static void q6routing_dai_unbind(struct device *dev, struct device *master, + void *d) +{ + struct msm_routing_data *data = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + + kfree(data); + + routing_data = NULL; +} + +static const struct component_ops q6routing_dai_comp_ops = { + .bind = q6routing_dai_bind, + .unbind = q6routing_dai_unbind, +}; + +static int q6pcm_routing_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &q6routing_dai_comp_ops); +} + +static int q6pcm_routing_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &q6routing_dai_comp_ops); + return 0; +} + +static struct platform_driver q6pcm_routing_platform_driver = { + .driver = { + .name = "q6routing", + }, + .probe = q6pcm_routing_probe, + .remove = q6pcm_routing_remove, +}; +module_platform_driver(q6pcm_routing_platform_driver); + +MODULE_DESCRIPTION("Q6 Routing platform"); +MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/qcom/qdsp6/q6routing.h b/sound/soc/qcom/qdsp6/q6routing.h new file mode 100644 index 000000000000..35514e651130 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6routing.h @@ -0,0 +1,9 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _Q6_PCM_ROUTING_H +#define _Q6_PCM_ROUTING_H + +int q6routing_stream_open(int fedai_id, int perf_mode, + int stream_id, int stream_type); +void q6routing_stream_close(int fedai_id, int stream_type); + +#endif /*_Q6_PCM_ROUTING_H */ From patchwork Wed May 9 12:56:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135266 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5610166lji; Wed, 9 May 2018 06:01:20 -0700 (PDT) X-Google-Smtp-Source: AB8JxZqKvpfdUEGaEcEEKqO7RFKKPS4UzIjE8IXpCpxqxmpRhB41QENfa2Uf7QhNv1bgzYiTmv95 X-Received: by 2002:a17:902:ea:: with SMTP id a97-v6mr44224259pla.28.1525870879886; Wed, 09 May 2018 06:01:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525870879; cv=none; d=google.com; s=arc-20160816; b=mEP7ZT6OtjJ1bfcHVQmqrfy0TjklJUV7GaqiSKK5Si4L2GfTTizTwZpEuZ7va5YQYk USDAu9EsLQQ1g4OR83midCzo2erdWqJFRwakY6EPJKje2EG+n8MwxLST2SNOeHqmwa9u 1azQ5NA8/Am7lOnZx3jE2z90bmjkbNCXjqA25EuXKcv9o83kaSxmvXAaFiEpoS0uOBBF s6qRsoyLqj0nij6BZ4eYjvWjCMgrj12ZO9z767xwH06rdoTT0gDZ8/mkCNPeZFrUvrB+ eHxpUQpazYjjyYV2SbZiZ4YZrBea+VSpPviFyPMO48+Ztkt+kjiwiKj8m+jW5ijIXMLF fTrQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=vaeK0HJl+LQjUfLeS9E7yzyYFeAp0VOtwlbSbMro3yI=; b=0+MoYBPaHXgFRSPQ0XDRYRu1DwTqJ6s36Yjx35ejef71eB0D3hELU9PG89OeO4w9Vf XCOoXXrHu/lNZmFTZLOdJ+wkSUlmrLsaukmXOZkKjqcBEJ5E9bIRXvySMyNw5KcxPUJv 9IdrhpeMFnPnXlPIpdQEDPCbXdWeh/ZoWN+3FEjQHYqgnjeWzjcRbP7RsuGVMFP4CaAj tT9KM0L1kmSUedQ1pQD/g0igAq3VjPkuLwk5R2k3C1S60A51Uh5xvxXhHttH9RX12ca1 Y2j3bUXM0IXLxj63QEeHTJnTKHet9+mlTadG6WVHc1NvAS8LKJaYbLbkYAYy4qxDCB+L xp5A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=OJno6KtN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id s5-v6si3057920pgo.12.2018.05.09.06.01.19; Wed, 09 May 2018 06:01:19 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=OJno6KtN; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935182AbeEINBQ (ORCPT + 29 others); Wed, 9 May 2018 09:01:16 -0400 Received: from mail-wr0-f195.google.com ([209.85.128.195]:46730 "EHLO mail-wr0-f195.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935136AbeEINBK (ORCPT ); Wed, 9 May 2018 09:01:10 -0400 Received: by mail-wr0-f195.google.com with SMTP id a12-v6so4679510wrn.13 for ; Wed, 09 May 2018 06:01:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linaro.org; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=vaeK0HJl+LQjUfLeS9E7yzyYFeAp0VOtwlbSbMro3yI=; b=OJno6KtNOzG02aU+WZv1ME3uKkjqxOU38gb69kDfwcwp8Ypv+uhLK/BvSzngHbmGrS MaKE2J7mt2zh1hTM3iOOd2/nTStn8XCpNTAM6xvQcdEGcSrcWGc5HfssPbdA5dK7Zcdl EpG6ROjizvKvjv8Cxxl17DZayGkIp+1cAJGiE= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=vaeK0HJl+LQjUfLeS9E7yzyYFeAp0VOtwlbSbMro3yI=; b=fE+NH6XJHToQeCfYUBiI7oz1lalPjr2qxD/RqqDoAVy8N+wnR82c94z6+zIr6/nZUb PCIQn5+jQoOScadTUPlkzywqH87l9SOwm1K8tKOAaXKEuRIqsyG80GPcP74bTgR3jVzV vIfLFzwurw3OAVu27jVxQN3QEdbG1REP5h//xhE9wZ4jPOgO1Vw6jO3/2LNAM4ygSxNQ EyxVAeCYsge+/9DIo2+nSUJ0rwu+239+Ht+LaVsM1XPOCo4RagqSOVVkBn80+/haqylD BzpohjYG1z7cUtXgpQ1TDT4HTtxiK2OK60zqnL3n+vcULeqd18p2ka1h1hn8W3WI7hCJ ug+Q== X-Gm-Message-State: ALKqPwdLxdivIii6KwG4wCAMPN7cbOBsWkdaqzMe2A+mX1E1JunfO9+A glDS+fyL4XInmvDZxOJFlBMsnQ== X-Received: by 2002:adf:ae02:: with SMTP id x2-v6mr4878346wrc.201.1525870868829; Wed, 09 May 2018 06:01:08 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.01.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:01:08 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 20/24] ASoC: qdsp6: q6afe: Add q6afe dai driver Date: Wed, 9 May 2018 13:56:31 +0100 Message-Id: <20180509125635.5653-21-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org This patch adds support to q6afe backend dais driver. Signed-off-by: Srinivas Kandagatla Reviewed-and-tested-by: Rohit kumar Reviewed-by: Banajit Goswami --- sound/soc/qcom/Kconfig | 4 + sound/soc/qcom/qdsp6/Makefile | 1 + sound/soc/qcom/qdsp6/q6afe-dai.c | 748 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 753 insertions(+) create mode 100644 sound/soc/qcom/qdsp6/q6afe-dai.c -- 2.16.2 diff --git a/sound/soc/qcom/Kconfig b/sound/soc/qcom/Kconfig index 43f9ed85efa8..d3523a30d942 100644 --- a/sound/soc/qcom/Kconfig +++ b/sound/soc/qcom/Kconfig @@ -50,6 +50,9 @@ config SND_SOC_QDSP6_CORE config SND_SOC_QDSP6_AFE tristate +config SND_SOC_QDSP6_AFE_DAI + tristate + config SND_SOC_QDSP6_ADM tristate @@ -65,6 +68,7 @@ config SND_SOC_QDSP6 select SND_SOC_QDSP6_COMMON select SND_SOC_QDSP6_CORE select SND_SOC_QDSP6_AFE + select SND_SOC_QDSP6_AFE_DAI select SND_SOC_QDSP6_ADM select SND_SOC_QDSP6_ROUTING select SND_SOC_QDSP6_ASM diff --git a/sound/soc/qcom/qdsp6/Makefile b/sound/soc/qcom/qdsp6/Makefile index 0e8e2febb7ec..bada1aa303c2 100644 --- a/sound/soc/qcom/qdsp6/Makefile +++ b/sound/soc/qcom/qdsp6/Makefile @@ -1,6 +1,7 @@ obj-$(CONFIG_SND_SOC_QDSP6_COMMON) += q6dsp-common.o obj-$(CONFIG_SND_SOC_QDSP6_CORE) += q6core.o obj-$(CONFIG_SND_SOC_QDSP6_AFE) += q6afe.o +obj-$(CONFIG_SND_SOC_QDSP6_AFE_DAI) += q6afe-dai.o obj-$(CONFIG_SND_SOC_QDSP6_ADM) += q6adm.o obj-$(CONFIG_SND_SOC_QDSP6_ROUTING) += q6routing.o obj-$(CONFIG_SND_SOC_QDSP6_ASM) += q6asm.o diff --git a/sound/soc/qcom/qdsp6/q6afe-dai.c b/sound/soc/qcom/qdsp6/q6afe-dai.c new file mode 100644 index 000000000000..4378e29a95c5 --- /dev/null +++ b/sound/soc/qcom/qdsp6/q6afe-dai.c @@ -0,0 +1,748 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2011-2017, The Linux Foundation. All rights reserved. +// Copyright (c) 2018, Linaro Limited + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "q6afe.h" + +struct q6afe_dai_priv_data { + uint32_t sd_line_mask; +}; + +struct q6afe_dai_data { + struct q6afe_port *port[AFE_PORT_MAX]; + struct q6afe_port_config port_config[AFE_PORT_MAX]; + bool is_port_started[AFE_PORT_MAX]; + struct q6afe_dai_priv_data priv[AFE_PORT_MAX]; +}; + +static int q6slim_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_slim_cfg *slim = &dai_data->port_config[dai->id].slim; + + slim->num_channels = params_channels(params); + slim->sample_rate = params_rate(params); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + case SNDRV_PCM_FORMAT_SPECIAL: + slim->bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + slim->bit_width = 24; + break; + case SNDRV_PCM_FORMAT_S32_LE: + slim->bit_width = 32; + break; + default: + pr_err("%s: format %d\n", + __func__, params_format(params)); + return -EINVAL; + } + + return 0; +} + +static int q6hdmi_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int channels = params_channels(params); + struct q6afe_hdmi_cfg *hdmi = &dai_data->port_config[dai->id].hdmi; + + hdmi->sample_rate = params_rate(params); + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + hdmi->bit_width = 16; + break; + case SNDRV_PCM_FORMAT_S24_LE: + hdmi->bit_width = 24; + break; + } + + /* HDMI spec CEA-861-E: Table 28 Audio InfoFrame Data Byte 4 */ + switch (channels) { + case 2: + hdmi->channel_allocation = 0; + break; + case 3: + hdmi->channel_allocation = 0x02; + break; + case 4: + hdmi->channel_allocation = 0x06; + break; + case 5: + hdmi->channel_allocation = 0x0A; + break; + case 6: + hdmi->channel_allocation = 0x0B; + break; + case 7: + hdmi->channel_allocation = 0x12; + break; + case 8: + hdmi->channel_allocation = 0x13; + break; + default: + dev_err(dai->dev, "invalid Channels = %u\n", channels); + return -EINVAL; + } + + return 0; +} + +static int q6i2s_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg; + + i2s->sample_rate = params_rate(params); + i2s->bit_width = params_width(params); + i2s->num_channels = params_channels(params); + i2s->sd_line_mask = dai_data->priv[dai->id].sd_line_mask; + + return 0; +} + +static int q6i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_i2s_cfg *i2s = &dai_data->port_config[dai->id].i2s_cfg; + + i2s->fmt = fmt; + + return 0; +} + +static void q6afe_dai_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + + dai_data->is_port_started[dai->id] = false; + +} + +static int q6afe_mi2s_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (dai_data->is_port_started[dai->id]) { + /* stop the port and restart with new port config */ + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + return rc; + } + } + + rc = q6afe_i2s_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].i2s_cfg); + if (rc < 0) { + dev_err(dai->dev, "fail to prepare AFE port %x\n", dai->id); + return rc; + } + + rc = q6afe_port_start(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to start AFE port %x\n", dai->id); + return rc; + } + dai_data->is_port_started[dai->id] = true; + + return 0; +} + +static int q6afe_dai_prepare(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + int rc; + + if (dai_data->is_port_started[dai->id]) { + /* stop the port and restart with new port config */ + rc = q6afe_port_stop(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to close AFE port (%d)\n", rc); + return rc; + } + } + + if (dai->id == HDMI_RX) + q6afe_hdmi_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].hdmi); + else if (dai->id >= SLIMBUS_0_RX && dai->id <= SLIMBUS_6_TX) + q6afe_slim_port_prepare(dai_data->port[dai->id], + &dai_data->port_config[dai->id].slim); + + rc = q6afe_port_start(dai_data->port[dai->id]); + if (rc < 0) { + dev_err(dai->dev, "fail to start AFE port %x\n", dai->id); + return rc; + } + dai_data->is_port_started[dai->id] = true; + + return 0; +} + +static int q6slim_set_channel_map(struct snd_soc_dai *dai, + unsigned int tx_num, unsigned int *tx_slot, + unsigned int rx_num, unsigned int *rx_slot) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port_config *pcfg = &dai_data->port_config[dai->id]; + int i; + + if (!rx_slot) { + pr_err("%s: rx slot not found\n", __func__); + return -EINVAL; + } + + for (i = 0; i < rx_num; i++) { + pcfg->slim.ch_mapping[i] = rx_slot[i]; + pr_debug("%s: find number of channels[%d] ch[%d]\n", + __func__, i, rx_slot[i]); + } + + pcfg->slim.num_channels = rx_num; + + pr_debug("%s: SLIMBUS_%d_RX cnt[%d] ch[%d %d]\n", __func__, + (dai->id - SLIMBUS_0_RX) / 2, rx_num, + pcfg->slim.ch_mapping[0], + pcfg->slim.ch_mapping[1]); + + return 0; +} + +static int q6afe_mi2s_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port *port = dai_data->port[dai->id]; + + switch (clk_id) { + case LPAIF_DIG_CLK: + return q6afe_port_set_sysclk(port, clk_id, 0, 5, freq, dir); + case LPAIF_BIT_CLK: + case LPAIF_OSR_CLK: + return q6afe_port_set_sysclk(port, clk_id, + Q6AFE_LPASS_CLK_SRC_INTERNAL, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + freq, dir); + case Q6AFE_LPASS_CLK_ID_PRI_MI2S_IBIT ... Q6AFE_LPASS_CLK_ID_INT_MCLK_1: + return q6afe_port_set_sysclk(port, clk_id, + Q6AFE_LPASS_CLK_ATTRIBUTE_COUPLE_NO, + Q6AFE_LPASS_CLK_ROOT_DEFAULT, + freq, dir); + } + + return 0; +} + +static const struct snd_soc_dapm_route q6afe_dapm_routes[] = { + {"HDMI Playback", NULL, "HDMI_RX"}, + {"Slimbus1 Playback", NULL, "SLIMBUS_1_RX"}, + {"Slimbus2 Playback", NULL, "SLIMBUS_2_RX"}, + {"Slimbus3 Playback", NULL, "SLIMBUS_3_RX"}, + {"Slimbus4 Playback", NULL, "SLIMBUS_4_RX"}, + {"Slimbus5 Playback", NULL, "SLIMBUS_5_RX"}, + {"Slimbus6 Playback", NULL, "SLIMBUS_6_RX"}, + + {"Primary MI2S Playback", NULL, "PRI_MI2S_RX"}, + {"Secondary MI2S Playback", NULL, "SEC_MI2S_RX"}, + {"Tertiary MI2S Playback", NULL, "TERT_MI2S_RX"}, + {"Quaternary MI2S Playback", NULL, "QUAT_MI2S_RX"}, + + {"TERT_MI2S_TX", NULL, "Tertiary MI2S Capture"}, + {"PRI_MI2S_TX", NULL, "Primary MI2S Capture"}, + {"SEC_MI2S_TX", NULL, "Secondary MI2S Capture"}, + {"QUAT_MI2S_TX", NULL, "Quaternary MI2S Capture"}, +}; + +static struct snd_soc_dai_ops q6hdmi_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6hdmi_hw_params, + .shutdown = q6afe_dai_shutdown, +}; + +static struct snd_soc_dai_ops q6i2s_ops = { + .prepare = q6afe_mi2s_prepare, + .hw_params = q6i2s_hw_params, + .set_fmt = q6i2s_set_fmt, + .shutdown = q6afe_dai_shutdown, + .set_sysclk = q6afe_mi2s_set_sysclk, +}; + +static struct snd_soc_dai_ops q6slim_ops = { + .prepare = q6afe_dai_prepare, + .hw_params = q6slim_hw_params, + .shutdown = q6afe_dai_shutdown, + .set_channel_map = q6slim_set_channel_map, +}; + +static int msm_dai_q6_dai_probe(struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + struct q6afe_port *port; + + port = q6afe_port_get_from_id(dai->dev, dai->id); + if (IS_ERR(port)) { + dev_err(dai->dev, "Unable to get afe port\n"); + return -EINVAL; + } + dai_data->port[dai->id] = port; + + return 0; +} + +static int msm_dai_q6_dai_remove(struct snd_soc_dai *dai) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dai->dev); + + q6afe_port_put(dai_data->port[dai->id]); + dai_data->port[dai->id] = NULL; + + return 0; +} + +static struct snd_soc_dai_driver q6afe_dais[] = { + { + .playback = { + .stream_name = "HDMI Playback", + .rates = SNDRV_PCM_RATE_48000 | + SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 2, + .channels_max = 8, + .rate_max = 192000, + .rate_min = 48000, + }, + .ops = &q6hdmi_ops, + .id = HDMI_RX, + .name = "HDMI", + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .name = "SLIMBUS_0_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_0_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + .playback = { + .stream_name = "Slimbus Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + }, { + .playback = { + .stream_name = "Slimbus1 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_1_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_1_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus2 Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 8, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_2_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_2_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus3 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_3_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_3_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus4 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_4_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_4_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus5 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .name = "SLIMBUS_5_RX", + .ops = &q6slim_ops, + .id = SLIMBUS_5_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Slimbus6 Playback", + .rates = SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 | + SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | + SNDRV_PCM_RATE_192000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .channels_min = 1, + .channels_max = 2, + .rate_min = 8000, + .rate_max = 192000, + }, + .ops = &q6slim_ops, + .name = "SLIMBUS_6_RX", + .id = SLIMBUS_6_RX, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Primary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = PRIMARY_MI2S_RX, + .name = "PRI_MI2S_RX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Primary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = PRIMARY_MI2S_TX, + .name = "PRI_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Secondary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "SEC_MI2S_RX", + .id = SECONDARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Secondary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = SECONDARY_MI2S_TX, + .name = "SEC_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Tertiary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "TERT_MI2S_RX", + .id = TERTIARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Tertiary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = TERTIARY_MI2S_TX, + .name = "TERT_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .playback = { + .stream_name = "Quaternary MI2S Playback", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .name = "QUAT_MI2S_RX", + .id = QUATERNARY_MI2S_RX, + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, { + .capture = { + .stream_name = "Quaternary MI2S Capture", + .rates = SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_8000 | + SNDRV_PCM_RATE_16000, + .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE, + .rate_min = 8000, + .rate_max = 48000, + }, + .id = QUATERNARY_MI2S_TX, + .name = "QUAT_MI2S_TX", + .ops = &q6i2s_ops, + .probe = msm_dai_q6_dai_probe, + .remove = msm_dai_q6_dai_remove, + }, +}; + +static int q6afe_of_xlate_dai_name(struct snd_soc_component *component, + 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(q6afe_dais); i++) { + if (q6afe_dais[i].id == id) { + *dai_name = q6afe_dais[i].name; + ret = 0; + break; + } + } + + return ret; +} + +static const struct snd_soc_dapm_widget q6afe_dai_widgets[] = { + SND_SOC_DAPM_AIF_OUT("HDMI_RX", "HDMI Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_0_RX", "Slimbus Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_1_RX", "Slimbus1 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_2_RX", "Slimbus2 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_3_RX", "Slimbus3 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_4_RX", "Slimbus4 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_5_RX", "Slimbus5 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SLIMBUS_6_RX", "Slimbus6 Playback", 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("QUAT_MI2S_RX", "Quaternary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("QUAT_MI2S_TX", "Quaternary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("TERT_MI2S_RX", "Tertiary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("TERT_MI2S_TX", "Tertiary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX", "Secondary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("SEC_MI2S_TX", "Secondary MI2S Capture", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("SEC_MI2S_RX_SD1", + "Secondary MI2S Playback SD1", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_OUT("PRI_MI2S_RX", "Primary MI2S Playback", + 0, 0, 0, 0), + SND_SOC_DAPM_AIF_IN("PRI_MI2S_TX", "Primary MI2S Capture", + 0, 0, 0, 0), +}; + +static const struct snd_soc_component_driver q6afe_dai_component = { + .name = "q6afe-dai-component", + .dapm_widgets = q6afe_dai_widgets, + .num_dapm_widgets = ARRAY_SIZE(q6afe_dai_widgets), + .dapm_routes = q6afe_dapm_routes, + .num_dapm_routes = ARRAY_SIZE(q6afe_dapm_routes), + .of_xlate_dai_name = q6afe_of_xlate_dai_name, + +}; + +static void of_q6afe_parse_dai_data(struct device *dev, + struct q6afe_dai_data *data) +{ + struct device_node *node; + int ret; + + for_each_child_of_node(dev->of_node, node) { + unsigned int lines[Q6AFE_MAX_MI2S_LINES]; + struct q6afe_dai_priv_data *priv; + int id, i, num_lines; + + ret = of_property_read_u32(node, "reg", &id); + if (ret || id > AFE_PORT_MAX) { + dev_err(dev, "valid dai id not found:%d\n", ret); + continue; + } + + switch (id) { + /* MI2S specific properties */ + case PRIMARY_MI2S_RX ... QUATERNARY_MI2S_TX: + priv = &data->priv[id]; + ret = of_property_read_variable_u32_array(node, + "qcom,sd-lines", + lines, 0, + Q6AFE_MAX_MI2S_LINES); + if (ret < 0) + num_lines = 0; + else + num_lines = ret; + + priv->sd_line_mask = 0; + + for (i = 0; i < num_lines; i++) + priv->sd_line_mask |= BIT(lines[i]); + + break; + default: + break; + } + } +} + +static int q6afe_dai_bind(struct device *dev, struct device *master, void *data) +{ + struct q6afe_dai_data *dai_data; + + dai_data = kzalloc(sizeof(*dai_data), GFP_KERNEL); + if (!dai_data) + return -ENOMEM; + + dev_set_drvdata(dev, dai_data); + + of_q6afe_parse_dai_data(dev, dai_data); + + return snd_soc_register_component(dev, &q6afe_dai_component, + q6afe_dais, ARRAY_SIZE(q6afe_dais)); +} + +static void q6afe_dai_unbind(struct device *dev, struct device *master, + void *data) +{ + struct q6afe_dai_data *dai_data = dev_get_drvdata(dev); + + snd_soc_unregister_component(dev); + kfree(dai_data); +} + +static const struct component_ops q6afe_dai_comp_ops = { + .bind = q6afe_dai_bind, + .unbind = q6afe_dai_unbind, +}; + +static int q6afe_dai_dev_probe(struct platform_device *pdev) +{ + return component_add(&pdev->dev, &q6afe_dai_comp_ops); +} + +static int q6afe_dai_dev_remove(struct platform_device *pdev) +{ + component_del(&pdev->dev, &q6afe_dai_comp_ops); + return 0; +} + +static struct platform_driver q6afe_dai_platform_driver = { + .driver = { + .name = "q6afe-dai", + }, + .probe = q6afe_dai_dev_probe, + .remove = q6afe_dai_dev_remove, +}; +module_platform_driver(q6afe_dai_platform_driver); + +MODULE_DESCRIPTION("Q6 Audio Fronend dai driver"); +MODULE_LICENSE("GPL v2"); From patchwork Wed May 9 12:56:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Srinivas Kandagatla X-Patchwork-Id: 135269 Delivered-To: patch@linaro.org Received: by 10.46.151.6 with SMTP id r6csp5610539lji; Wed, 9 May 2018 06:01:31 -0700 (PDT) X-Google-Smtp-Source: AB8JxZpbp/TFiKCsFjrx1B0xoz5c3KxPh0Gh3SQ4EKs1GMvCHQLN4pPz0CX++yFqgktJA1bHWukL X-Received: by 2002:a17:902:5382:: with SMTP id c2-v6mr45847350pli.335.1525870891698; Wed, 09 May 2018 06:01:31 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1525870891; cv=none; d=google.com; s=arc-20160816; b=CwDPKLHi0Hgb4zvLI0uISpjfXSKDZQyOgtwxSL9Bo75HNfVc72cYyvPgRCaLh52iM9 j/nmtyHTlFMi22Xa40vw0ZV5eDFbk7appRUwZ0rhm7KHtp5yXC39R9aK3P+Ws9xQn7UM 2zwAKbmr8oyE7ArrT8YA08GPNQNh3vUrizZndjgscL4GV6Be38AO6nzo+//A4m8uhSYC 71508yF/bqSM1sV8LlJy6+VQ10yrLdXf0QPaDLkPg3/WSqbF8RuScIuyftbnmns8OLR+ oMEmOOpNplr03RP/Sjh6mddNe1ZekNl+kYvuJw6qFX6ZCBjS6aGtjbglMyHVqgNRhWn5 515w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:in-reply-to:message-id:date :subject:cc:to:from:dkim-signature:arc-authentication-results; bh=GWSFu/p0icXeZfV2GGmRSjJWUCYAoHalwz5/EHU3XaY=; b=E9prHe1sHokV+zqh9c0uIOENVRcf4xvgGXi8x9pfS+MoZp9vgyrtn/stEctnTpBtDT MqLpsVlRQ/UV9S4B8qUEwjkvzg2QopUICsx4meY4rMidNB5j0EYr6JpkgohJcy0JZhsJ ylVErsR8l0SEfWCFxYeeBTWpO3WgNq2aQiITJQoP0txVe/GZhlw56O97OblrQUbXyqm9 tWR+xEn0+ShKSt2V6vUUdzbb+B8m4FrRiW4WQELkmXnBQy7J7TYL8ZnJGjIL6MeCmQcR UJ0LAR1NKhbW0J1kXmTtjb4iZvRLoHcKzDTBQEV8GtdZs9MBg9Nr784hwGE/R87P5WzR VFLQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EDGfoI4s; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id j64-v6si2569149pgc.21.2018.05.09.06.01.31; Wed, 09 May 2018 06:01:31 -0700 (PDT) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@linaro.org header.s=google header.b=EDGfoI4s; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linaro.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S935191AbeEINB1 (ORCPT + 29 others); Wed, 9 May 2018 09:01:27 -0400 Received: from mail-wm0-f67.google.com ([74.125.82.67]:52839 "EHLO mail-wm0-f67.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S935169AbeEINBP (ORCPT ); Wed, 9 May 2018 09:01:15 -0400 Received: by mail-wm0-f67.google.com with SMTP id w194so24488755wmf.2 for ; Wed, 09 May 2018 06:01: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; bh=GWSFu/p0icXeZfV2GGmRSjJWUCYAoHalwz5/EHU3XaY=; b=EDGfoI4sjhiZqnO4m8Cicaw0PiV+zePaoUm8q1N0gZj7aqIMUyt+zgW+btfPTw8cxR 1kWw+xctHbESzpNvnXzih+SNY0agC8iq8HqBsLiap/OiP4mHhzA3vqDiyNYBn7xw1Rji P57ft7cvv9A694g5dAHpYHCWAVeD9A1/I1/rQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=GWSFu/p0icXeZfV2GGmRSjJWUCYAoHalwz5/EHU3XaY=; b=cdsxVCWMXto8t2NP1QG6vk8JlAerurHVd+o8Vm6fJlE7TfMVx3gOX7a5tBPuyGXNVA M4m6Dh7UnO37vXicURivPuprSvoqqvDTUVpO1BSbaMrlVnXjlKOZuyVri5QZp5taYIXb YRQQv2a9Nvc1JT9BbEALQwFONO7PXt8izj5Qa8b/CIxUNHjdyoSGXPa66SVk+1F+ESVH 4G+OIByRJ8NtP2F9FEDVaSUVLdpPofkVZfPzyJVuOiZ7bwbLNYmtVG4RaKx2cl0tZ8GS 4GooiQfRTzYhfuPNf8RVXWSIEw/w84OwQ8l/KL4UZQDLdiL7j9Sf02VEPBX1FB2g4qpa iHjQ== X-Gm-Message-State: ALKqPwcDLBv89bSwAu8Gxf6upvLAIe5KpaenmSbOrj1UHSZOCYMS5bsj f2d1Z/OeRnjPmKPw2JIPBWYbvQ== X-Received: by 10.28.13.202 with SMTP id 193mr5565008wmn.36.1525870874394; Wed, 09 May 2018 06:01:14 -0700 (PDT) Received: from localhost.localdomain (cpc90716-aztw32-2-0-cust92.18-1.cable.virginm.net. [86.26.100.93]) by smtp.gmail.com with ESMTPSA id q2-v6sm29422963wrj.57.2018.05.09.06.01.13 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Wed, 09 May 2018 06:01:13 -0700 (PDT) From: Srinivas Kandagatla To: andy.gross@linaro.org, broonie@kernel.org, linux-arm-msm@vger.kernel.org, alsa-devel@alsa-project.org, robh+dt@kernel.org, bgoswami@codeaurora.org Cc: gregkh@linuxfoundation.org, david.brown@linaro.org, mark.rutland@arm.com, lgirdwood@gmail.com, plai@codeaurora.org, tiwai@suse.com, perex@perex.cz, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, rohkumar@qti.qualcomm.com, spatakok@qti.qualcomm.com, Srinivas Kandagatla Subject: [PATCH v8 24/24] MAINTAINERS: Add myself as co-maintainer of qcom audio Date: Wed, 9 May 2018 13:56:35 +0100 Message-Id: <20180509125635.5653-25-srinivas.kandagatla@linaro.org> X-Mailer: git-send-email 2.16.2 In-Reply-To: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> References: <20180509125635.5653-1-srinivas.kandagatla@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Add myself as co-maintainer of qcom audio drivers Signed-off-by: Srinivas Kandagatla Reviewed-by: Banajit Goswami --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) -- 2.16.2 diff --git a/MAINTAINERS b/MAINTAINERS index 20032feaa9e7..3df5f6226827 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11522,6 +11522,7 @@ F: drivers/crypto/qat/ QCOM AUDIO (ASoC) DRIVERS M: Patrick Lai M: Banajit Goswami +M: Srinivas Kandagatla L: alsa-devel@alsa-project.org (moderated for non-subscribers) S: Supported F: sound/soc/qcom/