From patchwork Sat Oct 23 11:13:57 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579505 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5EE2BC433FE for ; Sat, 23 Oct 2021 11:16:25 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2BC5B60E97 for ; Sat, 23 Oct 2021 11:16:25 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 2BC5B60E97 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=r6g2XMq0I5r53XT4pfyneUv0uhI2lOWcR6qoL8vgqNA=; b=Mzwar2gEsR0Tk4 oZB6EgiEo2ZjJZnrLMKxyr0ROFWh0uSgJXlaDXzy4i34grn9sauRgo/eUoOMHPZE6iNS1+vmxd9Ue W9PjDeofDi/vI8Dn4Uk933eZz4AcUKkrI+FC6Tpq4LU+tNz54HELHaFFVMb+1Cc3zJYyGLsaIex56 wm3glxwLj1inNQbC0NcYilWNHFQ7UYMk2SdtWOfHlFO3pa2vN+BRW9wcABZmECvqQ41EMwM+Kvaef 3JpuAKtq92QxGBjewxyKEC4EnpYzhWbcC3j3wS4n1EPP3eHwxOkmVfPNGOqP87oqcDPL+2hREoFPn 2IvCgXE2c7+jtU19Sk0Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzJ-00CcLY-ME; Sat, 23 Oct 2021 11:14:57 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzF-00CcKb-CF; Sat, 23 Oct 2021 11:14:54 +0000 X-UUID: 66c0baf007da4dea94464e564c8035fd-20211023 X-UUID: 66c0baf007da4dea94464e564c8035fd-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 2097715582; Sat, 23 Oct 2021 04:14:51 -0700 Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:49 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:14:48 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:48 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 01/13] dt-bindings: soc: mediatek: apusys: add mt8192 apu iommu bindings Date: Sat, 23 Oct 2021 19:13:57 +0800 Message-ID: <20211023111409.30463-2-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041453_446307_CE99C280 X-CRM114-Status: UNSURE ( 8.39 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add mt8192 apu iommu bindings. Signed-off-by: Flora Fu --- Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml index c528a299afa9..338d245fc4af 100644 --- a/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml +++ b/Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml @@ -77,6 +77,7 @@ properties: - mediatek,mt8173-m4u # generation two - mediatek,mt8183-m4u # generation two - mediatek,mt8192-m4u # generation two + - mediatek,mt8192-iommu-apu # generation two - mediatek,mt8195-iommu-vdo # generation two - mediatek,mt8195-iommu-vpp # generation two - mediatek,mt8195-iommu-infra # generation two @@ -154,6 +155,7 @@ allOf: compatible: enum: - mediatek,mt8192-m4u + - mediatek,mt8192-iommu-apu - mediatek,mt8195-iommu-vdo - mediatek,mt8195-iommu-vpp From patchwork Sat Oct 23 11:13:58 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579511 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CA28BC433F5 for ; Sat, 23 Oct 2021 11:16:54 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 9A9A860E97 for ; Sat, 23 Oct 2021 11:16:54 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 9A9A860E97 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=SS40ljDaZODEhj7JfLmHSdDiOCkkZ/BstfYPmgrVJSs=; b=tDGt4brsjTIGMI Vf637xRxGHbDguFyw4ibxvpeY6R6AkS7WT7RLCccFkwPi9nkoyK+lSrP54MwnZrHJ++WsTaquRrbF khgUkJCMIZzfWrIGnzBbRNmFarkUGAIm5kRXd4lj8212B3MrUjV82FUqZaUuFwGrsWrxT9reY1RMQ 5n7LYH7v9YKUgYqMelc5uFj17nks1iO8Tug8wRx+RMAO06+TJOSyQZ+Cnri/JgBb1yq4DMp2KFpGO FeEMk6D682hTYF/eNze+ubVQODY5GUVN92PyHsT4SssKnbS0N/gDL3KnCbJCVRTt5Gq6Or1w5NcCg yiOWSCiyHxAjljXKJimQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzp-00Ccau-PO; Sat, 23 Oct 2021 11:15:29 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzI-00CcLi-UE; Sat, 23 Oct 2021 11:14:58 +0000 X-UUID: 3c479e071452475896d1b2e76669081d-20211023 X-UUID: 3c479e071452475896d1b2e76669081d-20211023 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 13240990; Sat, 23 Oct 2021 04:14:53 -0700 Received: from mtkmbs10n2.mediatek.inc (172.21.101.183) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:51 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sat, 23 Oct 2021 19:14:50 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:50 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 02/13] dt-bindings: soc: mediatek: apusys: Add new document for APU power Date: Sat, 23 Oct 2021 19:13:58 +0800 Message-ID: <20211023111409.30463-3-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041457_010305_665F7750 X-CRM114-Status: GOOD ( 13.24 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add new document for APU power controller. Signed-off-by: Flora Fu --- .../soc/mediatek/mediatek,apu-pwr.yaml | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-pwr.yaml diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-pwr.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-pwr.yaml new file mode 100644 index 000000000000..0fd5af5138e3 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-pwr.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# # Copyright 2021 MediaTek Inc. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/mediatek/mediatek,apu-pwr.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek APU Power + +description: | + Mediatek AI Process Unit (APU) power driver support for subsys clock and + regulator controller. It will has device link to iommu-apu and apusys-rv + tinysys driver to ensure the power state is ready for hardware + in sub modules. + +maintainers: + - Flora Fu + +properties: + compatible: + oneOf: + - const: mediatek,apusys-power + - items: + - const: mediatek,apusys-power + - const: mediatek,mt8192-apu-power + + reg: + minItems: 1 + + reg-names: + minItems: 1 + + power-domains: + maxItems: 1 + + vvpu-supply: + description: apu vpu regulator supply. + + vmdla-supply: + description: apu mdla regulator supply. + + clocks: + description: Contains module clock source and clock names + + clock-names: + description: Names of the clocks list in clocks property + +required: + - compatible + - reg + - reg-names + - clocks + - clock-names + - vvpu-supply + - vmdla-supply + +additionalProperties: false + +examples: + - | + #include + apusys_power: apusys_power@190f1000 { + compatible = "mediatek,apusys-power", + "mediatek,mt8192-apu-power"; + reg = <0x190f1000 0x1000>; + reg-names = "apu_pcu"; + power-domains = <&apuspm 0>; + vvpu-supply = <&mt6359_vproc1_buck_reg>; + vmdla-supply = <&mt6359_vproc2_buck_reg>; + clocks = <&topckgen CLK_TOP_DSP_SEL>, + <&topckgen CLK_TOP_DSP1_SEL>, + <&topckgen CLK_TOP_DSP1_NPUPLL_SEL>, + <&topckgen CLK_TOP_DSP2_SEL>, + <&topckgen CLK_TOP_DSP2_NPUPLL_SEL>, + <&topckgen CLK_TOP_DSP5_SEL>, + <&topckgen CLK_TOP_DSP5_APUPLL_SEL>, + <&topckgen CLK_TOP_IPU_IF_SEL>, + <&clk26m>; + clock-names = "clk_top_dsp_sel", + "clk_top_dsp1_sel", + "clk_top_dsp1_npupll_sel", + "clk_top_dsp2_sel", + "clk_top_dsp2_npupll_sel", + "clk_top_dsp5_sel", + "clk_top_dsp5_apupll_sel", + "clk_top_ipu_if_sel", + "clk_top_clk26m"; + }; From patchwork Sat Oct 23 11:13:59 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579509 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 47F3FC433FE for ; Sat, 23 Oct 2021 11:16:35 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 0919D60E97 for ; Sat, 23 Oct 2021 11:16:35 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 0919D60E97 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=yJscAbX1oueZOQB4GYkQLIDIqZzVQJmwY1Jx/+Zbm9U=; b=aCSIf8LoGEaOzq q0poQHVNd3qqPrFGVDHNdGgDOVRh7TuyKa4LFCSjBP41la6zTBtdfMbMjvQeb9EbonlAVVqtJ1CuH ONGgFfmCbnWODtqRlWl2qqC5M0w8uvWKFj/96GK+1P78dfrsJQMPZXbg+wZUMzlFYW2dEqUAQjziT X54PLwst0IkQjUGhuZ8QVSUfQ7WpSduLDJHs5rrrKRVnxnhj96gPR090PX/3ul/AN7h58erVuY9Hw jF5qdGR2yCBzl8ZLkHzfwjxbvZHZvy+t0fHUnJelImAjP1z8sG1A2Yrutz2c4vrWr5sPVJhAKugZP KhjpG+mFmYAxOu+YDakQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzb-00CcTZ-6Z; Sat, 23 Oct 2021 11:15:15 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzH-00CcLE-V2; Sat, 23 Oct 2021 11:14:57 +0000 X-UUID: 28f0ac0489f1434c9a70966f9b1d9e50-20211023 X-UUID: 28f0ac0489f1434c9a70966f9b1d9e50-20211023 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1709543178; Sat, 23 Oct 2021 04:14:54 -0700 Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:52 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:14:51 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:51 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 03/13] dt-bindings: soc: mediatek: apusys: Add new document for APU tinysys Date: Sat, 23 Oct 2021 19:13:59 +0800 Message-ID: <20211023111409.30463-4-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041456_031537_2E6E9610 X-CRM114-Status: GOOD ( 14.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add new document for APU tinysys. Signed-off-by: Flora Fu --- .../soc/mediatek/mediatek,apu-rv.yaml | 140 ++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-rv.yaml diff --git a/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-rv.yaml b/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-rv.yaml new file mode 100644 index 000000000000..ee0ff5d656e9 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/mediatek/mediatek,apu-rv.yaml @@ -0,0 +1,140 @@ +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) +# # Copyright 2021 MediaTek Inc. +%YAML 1.2 +--- +$id: "http://devicetree.org/schemas/soc/mediatek/mediatek,apu-rv.yaml#" +$schema: "http://devicetree.org/meta-schemas/core.yaml#" + +title: Mediatek APU Power + +description: | + APU integrated subsystem having MD32RV33 (MD32) that runs tinysys + The tinsys is running on a micro processor in APU. + Its firmware is load and boot from Kernel side. Kernel and tinysys use + IPI to tx/rx messages. + +maintainers: + - Flora Fu + +properties: + compatible: + enum: + - mediatek,mt8192-apusys-rv + + reg: + minItems: 1 + + reg-names: + minItems: 1 + + power-domains: + maxItems: 1 + + iommus: + maxItems: 1 + + interrupts: + description: List of interrupts. + + interrupt-names: + description: Name list of interrupts. + + mediatek,apusys-power: + $ref: /schemas/types.yaml#/definitions/phandle + description: | + phandle to the device containing the apusys-power handle. + + apu_ctrl: + description: handle the ipi state, time sync and deep idle message. + type: object + + properties: + compatible: + const: "mediatek,apu-ctrl-rpmsg" + + required: + - compatible + + additionalProperties: false + + apu_pwr_tx: + description: handle the message trigger from AP side to tinysys. + type: object + + properties: + compatible: + const: "mediatek,apupwr-tx-rpmsg" + + required: + - compatible + + additionalProperties: false + + apu_pwr_rx: + description: handle the message trigger from tinysys to AP side. + type: object + + properties: + compatible: + const: "mediatek,apupwr-rx-rpmsg" + + required: + - compatible + + additionalProperties: false + + apu_mdw_rpmsg: + description: handle the middleware messages. + type: object + + properties: + compatible: + const: "mediatek,apu-mdw-rpmsg" + + required: + - compatible + + additionalProperties: false + +required: + - compatible + - reg + - power-domains + - interrupts + - mediatek,apusys-power + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + apusys_rv@19001000 { + compatible = "mediatek,mt8192-apusys-rv"; + reg = <0x19000000 0x1000>, + <0x19001000 0x1000>; + reg-names = "apu_mbox", + "md32_sysctrl"; + mediatek,apusys-power = <&apusys_power>; + power-domains = <&apuspm 0>; + iommus = <&iommu_apu IOMMU_PORT_APU_DATA>; + interrupts = , + ; + interrupt-names = "apu_wdt", + "mbox0_irq"; + apu_ctrl { + compatible = "mediatek,apu-ctrl-rpmsg"; + }; + apu_pwr_tx { + compatible = "mediatek,apupwr-tx-rpmsg"; + }; + apu_pwr_rx { + compatible = "mediatek,apupwr-rx-rpmsg"; + }; + apu_mdw_rpmsg { + compatible = "mediatek,apu-mdw-rpmsg"; + }; + }; From patchwork Sat Oct 23 11:14:00 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579513 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 544AEC433F5 for ; Sat, 23 Oct 2021 11:17:11 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 26E0160EE9 for ; Sat, 23 Oct 2021 11:17:11 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 26E0160EE9 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=7nbksgOSywYC+Or1Lk1wesJe/uaG2UNUVs+folW/hLk=; b=rh0dQ6e69Ca1O/ BlNZevX5aQyCMZZwfvcl93n3VyBc0E+dT3/zGbsLyKlxjBOsn8Q2fFUDWDmkBuRKHW00W4U58updc GbdDnwPrgSlLPdR4cqRbojY1an2nfLzPSvk5cjCIJxfAlAsKWgahEICIW/GTyfKyWOlicwaNHQbG3 mmRKPEuZ8e+8AazIQQXLZEibM4Y8oLISrtgTg9FTn2v/jFI3Icy9rHnj93l0PDjDf7JYzn3FD+DBt JiYilI0gg9hOmI1fD7s/BJiF1CA7492UlAsuDQIzIvdR6FNxq781NXn49hE+aQ0C66ZxBE/1hSe70 oyZJUVRCtRxrYynfsBSQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF09-00Cckx-G5; Sat, 23 Oct 2021 11:15:49 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzJ-00CcMB-UT; Sat, 23 Oct 2021 11:14:59 +0000 X-UUID: c9455a2900ee4137b68ecb1ddae13b02-20211023 X-UUID: c9455a2900ee4137b68ecb1ddae13b02-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 48087376; Sat, 23 Oct 2021 04:14:55 -0700 Received: from mtkmbs10n2.mediatek.inc (172.21.101.183) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:54 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sat, 23 Oct 2021 19:14:52 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:52 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 04/13] iommu/mediatek: Add APU iommu support Date: Sat, 23 Oct 2021 19:14:00 +0800 Message-ID: <20211023111409.30463-5-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041458_017531_7F43A48D X-CRM114-Status: GOOD ( 18.10 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org APU IOMMU is a new iommu HW. it use a new pagetable. Add support for mt8192 apu iommu. Signed-off-by: Yong Wu Signed-off-by: Flora Fu --- drivers/iommu/mtk_iommu.c | 57 +++++++++++++++++++ include/dt-bindings/memory/mt8192-larb-port.h | 4 ++ 2 files changed, 61 insertions(+) diff --git a/drivers/iommu/mtk_iommu.c b/drivers/iommu/mtk_iommu.c index 90be8ebbc98a..a5f8f19e053a 100644 --- a/drivers/iommu/mtk_iommu.c +++ b/drivers/iommu/mtk_iommu.c @@ -133,6 +133,7 @@ /* 2 bits: iommu type */ #define MTK_IOMMU_TYPE_MM (0x0 << 13) #define MTK_IOMMU_TYPE_INFRA (0x1 << 13) +#define MTK_IOMMU_TYPE_APU (0x2 << 13) #define MTK_IOMMU_TYPE_MASK (0x3 << 13) #define IFA_IOMMU_PCIe_SUPPORT BIT(15) @@ -185,6 +186,7 @@ static int mtk_iommu_hw_init(const struct mtk_iommu_data *data, unsigned int ban #define MTK_IOMMU_4GB_MODE_REMAP_BASE 0x140000000UL static LIST_HEAD(m4ulist); /* List all the M4U HWs */ +static LIST_HEAD(apulist); /* List the apu iommu HWs */ #define for_each_m4u(data, head) list_for_each_entry(data, head, list) @@ -209,6 +211,13 @@ static const struct mtk_iommu_iova_region mt8192_multi_dom[] = { #endif }; +static const struct mtk_iommu_iova_region mt8192_multi_dom_apu[] = { + { .iova_base = 0x0, .size = SZ_4G}, /* APU DATA */ + { .iova_base = 0x4000000ULL, .size = 0x4000000}, /* APU VLM */ + { .iova_base = 0x10000000ULL, .size = 0x10000000}, /* APU VPU */ + { .iova_base = 0x70000000ULL, .size = 0x12600000}, /* APU REG */ +}; + /* If 2 M4U share a domain(use the same hwlist), Put the corresponding info in first data.*/ static struct mtk_iommu_data *mtk_iommu_get_frst_data(struct list_head *hwlist) { @@ -923,6 +932,37 @@ static int mtk_iommu_mm_dts_parse(struct device *dev, return 0; } +static int mtk_iommu_apu_prepare(struct device *dev) +{ + struct device_node *apupower_node; + struct platform_device *apudev; + struct device_link *link; + + apupower_node = of_find_compatible_node(NULL, NULL, "mediatek,apusys-power"); + if (!apupower_node) { + dev_warn(dev, "Can't find apu power node!\n"); + return -EINVAL; + } + + if (!of_device_is_available(apupower_node)) { + of_node_put(apupower_node); + return -EPERM; + } + + apudev = of_find_device_by_node(apupower_node); + if (!apudev) { + of_node_put(apupower_node); + return -EPROBE_DEFER; + } + + link = device_link_add(&apudev->dev, dev, DL_FLAG_PM_RUNTIME); + if (!link) + dev_err(dev, "Unable link %s.\n", apudev->name); + + of_node_put(apupower_node); + return 0; +} + static int mtk_iommu_probe(struct platform_device *pdev) { struct mtk_iommu_data *data; @@ -1021,6 +1061,10 @@ static int mtk_iommu_probe(struct platform_device *pdev) } data->pericfg = infracfg; + } else if (MTK_IOMMU_IS_TYPE(data->plat_data, MTK_IOMMU_TYPE_APU)) { + ret = mtk_iommu_apu_prepare(dev); + if (ret) + goto out_runtime_disable; } platform_set_drvdata(pdev, data); @@ -1268,6 +1312,18 @@ static const struct mtk_iommu_plat_data mt8192_data = { {0, 14, 16}, {0, 13, 18, 17}}, }; +static const struct mtk_iommu_plat_data mt8192_data_apu = { + .m4u_plat = M4U_MT8192, + .flags = WR_THROT_EN | DCM_DISABLE | MTK_IOMMU_TYPE_APU | + SHARE_PGTABLE, + .inv_sel_reg = REG_MMU_INV_SEL_GEN2, + .hw_list = &apulist, + .bank_nr = 1, + .bank_enable = {true}, + .iova_region = mt8192_multi_dom_apu, + .iova_region_nr = ARRAY_SIZE(mt8192_multi_dom_apu), +}; + static const struct mtk_iommu_plat_data mt8195_data_infra = { .m4u_plat = M4U_MT8195, .flags = WR_THROT_EN | DCM_DISABLE | @@ -1323,6 +1379,7 @@ static const struct of_device_id mtk_iommu_of_ids[] = { { .compatible = "mediatek,mt8173-m4u", .data = &mt8173_data}, { .compatible = "mediatek,mt8183-m4u", .data = &mt8183_data}, { .compatible = "mediatek,mt8192-m4u", .data = &mt8192_data}, + { .compatible = "mediatek,mt8192-iommu-apu", .data = &mt8192_data_apu}, { .compatible = "mediatek,mt8195-iommu-infra", .data = &mt8195_data_infra}, { .compatible = "mediatek,mt8195-iommu-vdo", .data = &mt8195_data_vdo}, { .compatible = "mediatek,mt8195-iommu-vpp", .data = &mt8195_data_vpp}, diff --git a/include/dt-bindings/memory/mt8192-larb-port.h b/include/dt-bindings/memory/mt8192-larb-port.h index 23035a52c675..908d6831bf99 100644 --- a/include/dt-bindings/memory/mt8192-larb-port.h +++ b/include/dt-bindings/memory/mt8192-larb-port.h @@ -240,4 +240,8 @@ #define M4U_PORT_L20_IPE_RSC_RDMA0 MTK_M4U_ID(20, 4) #define M4U_PORT_L20_IPE_RSC_WDMA MTK_M4U_ID(20, 5) +#define IOMMU_PORT_APU_DATA MTK_M4U_ID(0, 0) +#define IOMMU_PORT_APU_VLM MTK_M4U_ID(0, 1) +#define IOMMU_PORT_APU_VPU MTK_M4U_ID(0, 2) + #endif From patchwork Sat Oct 23 11:14:01 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579573 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A096C433F5 for ; Sat, 23 Oct 2021 11:26:50 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BFC6C60FE7 for ; Sat, 23 Oct 2021 11:26:49 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org BFC6C60FE7 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=WndKCCj6cXU0MPWFKaen1c0lra9hEDQ9VpOapR3WOG8=; b=ck54SlXcylDpap dLhOK+8FU7IWIEfuiDtdzVmbpNwILD/W+Bh65aJt0/TYbX3FA5w6crCaYAM0G3yhozJYN4fH6cyrn l0IEaUUPxkUHmDiftdfF60w1POIQ32axJnBBc0KDfeGJrsG+ctyaLB1JqtsREXqEyubJhn8lTwkfi gsS20GlpyWe7LDx2MH8FcpDV018ykrRhCp/wL0Y9DmT6FYiui5d2bjToPehnAcXaCk9oljOYZWvLo ntWhTh/pm4DURLZH1FxT3ctPH3eBAXJ0hL3+xatN1/o4rhabKnfvBkjPaWnzvSjH6lPdBNx64Ia6i KYhJ9OOBel/7B1c+hPRg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9c-00CgUE-Ci; Sat, 23 Oct 2021 11:25:36 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9E-00CgNM-1o; Sat, 23 Oct 2021 11:25:13 +0000 X-UUID: ebd0b39309314dfdade58e16cc70435b-20211023 X-UUID: ebd0b39309314dfdade58e16cc70435b-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1138835637; Sat, 23 Oct 2021 04:25:03 -0700 Received: from mtkexhb02.mediatek.inc (172.21.101.103) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:06 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb02.mediatek.inc (172.21.101.103) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:14:53 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:53 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 05/13] soc: mediatek: Add command for APU SMC call Date: Sat, 23 Oct 2021 19:14:01 +0800 Message-ID: <20211023111409.30463-6-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_042512_139545_C9E85E8C X-CRM114-Status: UNSURE ( 8.84 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add command for APU SMC call. The tinyys start and stop sequence will porcess in ATF. Signed-off-by: Flora Fu --- include/linux/soc/mediatek/mtk_sip_svc.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/linux/soc/mediatek/mtk_sip_svc.h b/include/linux/soc/mediatek/mtk_sip_svc.h index 082398e0cfb1..ce44d26a3922 100644 --- a/include/linux/soc/mediatek/mtk_sip_svc.h +++ b/include/linux/soc/mediatek/mtk_sip_svc.h @@ -22,4 +22,6 @@ ARM_SMCCC_CALL_VAL(ARM_SMCCC_FAST_CALL, MTK_SIP_SMC_CONVENTION, \ ARM_SMCCC_OWNER_SIP, fn_id) +/* APUSYS SMC call */ +#define MTK_SIP_APUSYS_CONTROL MTK_SIP_SMC_CMD(0x51E) #endif From patchwork Sat Oct 23 11:14:02 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579515 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 60971C433FE for ; Sat, 23 Oct 2021 11:17:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 2EDEA6052B for ; Sat, 23 Oct 2021 11:17:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 2EDEA6052B Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=dvQoQt1YFnxh16HFHYPC01xORANKj1503PA8vuuvI0k=; b=WJ6usNmzRPuY21 ZZVAn9VXiEDcr5GZwh1bqfv1sQwod8L2yECEtLbTe9cRVddBydfWkmEJFrRPn63r5kxA3j764DXHO hhrQSud9QIAcJlBwv94avq7nnSI2RziaxcfbBhvmklQ6g/8ThcKotQP6dnxbOwLpnR9Rpv6wlvKC/ 2q6wJetqPt75r3IxLh05Rj36zQc2+AC+vUuu55zAiQ2nbuCf6zp44CJ4jrPrlKgVbD24mZQXhwM/i X1KFLc70qbvBomnSwjw1e4EAEOK9vd/yqJ3whrduxMZNXxMQNI14XG+S0Kj+3C/Y9+bsl+EyObdPR 4MzqmsblmLVMZ6hcK49Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF0Q-00Ccvf-0d; Sat, 23 Oct 2021 11:16:06 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzL-00CcMB-Ky; Sat, 23 Oct 2021 11:15:01 +0000 X-UUID: be6ad2ec2277401fadd41eedda5535b8-20211023 X-UUID: be6ad2ec2277401fadd41eedda5535b8-20211023 Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 79138695; Sat, 23 Oct 2021 04:14:57 -0700 Received: from mtkmbs10n1.mediatek.inc (172.21.101.34) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:55 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Sat, 23 Oct 2021 19:14:54 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:54 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 06/13] soc: mediatek: apu: Add apu core driver Date: Sat, 23 Oct 2021 19:14:02 +0800 Message-ID: <20211023111409.30463-7-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041459_720435_C5D1E585 X-CRM114-Status: GOOD ( 22.42 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add apu core driver. The core driver will init the reset part of apu functions. Signed-off-by: Flora Fu --- drivers/soc/mediatek/Kconfig | 18 +++++ drivers/soc/mediatek/apusys/Makefile | 3 + drivers/soc/mediatek/apusys/apu-core.c | 91 ++++++++++++++++++++++++++ drivers/soc/mediatek/apusys/apu-core.h | 11 ++++ 4 files changed, 123 insertions(+) create mode 100644 drivers/soc/mediatek/apusys/apu-core.c create mode 100644 drivers/soc/mediatek/apusys/apu-core.h diff --git a/drivers/soc/mediatek/Kconfig b/drivers/soc/mediatek/Kconfig index d9bac2710494..074b0cf24c44 100644 --- a/drivers/soc/mediatek/Kconfig +++ b/drivers/soc/mediatek/Kconfig @@ -24,6 +24,24 @@ config MTK_APU_PM APU power domain shall be enabled before accessing the internal sub modules. +config MTK_APU + tristate "MediaTek APUSYS Support" + select REGMAP + select MTK_APU_PM + select MTK_SCP + help + Say yes here to add support for the APU tinysys. The tinsys is + running on a micro processor in APU. + Its firmware is load and boot from Kernel side. Kernel and tinysys use + IPI to tx/rx messages. + +config MTK_APU_DEBUG + tristate "MediaTek APUSYS debug functions" + depends on MTK_APU + help + Say yes here to enalbe debug on APUSYS. + Disable it if you don't need them. + config MTK_CMDQ tristate "MediaTek CMDQ Support" depends on ARCH_MEDIATEK || COMPILE_TEST diff --git a/drivers/soc/mediatek/apusys/Makefile b/drivers/soc/mediatek/apusys/Makefile index 8821c0f0b7b7..6b5249ec7064 100644 --- a/drivers/soc/mediatek/apusys/Makefile +++ b/drivers/soc/mediatek/apusys/Makefile @@ -1,2 +1,5 @@ # SPDX-License-Identifier: GPL-2.0 obj-$(CONFIG_MTK_APU_PM) += mtk-apu-pm.o + +obj-$(CONFIG_MTK_APU) += apu.o +apu-objs += apu-core.o diff --git a/drivers/soc/mediatek/apusys/apu-core.c b/drivers/soc/mediatek/apusys/apu-core.c new file mode 100644 index 000000000000..c1db2394307f --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-core.c @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include + +#include "apu-core.h" + +#define APUSYS_DEV_NAME "apusys" + +static struct apusys_core_info g_core_info; + +/* + * init function at other modulses + * call init function in order at apu.ko init stage + */ +static int (*apusys_init_func[])(struct apusys_core_info *) = { +}; + +/* + * exit function at other modulses + * call exit function in order at apu.ko exit stage + */ +static void (*apusys_exit_func[])(void) = { +}; + +static void create_dbg_root(void) +{ + g_core_info.dbg_root = debugfs_create_dir(APUSYS_DEV_NAME, NULL); + + /* check dbg root create status */ + if (IS_ERR_OR_NULL(g_core_info.dbg_root)) + pr_info("failed to create debug dir.\n"); +} + +static void destroy_dbg_root(void) +{ + debugfs_remove_recursive(g_core_info.dbg_root); +} + +static int __init apusys_init(void) +{ + int i, j, ret = 0; + int func_num = sizeof(apusys_init_func) / sizeof(int *); + + /* init apusys_dev */ + create_dbg_root(); + + /* call init func */ + for (i = 0; i < func_num; i++) { + if (!apusys_init_func[i]) + break; + + ret = apusys_init_func[i](&g_core_info); + if (ret) { + pr_info("init function(%d) fail(%d)", i, ret); + + /* exit device */ + for (j = i - 1; j >= 0; j--) + apusys_exit_func[j](); + + destroy_dbg_root(); + break; + } + } + + return 0; +} + +static void __exit apusys_exit(void) +{ + int func_num = sizeof(apusys_exit_func) / sizeof(int *); + int i; + + /* call release func */ + for (i = 0; i < func_num; i++) { + if (!apusys_exit_func[i]) + break; + + apusys_exit_func[i](); + } + + destroy_dbg_root(); +} + +module_init(apusys_init); +module_exit(apusys_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/soc/mediatek/apusys/apu-core.h b/drivers/soc/mediatek/apusys/apu-core.h new file mode 100644 index 000000000000..bac730bbc7ea --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-core.h @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ +#ifndef APU_CORE_H +#define APU_CORE_H + +struct apusys_core_info { + struct dentry *dbg_root; +}; +#endif From patchwork Sat Oct 23 11:14:03 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579577 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id F03B9C433EF for ; Sat, 23 Oct 2021 11:27:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id BCFD060E05 for ; Sat, 23 Oct 2021 11:27:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org BCFD060E05 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=k/N4KoKcCJTbPj3gP6Qv9z+O92XPHuwAFeJcZyOh9Fo=; b=3LGDGCrlaRiL5Y NJQnz4BTgIVb6kl/4ygMZK/NIZIqzYOdpiWgDgsGZ2HGmBXGhGhT3wXBSgqKi00mT/Z7+lCvjMrX5 Fl3Q/Xu5jvGmPUlM08K53iXuCs8WeGXJ4fnews65WgQ056AAd7iuptAbBZaZsO3T7U5kIIQA1v81Y Hxbj4WIRuznuA+fJmburRnpp3HAOPGLwOWvEQuZNLDwXb6bSHbrqXoeeFHiHytAZmbfQ2uwvr0QBA CbdAKngP26WMqM3/IMeNtjmti17BIFYBZSwC/TCHwfg8KV9txygVoAruMqxLgoXvZMKbGiOrlhOD5 EJ3ByehAgXg7dRmP6CtA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meFA4-00CghT-3L; Sat, 23 Oct 2021 11:26:04 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9F-00CgNM-E5; Sat, 23 Oct 2021 11:25:17 +0000 X-UUID: fb043466ba65450392d8c81a2ac0df90-20211023 X-UUID: fb043466ba65450392d8c81a2ac0df90-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 149297955; Sat, 23 Oct 2021 04:25:03 -0700 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:02 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:14:55 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:55 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 07/13] soc: mediatek: apu: Add apu power driver Date: Sat, 23 Oct 2021 19:14:03 +0800 Message-ID: <20211023111409.30463-8-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_042513_609136_D08335A3 X-CRM114-Status: GOOD ( 27.00 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org APU power driver support for subsys clock and regulator controller. It has device link to iommu-apu and apusys-rv tinysys driver to ensure the power state is ready for hardware in sub modules. Signed-off-by: Flora Fu --- drivers/soc/mediatek/apusys/Makefile | 4 + drivers/soc/mediatek/apusys/apu-core.c | 2 + drivers/soc/mediatek/apusys/apu-core.h | 3 + drivers/soc/mediatek/apusys/apu-pwr-dbg.c | 167 ++++++ drivers/soc/mediatek/apusys/apu-pwr-ipi.c | 377 ++++++++++++++ drivers/soc/mediatek/apusys/apu-pwr.c | 599 ++++++++++++++++++++++ drivers/soc/mediatek/apusys/apu-pwr.h | 260 ++++++++++ 7 files changed, 1412 insertions(+) create mode 100644 drivers/soc/mediatek/apusys/apu-pwr-dbg.c create mode 100644 drivers/soc/mediatek/apusys/apu-pwr-ipi.c create mode 100644 drivers/soc/mediatek/apusys/apu-pwr.c create mode 100644 drivers/soc/mediatek/apusys/apu-pwr.h diff --git a/drivers/soc/mediatek/apusys/Makefile b/drivers/soc/mediatek/apusys/Makefile index 6b5249ec7064..8c61ed8e2c04 100644 --- a/drivers/soc/mediatek/apusys/Makefile +++ b/drivers/soc/mediatek/apusys/Makefile @@ -3,3 +3,7 @@ obj-$(CONFIG_MTK_APU_PM) += mtk-apu-pm.o obj-$(CONFIG_MTK_APU) += apu.o apu-objs += apu-core.o + +apu-objs += apu-pwr.o +apu-objs += apu-pwr-ipi.o +apu-$(CONFIG_MTK_APU_DEBUG) += apu-pwr-dbg.o diff --git a/drivers/soc/mediatek/apusys/apu-core.c b/drivers/soc/mediatek/apusys/apu-core.c index c1db2394307f..069e18af7a5b 100644 --- a/drivers/soc/mediatek/apusys/apu-core.c +++ b/drivers/soc/mediatek/apusys/apu-core.c @@ -18,6 +18,7 @@ static struct apusys_core_info g_core_info; * call init function in order at apu.ko init stage */ static int (*apusys_init_func[])(struct apusys_core_info *) = { + apu_power_drv_init, }; /* @@ -25,6 +26,7 @@ static int (*apusys_init_func[])(struct apusys_core_info *) = { * call exit function in order at apu.ko exit stage */ static void (*apusys_exit_func[])(void) = { + apu_power_drv_exit, }; static void create_dbg_root(void) diff --git a/drivers/soc/mediatek/apusys/apu-core.h b/drivers/soc/mediatek/apusys/apu-core.h index bac730bbc7ea..77f1b39424d1 100644 --- a/drivers/soc/mediatek/apusys/apu-core.h +++ b/drivers/soc/mediatek/apusys/apu-core.h @@ -8,4 +8,7 @@ struct apusys_core_info { struct dentry *dbg_root; }; + +int apu_power_drv_init(struct apusys_core_info *info); +void apu_power_drv_exit(void); #endif diff --git a/drivers/soc/mediatek/apusys/apu-pwr-dbg.c b/drivers/soc/mediatek/apusys/apu-pwr-dbg.c new file mode 100644 index 000000000000..ee81271cbb2c --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-pwr-dbg.c @@ -0,0 +1,167 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "apu-pwr.h" + +#define DEBUG_MAX_ARGS_NUM (5) + +struct dentry *apu_power_debugfs; + +static int apu_power_set_parameter(struct apu_power *apupwr, + enum APU_POWER_PARAM param, + u32 argc, u32 *args) +{ + struct device *dev = apupwr->dev; + int ret = 0; + + switch (param) { + case POWER_PARAM_FIX_OPP: + if (args[0] == 0) { + apu_update_fixed_opp_by_reg(dev, 0xffffffff); + apu_power_notify_uP_opp_limit(apupwr, + OPP_LIMIT_FIX_OPP); + } + break; + case POWER_PARAM_DVFS_DEBUG: + if (args[0] >= 0 && args[0] <= 0xffffffff) { + apu_update_fixed_opp_by_reg(dev, args[0]); + apu_power_notify_uP_opp_limit(apupwr, + OPP_LIMIT_DVFS_DEBUG); + } + break; + case POWER_PARAM_ULOG_LEVEL: + ret = (argc == 1) ? 0 : -EINVAL; + if (ret) { + dev_err(dev, + "invalid argument, expected:1, received:%d\n", + argc); + goto out; + } + apupwr->dbg_option = POWER_PARAM_ULOG_LEVEL; + apupwr->ulog_level = args[0]; + apu_power_set_ulog_level(apupwr, args[0]); + break; + + default: + dev_err(dev, "unsupport the power parameter:%d\n", param); + break; + } + +out: + return ret; +} + +static int apu_power_dbg_show(struct seq_file *s, void *unused) +{ + struct apu_power *apupwr = (struct apu_power *)s->private; + u32 ulog_level = apupwr->ulog_level; + u32 dbg_option = apupwr->dbg_option; + + switch (dbg_option) { + case POWER_PARAM_ULOG_LEVEL: + seq_printf(s, "ulog_level = %d\n", ulog_level); + break; + default: + break; + } + + return 0; +} + +static int apu_power_dbg_open(struct inode *inode, struct file *file) +{ + return single_open(file, apu_power_dbg_show, inode->i_private); +} + +static ssize_t apu_power_dbg_write(struct file *filp, + const char __user *buffer, + size_t count, loff_t *f_pos) +{ + struct apu_power *obj = file_inode(filp)->i_private; + char *tmp, *token, *cursor; + int ret, i; + enum APU_POWER_PARAM param; + unsigned int args[DEBUG_MAX_ARGS_NUM]; + + tmp = kzalloc(count + 1, GFP_KERNEL); + if (!tmp) + return -ENOMEM; + + ret = copy_from_user(tmp, buffer, count); + if (ret) { + dev_err(obj->dev, "copy_from_user failed, ret=%d\n", ret); + goto out; + } + + tmp[count] = '\0'; + cursor = tmp; + + /* parse a command */ + token = strsep(&cursor, " "); + if (strcmp(token, "fix_opp") == 0) { + param = POWER_PARAM_FIX_OPP; + } else if (strcmp(token, "dvfs_debug") == 0) { + param = POWER_PARAM_DVFS_DEBUG; + } else if (strcmp(token, "ulog") == 0) { + param = POWER_PARAM_ULOG_LEVEL; + } else { + ret = -EINVAL; + dev_err(obj->dev, "no power param[%s]!\n", token); + goto out; + } + + /* parse arguments */ + for (i = 0; + i < DEBUG_MAX_ARGS_NUM && (token = strsep(&cursor, " ")); i++) { + ret = kstrtouint(token, 0, &args[i]); + if (ret) { + dev_err(obj->dev, "fail to parse args[%d]\n", i); + goto out; + } + } + + apu_power_set_parameter(obj, param, i, args); + ret = count; +out: + kfree(tmp); + return ret; +} + +static const struct file_operations apu_power_dbg_fops = { + .open = apu_power_dbg_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, + .write = apu_power_dbg_write, +}; + +void apu_power_debugfs_init(struct apu_power *apupwr) +{ + int ret; + + apu_power_debugfs = debugfs_create_dir("apu_power", + apupwr->dbg_root); + ret = IS_ERR_OR_NULL(apu_power_debugfs); + if (ret) { + dev_err(apupwr->dev, "failed to create debug dir.\n"); + apu_power_debugfs = NULL; + } + + debugfs_create_file("power", (0644), + apu_power_debugfs, apupwr, &apu_power_dbg_fops); +} + +void apu_power_debugfs_exit(void) +{ + debugfs_remove_recursive(apu_power_debugfs); +} diff --git a/drivers/soc/mediatek/apusys/apu-pwr-ipi.c b/drivers/soc/mediatek/apusys/apu-pwr-ipi.c new file mode 100644 index 000000000000..c7bbcd1de73d --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-pwr-ipi.c @@ -0,0 +1,377 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu-pwr.h" + +#define APU_TX_MSG_TIMEOUT 1000 +#define RX_MAGIC0 0xaabb +#define RX_MAGIC1 0xccdd + +#define to_rpmsg_driver(__drv) container_of(__drv, struct rpmsg_driver, drv) +#define tx_to_apu_power(__d) \ + container_of(__d, struct apu_power, tx_rpmsg_driver) +#define rx_to_apu_power(__d) \ + container_of(__d, struct apu_power, rx_rpmsg_driver) + +struct apu_power_rpmsg { + struct rpmsg_device *rpdev; + struct rpmsg_endpoint *ept; + struct mutex lock; /* wait remote msg */ + struct completion comp; + int initialized; + struct power_ipi_cmd_reply ipi_rply; +}; + +static int apu_power_tx_send(struct apu_power *apupwr, + struct power_cmd_AP *pcmd, + u32 *data0, u32 *data1) +{ + struct rpmsg_device *rpdev = apupwr->tx_rpmsg_device; + struct apu_power_rpmsg *power_rpmsg = dev_get_drvdata(&rpdev->dev); + struct power_ipi_cmd_AP ipi_cmd_send; + struct timespec64 ts64; + unsigned long timeout = msecs_to_jiffies(APU_TX_MSG_TIMEOUT); + u64 timestamp; + int ret = 0; + + if (!power_rpmsg || !power_rpmsg->initialized) { + dev_err(&rpdev->dev, "%s: rpmsg not valid\n", __func__); + ret = -EINVAL; + return ret; + } + + memset(&ipi_cmd_send, 0, sizeof(struct power_ipi_cmd_AP)); + ktime_get_real_ts64(&ts64); + timestamp = ((ts64.tv_sec & 0xFFF) * USEC_PER_SEC) + + (ts64.tv_nsec / NSEC_PER_USEC); + ipi_cmd_send.cmd_sn = (u32)timestamp; + ipi_cmd_send.pwr_cmd = *pcmd; + + /* transport normal raw data */ + ipi_cmd_send.data0 = *data0; + ipi_cmd_send.data1 = *data1; + + mutex_lock(&power_rpmsg->lock); + reinit_completion(&power_rpmsg->comp); + + ret = rpmsg_send(power_rpmsg->ept, + (void *)&ipi_cmd_send, sizeof(ipi_cmd_send)); + if (ret) { + dev_err(&rpdev->dev, + "%s: failed to send msg to remote, ret=%d\n", + __func__, ret); + goto out; + } + + ret = wait_for_completion_interruptible_timeout(&power_rpmsg->comp, + timeout); + if (ret <= 0) { + dev_err(&rpdev->dev, + "%s waiting for ack interrupted or timeout, ret=%d\n", + __func__, ret); + goto out; + } + +out: + mutex_unlock(&power_rpmsg->lock); + return ret; +} + +void apu_power_set_ulog_level(struct apu_power *apupwr, + int level) +{ + struct power_cmd_AP pwr_cmd; + u32 data0; + u32 data1; + + memset(&pwr_cmd, 0, sizeof(struct power_cmd_AP)); + memset(&data0, 0, sizeof(u32)); + memset(&data1, 0, sizeof(u32)); + + pwr_cmd.req_id = CHANGE_LOG_LEVEL; + data0 = level; + apu_power_tx_send(apupwr, &pwr_cmd, &data0, &data1); +} + +void apu_power_notify_uP_opp_limit(struct apu_power *apupwr, + enum request_id_AP req) +{ + struct power_cmd_AP pwr_cmd; + u32 data0; + u32 data1; + + memset(&pwr_cmd, 0, sizeof(struct power_cmd_AP)); + memset(&data0, 0, sizeof(u32)); + memset(&data1, 0, sizeof(u32)); + + pwr_cmd.req_id = req; + switch (pwr_cmd.req_id) { + case OPP_LIMIT_THERM: + case OPP_LIMIT_FIX_OPP: + case OPP_LIMIT_DVFS_DEBUG: + break; + default: + return; + } + + apu_power_tx_send(apupwr, &pwr_cmd, &data0, &data1); +} + +static int apu_power_rx_callback(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 src) +{ + struct apu_power_rpmsg *power_rpmsg = dev_get_drvdata(&rpdev->dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct apu_power *apupwr = rx_to_apu_power(rpdrv); + int ret = 0; + struct device *dev = &rpdev->dev; + struct power_ipi_cmd_uP *received_data = NULL; + struct power_ipi_cmd_reply reply_data; + static u32 prev_cmd_sn; + u32 cmd_sn; + struct power_cmd_uP pwr_cmd; + u32 data0; + u32 data1; + + if (!len) { + dev_warn(dev, "apu power rpmsg received empty cmd"); + return -EINVAL; + } + + received_data = data; + cmd_sn = received_data->cmd_sn; + pwr_cmd = received_data->pwr_cmd; + data0 = received_data->data0; + data1 = received_data->data1; + + if (cmd_sn != prev_cmd_sn) + prev_cmd_sn = cmd_sn; + else + return -EINVAL; + + switch (pwr_cmd.req_id) { + case CHANGE_DEV_CLKSRC: + /* + * received_data.data0 : user + * received_data.data1 : on + */ + if (data1 == 1) + ret = apu_enable_dev_clksrc(apupwr->dev, data0); + else + apu_disable_dev_clksrc(apupwr->dev, data0); + break; + case CHANGE_DEV_CLOCK: + /* + * received_data.data0 : target_freq + * received_data.data1 : volt_domain + */ + ret = apu_set_clk_freq(apupwr->dev, data0, data1); + break; + case CHANGE_SYS_VCORE: + /* + * received_data.data0 : user + * received_data.data1 : vcore_opp + */ + ret = apu_config_vcore_volt(apupwr->dev, data1); + break; + default: + dev_err(dev, "invalid request id:%d (cmd_sn:0x%08x)\n", + pwr_cmd.req_id, + cmd_sn); + return -EINVAL; + } + + /* prepare reply data to remote */ + memset(&reply_data, 0, sizeof(struct power_ipi_cmd_reply)); + reply_data.cmd_sn = cmd_sn; + reply_data.data0 = RX_MAGIC0; + reply_data.data1 = RX_MAGIC1; + + /* send reply data to remote (no blocking) */ + ret = rpmsg_send(power_rpmsg->ept, + (void *)&reply_data, sizeof(reply_data)); + if (ret) + dev_err(dev, "%s: failed to send msg to remote, ret=%d\n", + __func__, ret); + + return ret; +} + +static int apu_power_rx_probe(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + struct rpmsg_channel_info chinfo = {}; + struct rpmsg_endpoint *ept; + struct apu_power_rpmsg *power_rpmsg; + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct apu_power *apupwr = rx_to_apu_power(rpdrv); + + power_rpmsg = devm_kzalloc(dev, + sizeof(struct apu_power_rpmsg), GFP_KERNEL); + if (!power_rpmsg) + return -ENOMEM; + + strscpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); + chinfo.src = rpdev->src; + chinfo.dst = RPMSG_ADDR_ANY; + ept = rpmsg_create_ept(rpdev, apu_power_rx_callback, NULL, chinfo); + if (!ept) { + dev_err(dev, "failed to create ept\n"); + return -ENODEV; + } + + init_completion(&power_rpmsg->comp); + mutex_init(&power_rpmsg->lock); + power_rpmsg->ept = ept; + power_rpmsg->rpdev = rpdev; + power_rpmsg->initialized = 1; + memset(&power_rpmsg->ipi_rply, 0x0, + sizeof(struct power_ipi_cmd_reply)); + dev_set_drvdata(dev, power_rpmsg); + apupwr->rx_rpmsg_device = rpdev; + + return 0; +} + +static void apu_power_rx_remove(struct rpmsg_device *rpdev) +{ + struct apu_power_rpmsg *power_rpmsg = dev_get_drvdata(&rpdev->dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct apu_power *apupwr = rx_to_apu_power(rpdrv); + + rpmsg_destroy_ept(power_rpmsg->ept); + apupwr->rx_rpmsg_device = NULL; +} + +static int apu_power_tx_callback(struct rpmsg_device *rpdev, void *data, + int len, void *priv, u32 src) +{ + struct device *dev = &rpdev->dev; + struct apu_power_rpmsg *power_rpmsg = dev_get_drvdata(&rpdev->dev); + + if (!len) { + dev_err(dev, "apu power rpmsg received empty rply"); + complete(&power_rpmsg->comp); + return -EINVAL; + } + + memcpy(&power_rpmsg->ipi_rply, data, + sizeof(struct power_ipi_cmd_reply)); + complete(&power_rpmsg->comp); + + return 0; +} + +static int apu_power_tx_probe(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + struct rpmsg_channel_info chinfo = {}; + struct rpmsg_endpoint *ept; + struct apu_power_rpmsg *power_rpmsg; + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct apu_power *apupwr = tx_to_apu_power(rpdrv); + + power_rpmsg = devm_kzalloc(dev, + sizeof(struct apu_power_rpmsg), GFP_KERNEL); + if (!power_rpmsg) + return -ENOMEM; + + strscpy(chinfo.name, rpdev->id.name, RPMSG_NAME_SIZE); + chinfo.src = rpdev->src; + chinfo.dst = RPMSG_ADDR_ANY; + ept = rpmsg_create_ept(rpdev, apu_power_tx_callback, NULL, chinfo); + if (!ept) { + dev_err(dev, "failed to create ept\n"); + return -ENODEV; + } + + init_completion(&power_rpmsg->comp); + mutex_init(&power_rpmsg->lock); + power_rpmsg->ept = ept; + power_rpmsg->rpdev = rpdev; + power_rpmsg->initialized = 1; + memset(&power_rpmsg->ipi_rply, 0x0, + sizeof(struct power_ipi_cmd_reply)); + dev_set_drvdata(dev, power_rpmsg); + apupwr->tx_rpmsg_device = rpdev; + + return 0; +} + +static void apu_power_tx_remove(struct rpmsg_device *rpdev) +{ + struct apu_power_rpmsg *power_rpmsg = dev_get_drvdata(&rpdev->dev); + struct rpmsg_driver *rpdrv = to_rpmsg_driver(rpdev->dev.driver); + struct apu_power *apupwr = tx_to_apu_power(rpdrv); + + rpmsg_destroy_ept(power_rpmsg->ept); + apupwr->tx_rpmsg_device = NULL; +} + +static const struct of_device_id apupwr_tx_rpmsg_of_match[] = { + { .compatible = "mediatek,apupwr-tx-rpmsg"}, + {}, +}; + +static const struct of_device_id apupwr_rx_rpmsg_of_match[] = { + { .compatible = "mediatek,apupwr-rx-rpmsg"}, + {}, +}; + +static struct rpmsg_driver pwr_tx_rpmsg_drv = { + .drv = { + .name = "apupwr-tx-rpmsg", + .owner = THIS_MODULE, + .of_match_table = apupwr_tx_rpmsg_of_match, + }, + .probe = apu_power_tx_probe, + .remove = apu_power_tx_remove, +}; + +static struct rpmsg_driver pwr_rx_rpmsg_drv = { + .drv = { + .name = "apupwr-rx-rpmsg", + .owner = THIS_MODULE, + .of_match_table = apupwr_rx_rpmsg_of_match, + }, + .probe = apu_power_rx_probe, + .remove = apu_power_rx_remove, +}; + +int apu_power_ipi_init(struct apu_power *apupwr) +{ + int ret = 0; + + apupwr->tx_rpmsg_driver = pwr_tx_rpmsg_drv; + ret = register_rpmsg_driver(&apupwr->tx_rpmsg_driver); + if (ret) + return ret; + + apupwr->rx_rpmsg_driver = pwr_rx_rpmsg_drv; + ret = register_rpmsg_driver(&apupwr->rx_rpmsg_driver); + if (ret) + goto err; + + return 0; +err: + unregister_rpmsg_driver(&apupwr->tx_rpmsg_driver); + return ret; +} + +void apu_power_ipi_exit(struct apu_power *apupwr) +{ + unregister_rpmsg_driver(&apupwr->tx_rpmsg_driver); + unregister_rpmsg_driver(&apupwr->rx_rpmsg_driver); +} diff --git a/drivers/soc/mediatek/apusys/apu-pwr.c b/drivers/soc/mediatek/apusys/apu-pwr.c new file mode 100644 index 000000000000..ef0df1469a76 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-pwr.c @@ -0,0 +1,599 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu-core.h" +#include "apu-pwr.h" + +static const char *mt8192_apu_clks[CLK_NUM] = { + [CLK_TOP_DSP_SEL] = "clk_top_dsp_sel", + [CLK_TOP_DSP1_SEL] = "clk_top_dsp1_sel", + [CLK_TOP_DSP1_NPUPLL_SEL] = "clk_top_dsp1_npupll_sel", + [CLK_TOP_DSP2_SEL] = "clk_top_dsp2_sel", + [CLK_TOP_DSP2_NPUPLL_SEL] = "clk_top_dsp2_npupll_sel", + [CLK_TOP_DSP5_SEL] = "clk_top_dsp5_sel", + [CLK_TOP_DSP5_APUPLL_SEL] = "clk_top_dsp5_apupll_sel", + [CLK_TOP_IPU_IF_SEL] = "clk_top_ipu_if_sel", + [CLK_CLK26M] = "clk_top_clk26m", + [CLK_TOP_MAINPLL_D4_D2] = "clk_top_mainpll_d4_d2", + [CLK_TOP_UNIVPLL_D4_D2] = "clk_top_univpll_d4_d2", + [CLK_TOP_UNIVPLL_D6_D2] = "clk_top_univpll_d6_d2", + [CLK_TOP_MMPLL_D6] = "clk_top_mmpll_d6", + [CLK_TOP_MMPLL_D5] = "clk_top_mmpll_d5", + [CLK_TOP_MMPLL_D4] = "clk_top_mmpll_d4", + [CLK_TOP_UNIVPLL_D5] = "clk_top_univpll_d5", + [CLK_TOP_UNIVPLL_D4] = "clk_top_univpll_d4", + [CLK_TOP_UNIVPLL_D3] = "clk_top_univpll_d3", + [CLK_TOP_MAINPLL_D6] = "clk_top_mainpll_d6", + [CLK_TOP_MAINPLL_D4] = "clk_top_mainpll_d4", + [CLK_TOP_MAINPLL_D3] = "clk_top_mainpll_d3", + [CLK_TOP_TVDPLL] = "clk_top_tvdpll_ck", + [CLK_TOP_APUPLL] = "clk_top_apupll_ck", + [CLK_TOP_NPUPLL] = "clk_top_npupll_ck", + [CLK_APMIXED_APUPLL] = "clk_apmixed_apupll_rate", + [CLK_APMIXED_NPUPLL] = "clk_apmixed_npupll_rate", +}; + +static struct dentry *dbg_root; + +static void apu_power_reg_init(struct device *dev) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + const struct apupwr_plat_reg *plat_regs; + void __iomem *spare_base; + + spare_base = apupwr->spare_base; + plat_regs = apupwr->plat_data->plat_regs; + + writel(0xffffffff, spare_base + plat_regs->opp_user); + writel(0xffffffff, spare_base + plat_regs->opp_curr); + writel(0xffffffff, spare_base + plat_regs->opp_thermal); +} + +static int apu_power_regulator_init(struct device *dev) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret; + + apupwr->vvpu_reg_id = devm_regulator_get_optional(dev, "vvpu"); + if (IS_ERR(apupwr->vvpu_reg_id)) { + ret = PTR_ERR(apupwr->vvpu_reg_id); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get vvpu regulator"); + + return ret; + } + + apupwr->vmdla_reg_id = devm_regulator_get_optional(dev, "vmdla"); + if (IS_ERR(apupwr->vmdla_reg_id)) { + ret = PTR_ERR(apupwr->vmdla_reg_id); + if (ret != -EPROBE_DEFER) + dev_err(dev, "Failed to get vmdla regulator"); + + return ret; + } + + ret = regulator_enable(apupwr->vvpu_reg_id); + if (ret) + return ret; + + ret = regulator_enable(apupwr->vmdla_reg_id); + if (ret) + return ret; + + return ret; +} + +static void apu_power_regulator_exit(struct device *dev) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + + if (apupwr->vvpu_reg_id) { + if (regulator_disable(apupwr->vvpu_reg_id)) + dev_err(apupwr->dev, "disable vvpu fail\n"); + } + + if (apupwr->vmdla_reg_id) { + if (regulator_disable(apupwr->vmdla_reg_id)) + dev_err(apupwr->dev, "disable mdla fail\n"); + } +} + +static int mt8192_apu_clock_init(struct device *dev) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int i = 0; + + apupwr->clk = devm_kcalloc(dev, CLK_NUM, + sizeof(*apupwr->clk), GFP_KERNEL); + if (!apupwr->clk) + return -ENOMEM; + + for (i = 0; i < CLK_NUM; i++) { + apupwr->clk[i] = devm_clk_get(dev, mt8192_apu_clks[i]); + if (IS_ERR(apupwr->clk[i])) { + dev_warn(dev, "%s devm_clk_get %s fail\n", + __func__, + mt8192_apu_clks[i]); + apupwr->clk[i] = NULL; + } + } + + return 0; +} + +static int mt8192_enalbe_vpu_clksrc(struct apu_power *apupwr) +{ + int ret; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP1_SEL]); + if (ret) + goto dsp1_sel_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP2_SEL]); + if (ret) + goto dsp2_sel_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_NPUPLL]); + if (ret) + goto npupll_sel_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP1_NPUPLL_SEL]); + if (ret) + goto dsp1_npupll_sel_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP2_NPUPLL_SEL]); + if (ret) + goto dsp2_npupll_sel_err; + + return 0; + +dsp2_npupll_sel_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP1_NPUPLL_SEL]); +dsp1_npupll_sel_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_NPUPLL]); +npupll_sel_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP2_SEL]); +dsp2_sel_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP1_SEL]); +dsp1_sel_err: + dev_err(apupwr->dev, "failed to enable vpu clk src\n"); + return ret; +} + +static int mt8192_enalbe_mdla_clksrc(struct apu_power *apupwr) +{ + int ret; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP5_SEL]); + if (ret) + goto dsp5_sel_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_APUPLL]); + if (ret) + goto apupll_err; + + ret = clk_prepare_enable(apupwr->clk[CLK_TOP_DSP5_APUPLL_SEL]); + if (ret) + goto dsp5_apupll_sel_err; + + return 0; + +dsp5_apupll_sel_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_APUPLL]); +apupll_err: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP5_APUPLL_SEL]); +dsp5_sel_err: + dev_err(apupwr->dev, "failed to enable mdla clk src\n"); + return ret; +} + +static int mt8192_apu_enable_dev_clksrc(struct device *dev, enum DVFS_USER user) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + + switch (user) { + case VPU0: + case VPU1: + ret = mt8192_enalbe_vpu_clksrc(apupwr); + break; + case MDLA0: + ret = mt8192_enalbe_mdla_clksrc(apupwr); + break; + default: + dev_err(dev, "%s illegal DVFS_USER: %d\n", __func__, user); + ret = -EINVAL; + } + + return ret; +} + +static void mt8192_apu_disable_dev_clksrc(struct device *dev, + enum DVFS_USER user) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + + switch (user) { + case VPU0: + case VPU1: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP2_NPUPLL_SEL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP1_NPUPLL_SEL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_NPUPLL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP2_SEL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP1_SEL]); + break; + case MDLA0: + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP5_APUPLL_SEL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_APUPLL]); + clk_disable_unprepare(apupwr->clk[CLK_TOP_DSP5_SEL]); + break; + default: + dev_err(dev, "%s illegal DVFS_USER: %d\n", __func__, user); + } +} + +static struct clk *find_clk_by_domain(struct device *dev, + enum DVFS_VOLTAGE_DOMAIN domain) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + + switch (domain) { + case V_APU_CONN: + return apupwr->clk[CLK_TOP_DSP_SEL]; + + case V_VPU0: + return apupwr->clk[CLK_TOP_DSP1_SEL]; + + case V_VPU1: + return apupwr->clk[CLK_TOP_DSP2_SEL]; + + case V_MDLA0: + return apupwr->clk[CLK_TOP_DSP5_SEL]; + + case V_VCORE: + return apupwr->clk[CLK_TOP_IPU_IF_SEL]; + + default: + dev_err(dev, "%s fail to find clk !\n", __func__); + return NULL; + } +} + +static int mt8192_apu_set_clk_freq(struct device *dev, + enum DVFS_FREQ freq, + enum DVFS_VOLTAGE_DOMAIN domain) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + struct clk *clk_src = NULL; + struct clk *clk_target = NULL; + + switch (freq) { + case DVFS_FREQ_00_026000_F: + clk_src = apupwr->clk[CLK_CLK26M]; + break; + + case DVFS_FREQ_00_208000_F: + clk_src = apupwr->clk[CLK_TOP_UNIVPLL_D6_D2]; + break; + + case DVFS_FREQ_00_273000_F: + clk_src = apupwr->clk[CLK_TOP_MAINPLL_D4_D2]; + break; + + case DVFS_FREQ_00_312000_F: + clk_src = apupwr->clk[CLK_TOP_UNIVPLL_D4_D2]; + break; + + case DVFS_FREQ_00_499200_F: + clk_src = apupwr->clk[CLK_TOP_UNIVPLL_D5]; + break; + + case DVFS_FREQ_00_546000_F: + clk_src = apupwr->clk[CLK_TOP_MAINPLL_D4]; + break; + + case DVFS_FREQ_00_624000_F: + clk_src = apupwr->clk[CLK_TOP_UNIVPLL_D4]; + break; + + case DVFS_FREQ_00_687500_F: + clk_src = apupwr->clk[CLK_TOP_MMPLL_D4]; + break; + + case DVFS_FREQ_00_728000_F: + clk_src = apupwr->clk[CLK_TOP_MAINPLL_D3]; + break; + + case DVFS_FREQ_00_832000_F: + clk_src = apupwr->clk[CLK_TOP_UNIVPLL_D3]; + break; + + case DVFS_FREQ_NOT_SUPPORT: + default: + clk_src = apupwr->clk[CLK_CLK26M]; + dev_warn(dev, "%s wrong freq : %d, force assign 26M\n", + __func__, freq); + } + + clk_target = find_clk_by_domain(dev, domain); + if (clk_target) { + ret = clk_set_parent(clk_target, clk_src); + if (ret) { + dev_err(dev, "%s fail p1 fail\n", __func__); + return ret; + } + switch (domain) { + case V_VPU0: + clk_target = apupwr->clk[CLK_TOP_DSP1_NPUPLL_SEL]; + clk_src = apupwr->clk[CLK_TOP_DSP1_SEL]; + break; + + case V_VPU1: + clk_target = apupwr->clk[CLK_TOP_DSP2_NPUPLL_SEL]; + clk_src = apupwr->clk[CLK_TOP_DSP2_SEL]; + break; + + case V_MDLA0: + clk_target = apupwr->clk[CLK_TOP_DSP5_APUPLL_SEL]; + clk_src = apupwr->clk[CLK_TOP_DSP5_SEL]; + break; + + default: + break; + } + ret = clk_set_parent(clk_target, clk_src); + if (ret) { + dev_err(dev, "%s fail p2 fail\n", __func__); + return ret; + } + } + + return ret; +} + +static int apu_clock_init(struct device *dev) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + + if (apupwr->plat_data->ops->clock_init) + ret = apupwr->plat_data->ops->clock_init(dev); + + return ret; +} + +int apu_enable_dev_clksrc(struct device *dev, enum DVFS_USER user) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + + if (apupwr->plat_data->ops->enable_dev_clksrc) + ret = apupwr->plat_data->ops->enable_dev_clksrc(dev, user); + + return ret; +} + +void apu_disable_dev_clksrc(struct device *dev, enum DVFS_USER user) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + + if (apupwr->plat_data->ops->disable_dev_clksrc) + apupwr->plat_data->ops->disable_dev_clksrc(dev, user); +} + +int apu_set_clk_freq(struct device *dev, + enum DVFS_FREQ freq, + enum DVFS_VOLTAGE_DOMAIN domain) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + + if (apupwr->plat_data->ops->set_clk_freq) + ret = apupwr->plat_data->ops->set_clk_freq(dev, + freq, domain); + + return ret; +} + +void apu_update_fixed_opp_by_reg(struct device *dev, + u32 opp_limit_stat) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + const struct apupwr_plat_reg *plat_regs; + void __iomem *spare_base; + + spare_base = apupwr->spare_base; + plat_regs = apupwr->plat_data->plat_regs; + writel(opp_limit_stat, spare_base + plat_regs->opp_user); +} + +void apu_check_curr_opp_by_reg(struct device *dev, + enum DVFS_USER specify_usr) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + const struct apupwr_plat_reg *plat_regs; + void __iomem *spare_base; + u32 curr_opp_stat; + + spare_base = apupwr->spare_base; + plat_regs = apupwr->plat_data->plat_regs; + + curr_opp_stat = readl(spare_base + plat_regs->opp_curr); + dev_info(dev, "%s user:%d curr opp:%d\n", + __func__, specify_usr, curr_opp_stat); +} + +void apu_update_thermal_opp_by_reg(struct device *dev, + enum DVFS_USER user, int therm_opp) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + const struct apupwr_plat_reg *plat_regs; + void __iomem *spare_base; + u32 curr_therm_stat; + + spare_base = apupwr->spare_base; + plat_regs = apupwr->plat_data->plat_regs; + + curr_therm_stat = readl(spare_base + plat_regs->opp_thermal); + curr_therm_stat &= ~(0xf << user); + curr_therm_stat |= ((therm_opp & 0xf) << user); + + writel(curr_therm_stat, spare_base + plat_regs->opp_thermal); +} + +int apu_config_vcore_volt(struct device *dev, enum DVFS_VOLTAGE volt) +{ + struct apu_power *apupwr = dev_get_drvdata(dev); + int ret = 0; + + if (apupwr->plat_data->ops->set_vcore) + ret = apupwr->plat_data->ops->set_vcore(dev, volt); + + return ret; +} + +static int apu_power_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apu_power *apupwr; + struct resource *res; + int ret = 0; + + apupwr = devm_kzalloc(dev, sizeof(struct apu_power), GFP_KERNEL); + if (!apupwr) + return -ENOMEM; + + platform_set_drvdata(pdev, apupwr); + + apupwr->dev = &pdev->dev; + apupwr->plat_data = device_get_match_data(dev); + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "apu_spare"); + apupwr->spare_base = devm_ioremap_resource(dev, res); + if (IS_ERR(apupwr->spare_base)) { + dev_err(dev, "Unable to ioremap spare_base\n"); + apupwr->spare_base = NULL; + return PTR_ERR(apupwr->spare_base); + } + + /* prepare registers */ + apu_power_reg_init(dev); + + /* prepare regulators */ + ret = apu_power_regulator_init(dev); + if (ret) + goto err_regulator; + + /* prepare clocks */ + ret = apu_clock_init(dev); + if (ret) + goto err_regulator; + + /* debugfs */ + apupwr->dbg_root = dbg_root; + apu_power_debugfs_init(apupwr); + + /* init remote ipi channel */ + ret = apu_power_ipi_init(apupwr); + if (ret) { + dev_err(dev, "failed to rpmsg channel\n"); + goto err_exit; + } + + pm_runtime_enable(dev); + + return 0; + +err_exit: + apu_power_ipi_exit(apupwr); + apu_power_debugfs_exit(); +err_regulator: + apu_power_regulator_exit(dev); + + return ret; +} + +static int apu_power_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct apu_power *apupwr = platform_get_drvdata(pdev); + + if (!apupwr) + return -ENODEV; + + pm_runtime_disable(dev); + apu_power_ipi_exit(apupwr); + apu_power_debugfs_exit(); + apu_power_regulator_exit(dev); + return 0; +} + +static const struct apupwr_plat_reg mt8192_pwr_reg = { + .opp_user = 0x40, + .opp_thermal = 0x44, + .opp_curr = 0x48, + .opp_mask = 0xF, +}; + +static struct apupwr_plat_ops mt8192_pwr_ops = { + .clock_init = mt8192_apu_clock_init, + .enable_dev_clksrc = mt8192_apu_enable_dev_clksrc, + .disable_dev_clksrc = mt8192_apu_disable_dev_clksrc, + .set_clk_freq = mt8192_apu_set_clk_freq, + .set_vcore = NULL, +}; + +static struct apupwr_plat_data mt8192_apu_power_data = { + .dvfs_user = MDLA0, + .plat_regs = &mt8192_pwr_reg, + .ops = &mt8192_pwr_ops, +}; + +static const struct of_device_id apu_power_of_match[] = { + { + .compatible = "mediatek,mt8192-apu-power", + .data = &mt8192_apu_power_data + }, { + /* Terminator */ + }, +}; +MODULE_DEVICE_TABLE(of, apu_power_of_match); + +static struct platform_driver apu_power_driver = { + .probe = apu_power_probe, + .remove = apu_power_remove, + .driver = { + .name = "apusys_power", + .of_match_table = of_match_ptr(apu_power_of_match), + }, +}; + +int apu_power_drv_init(struct apusys_core_info *info) +{ + dbg_root = info->dbg_root; + return platform_driver_register(&apu_power_driver); +} + +void apu_power_drv_exit(void) +{ + platform_driver_unregister(&apu_power_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("apu power driver"); diff --git a/drivers/soc/mediatek/apusys/apu-pwr.h b/drivers/soc/mediatek/apusys/apu-pwr.h new file mode 100644 index 000000000000..4b6d90d5f206 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-pwr.h @@ -0,0 +1,260 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef APU_PWR_H +#define APU_PWR_H + +#include +#include + +enum DVFS_USER { + VPU0 = 0, + VPU1, + MDLA0, + MDLA1, + APUSYS_DVFS_USER_NUM, +}; + +enum DVFS_VOLTAGE_DOMAIN { + V_VPU0 = 0, + V_VPU1, + V_MDLA0, + V_APU_CONN, + V_VCORE, + APUSYS_BUCK_DOMAIN_NUM, +}; + +enum DVFS_USER_TYPE { + TYPE_VPU, + TYPE_MDLA, + DVFS_USER_TYPE_NUM, + TYPE_UNKNOWN, +}; + +/* mt8192 apu clocks*/ +enum { + CLK_TOP_DSP_SEL = 0, + CLK_TOP_DSP1_SEL, + CLK_TOP_DSP1_NPUPLL_SEL, + CLK_TOP_DSP2_SEL, + CLK_TOP_DSP2_NPUPLL_SEL, + CLK_TOP_DSP5_SEL, + CLK_TOP_DSP5_APUPLL_SEL, + CLK_TOP_IPU_IF_SEL, + CLK_CLK26M, + CLK_TOP_MAINPLL_D4_D2, + CLK_TOP_UNIVPLL_D4_D2, + CLK_TOP_UNIVPLL_D6_D2, + CLK_TOP_MMPLL_D6, + CLK_TOP_MMPLL_D5, + CLK_TOP_MMPLL_D4, + CLK_TOP_UNIVPLL_D5, + CLK_TOP_UNIVPLL_D4, + CLK_TOP_UNIVPLL_D3, + CLK_TOP_MAINPLL_D6, + CLK_TOP_MAINPLL_D4, + CLK_TOP_MAINPLL_D3, + CLK_TOP_TVDPLL, + CLK_TOP_APUPLL, + CLK_TOP_NPUPLL, + CLK_APMIXED_APUPLL, + CLK_APMIXED_NPUPLL, + CLK_NUM +}; + +enum DVFS_VOLTAGE { + DVFS_VOLT_NOT_SUPPORT = 0, + DVFS_VOLT_00_550000_V = 550000, + DVFS_VOLT_00_575000_V = 575000, + DVFS_VOLT_00_600000_V = 600000, + DVFS_VOLT_00_650000_V = 650000, + DVFS_VOLT_00_700000_V = 700000, + DVFS_VOLT_00_725000_V = 725000, + DVFS_VOLT_00_750000_V = 750000, + DVFS_VOLT_00_775000_V = 775000, + DVFS_VOLT_00_800000_V = 800000, + DVFS_VOLT_00_825000_V = 825000, + DVFS_VOLT_MAX = 825000 + 1, +}; + +enum DVFS_FREQ { + DVFS_FREQ_NOT_SUPPORT = 0, + DVFS_FREQ_00_026000_F = 26000, + DVFS_FREQ_00_208000_F = 208000, + DVFS_FREQ_00_273000_F = 273000, + DVFS_FREQ_00_312000_F = 312000, + DVFS_FREQ_00_499200_F = 499200, + DVFS_FREQ_00_525000_F = 525000, + DVFS_FREQ_00_546000_F = 546000, + DVFS_FREQ_00_594000_F = 594000, + DVFS_FREQ_00_624000_F = 624000, + DVFS_FREQ_00_688000_F = 688000, + DVFS_FREQ_00_687500_F = 687500, + DVFS_FREQ_00_728000_F = 728000, + DVFS_FREQ_00_800000_F = 800000, + DVFS_FREQ_00_832000_F = 832000, + DVFS_FREQ_00_960000_F = 960000, + DVFS_FREQ_00_1100000_F = 1100000, + DVFS_FREQ_MAX, +}; + +enum APU_POWER_PARAM { + POWER_PARAM_FIX_OPP, + POWER_PARAM_DVFS_DEBUG, + POWER_PARAM_GET_POWER_REG, + POWER_PARAM_POWER_STRESS, + POWER_PARAM_OPP_TABLE, + POWER_PARAM_CURR_STATUS, + POWER_PARAM_LOG_LEVEL, + POWER_PARAM_ULOG_LEVEL, +}; + +struct apu_dev_power_data { + int dev_type; + int dev_core; + void *pdata; +}; + +struct apupwr_plat_reg { + u32 opp_user; + u32 opp_thermal; + u32 opp_curr; + u32 opp_mask; +}; + +struct apupwr_plat_ops { + int (*clock_init)(struct device *dev); + int (*enable_dev_clksrc)(struct device *dev, enum DVFS_USER user); + void (*disable_dev_clksrc)(struct device *dev, enum DVFS_USER user); + int (*set_clk_freq)(struct device *dev, enum DVFS_FREQ freq, + enum DVFS_VOLTAGE_DOMAIN domain); + int (*set_vcore)(struct device *dev, enum DVFS_VOLTAGE volt); +}; + +struct apupwr_plat_data { + u32 flags; + int dvfs_user; + const struct apupwr_plat_reg *plat_regs; + const struct apupwr_plat_ops *ops; +}; + +struct apu_power { + struct device *dev; + void __iomem *spare_base; + const struct apupwr_plat_data *plat_data; + struct clk **clk; + struct regulator *vvpu_reg_id; + struct regulator *vmdla_reg_id; + + /* rpmsg device for power ipi */ + struct rpmsg_driver tx_rpmsg_driver; + struct rpmsg_device *tx_rpmsg_device; + struct rpmsg_driver rx_rpmsg_driver; + struct rpmsg_device *rx_rpmsg_device; + + /*debug*/ + struct dentry *dbg_root; + u32 dbg_option; + u32 ulog_level; +}; + +/* request send from AP to uP */ +enum request_id_AP { + DVFS_STAT_UPDATE = 0, + OPP_LIMIT_THERM, + OPP_LIMIT_FIX_OPP, + OPP_LIMIT_DVFS_DEBUG, + CHANGE_LOG_LEVEL, + STRESS_TEST, +}; + +/* request send from uP to AP */ +enum request_id_uP { + CHANGE_DEV_CLKSRC = 0, + CHANGE_DEV_CLOCK, + CHANGE_SYS_VCORE, + SYNC_STAT_UP_POWER, + SYNC_STAT_DEV_POWER, + DUMP_POWER_INFO, +}; + +/* power cmd format (from AP to uP) */ +struct power_cmd_AP { + u32 req_id:4, + reserved0:4, + reserved1:4, + reserved2:4, + reserved3:4, + reserved4:4, + reserved5:4, + need_handle_ack:4; +}; + +/* ipi cmd format (from AP to uP) */ +struct power_ipi_cmd_AP { + u32 cmd_sn; + struct power_cmd_AP pwr_cmd; + u32 data0; + u32 data1; +}; + +/*power cmd format (from uP to AP) */ +struct power_cmd_uP { + u32 req_id:4, + dev_id:4, + target_opp:4, + reserved0:4, + reserved1:4, + reserved2:4, + reserved3:4, + need_handle_ack:4; +}; + +/* ipi cmd format (from uP to AP) */ +struct power_ipi_cmd_uP { + u32 cmd_sn; + struct power_cmd_uP pwr_cmd; + u32 data0; + u32 data1; +}; + +/* reply to remote that we are completed */ +struct power_ipi_cmd_reply { + u32 cmd_sn; + u32 data0; + u32 data1; + u32 reserved3[61]; +}; + +int apu_enable_dev_clksrc(struct device *dev, enum DVFS_USER); +void apu_disable_dev_clksrc(struct device *dev, enum DVFS_USER); +int apu_set_clk_freq(struct device *dev, + enum DVFS_FREQ freq, + enum DVFS_VOLTAGE_DOMAIN domain); + +void apu_update_fixed_opp_by_reg(struct device *dev, + u32 opp_limit_stat); +void apu_check_curr_opp_by_reg(struct device *dev, + enum DVFS_USER specify_usr); +void apu_update_thermal_opp_by_reg(struct device *dev, + enum DVFS_USER user, int therm_opp); + +int apu_config_vcore_volt(struct device *dev, enum DVFS_VOLTAGE volt); + +int apu_power_ipi_init(struct apu_power *apupwr); +void apu_power_ipi_exit(struct apu_power *apupwr); +void apu_power_set_ulog_level(struct apu_power *apupwr, + int level); +void apu_power_notify_uP_opp_limit(struct apu_power *apu_power, + enum request_id_AP req); + +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) +void apu_power_debugfs_init(struct apu_power *apupwr); +void apu_power_debugfs_exit(void); +#else +static inline void apu_power_debugfs_init(struct apu_power *apupwr) { } +static inline void apu_power_debugfs_exit(void) { } +#endif +#endif From patchwork Sat Oct 23 11:14:04 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579563 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2DF5FC433EF for ; Sat, 23 Oct 2021 11:18:16 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E485860F50 for ; Sat, 23 Oct 2021 11:18:15 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org E485860F50 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=iUK5UaN3bzVGLPRU1pWpQtUvTfTEIvGVJFvRTP6OlE4=; b=FYDWMGnAs8t/Sb NQWxjODRbkDfEVO4jzIyiDfNRjJ8OlZFNwSRshXLIdyqp1CM3KOCJEXy4EL9gj/nd0fwz0nGLI0ZN LQjvDTTQ7pFbUmlRe/GZUDy0y9R2CSHq9tFIoGQObqmP4UzG2oCSvXTr+oTvqsZ9Ol3BzZswrit2r 0hklosf3vYYo+7VAp8CRt3NOXPJGG5in/leuKPdunHvSwAQ1vRweY2OaHls7dXYw5OIEB4JLUj2nj b3NaUTJ9Lr0L8MQODnyUhJzikSAfhK7J3hw01hsNgKANxYeNpjXrAKhjmoEgJyB6sXOFOrwBb2fAn wb2gYQZ/GnMTlWGPhAiQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF0o-00CdAd-EX; Sat, 23 Oct 2021 11:16:31 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzN-00CcOR-WB; Sat, 23 Oct 2021 11:15:07 +0000 X-UUID: cb192253e2624076a97b47722dd6d69f-20211023 X-UUID: cb192253e2624076a97b47722dd6d69f-20211023 Received: from mtkcas67.mediatek.inc [(172.29.193.45)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1151792081; Sat, 23 Oct 2021 04:15:00 -0700 Received: from MTKMBS07N2.mediatek.inc (172.21.101.141) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:58 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n2.mediatek.inc (172.21.101.141) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:14:56 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:56 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 08/13] soc: mediatek: apu: Add apusys rv driver Date: Sat, 23 Oct 2021 19:14:04 +0800 Message-ID: <20211023111409.30463-9-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041502_169453_76630937 X-CRM114-Status: GOOD ( 29.28 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add driver for control APU tinysys APU integrated subsystem having MD32RV33 (MD32) that runs tinysys The tinsys is running on a micro processor in APU. Its firmware is load and boot from Kernel side. Kernel and tinysys use IPI to tx/rx messages. Signed-off-by: Flora Fu --- drivers/soc/mediatek/apusys/Makefile | 6 + drivers/soc/mediatek/apusys/apu-config.h | 100 +++ drivers/soc/mediatek/apusys/apu-core.c | 2 + drivers/soc/mediatek/apusys/apu-core.h | 2 + drivers/soc/mediatek/apusys/apu-ipi.c | 486 ++++++++++++ drivers/soc/mediatek/apusys/apu-mbox.c | 83 ++ drivers/soc/mediatek/apusys/apu-mbox.h | 27 + drivers/soc/mediatek/apusys/apu-rproc.c | 806 ++++++++++++++++++++ drivers/soc/mediatek/apusys/apu-sw-logger.c | 429 +++++++++++ drivers/soc/mediatek/apusys/apu.h | 256 +++++++ drivers/soc/mediatek/apusys/mt81xx-plat.c | 320 ++++++++ 11 files changed, 2517 insertions(+) create mode 100644 drivers/soc/mediatek/apusys/apu-config.h create mode 100644 drivers/soc/mediatek/apusys/apu-ipi.c create mode 100644 drivers/soc/mediatek/apusys/apu-mbox.c create mode 100644 drivers/soc/mediatek/apusys/apu-mbox.h create mode 100644 drivers/soc/mediatek/apusys/apu-rproc.c create mode 100644 drivers/soc/mediatek/apusys/apu-sw-logger.c create mode 100644 drivers/soc/mediatek/apusys/apu.h create mode 100644 drivers/soc/mediatek/apusys/mt81xx-plat.c diff --git a/drivers/soc/mediatek/apusys/Makefile b/drivers/soc/mediatek/apusys/Makefile index 8c61ed8e2c04..490de0ee4727 100644 --- a/drivers/soc/mediatek/apusys/Makefile +++ b/drivers/soc/mediatek/apusys/Makefile @@ -7,3 +7,9 @@ apu-objs += apu-core.o apu-objs += apu-pwr.o apu-objs += apu-pwr-ipi.o apu-$(CONFIG_MTK_APU_DEBUG) += apu-pwr-dbg.o + +apu-objs += apu-rproc.o +apu-objs += apu-ipi.o +apu-objs += apu-mbox.o +apu-objs += mt81xx-plat.o +apu-$(CONFIG_DEBUG_FS) += apu-sw-logger.o diff --git a/drivers/soc/mediatek/apusys/apu-config.h b/drivers/soc/mediatek/apusys/apu-config.h new file mode 100644 index 000000000000..fee3b0334502 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-config.h @@ -0,0 +1,100 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef APU_CONFIG_H +#define APU_CONFIG_H + +struct apu_ipi_config { + u64 in_buf_da; + u64 out_buf_da; +} __packed; + +struct vpu_init_info { + u32 vpu_num; + u32 cfg_addr; + u32 cfg_size; + u32 algo_info_ptr[3 * 2]; + u32 rst_vec[3]; + u32 dmem_addr[3]; + u32 imem_addr[3]; + u32 iram_addr[3]; + u32 cmd_addr[3]; + u32 log_addr[3]; + u32 log_size[3]; +} __packed; + +struct apusys_chip_data { + u32 s_code; + u32 b_code; + u32 r_code; + u32 a_code; +} __packed; + +struct logger_init_info { + u32 iova; +} __packed; + +struct reviser_init_info { + u32 boundary; + u32 dram[32]; +} __packed; + +enum user_config { + APU_IPI_CONFIG = 0x0, + VPU_INIT_INFO, + APUSYS_CHIP_DATA, + LOGGER_INIT_INFO, + REVISER_INIT_INFO, + USER_CONFIG_MAX +}; + +struct config_v1_entry_table { + u32 user_entry[USER_CONFIG_MAX]; +} __packed; + +struct config_v1 { + /* header begin */ + u32 header_magic; + u32 header_rev; + u32 entry_offset; + u32 config_size; + /* header end */ + /* do not add new member before this line */ + + /* system related config begin */ + u32 ramdump_offset; + u32 ramdump_type; + u64 time_offset; + /* system related config end */ + + /* entry table */ + u8 entry_tbl[sizeof(struct config_v1_entry_table)]; + + /* user data payload begin */ + u8 user0_data[sizeof(struct apu_ipi_config)]; + u8 user1_data[sizeof(struct vpu_init_info)]; + u8 user2_data[sizeof(struct apusys_chip_data)]; + u8 user3_data[sizeof(struct logger_init_info)]; + u8 user4_data[sizeof(struct reviser_init_info)]; + /* user data payload end */ +} __packed; + +static inline void *get_apu_config_user_ptr(struct config_v1 *conf, + enum user_config user_id) +{ + struct config_v1_entry_table *entry_tbl; + + if (!conf) + return NULL; + + if (user_id >= USER_CONFIG_MAX) + return NULL; + + entry_tbl = (struct config_v1_entry_table *) + ((void *)conf + conf->entry_offset); + + return (void *)conf + entry_tbl->user_entry[user_id]; +} +#endif /* APU_CONFIG_H */ diff --git a/drivers/soc/mediatek/apusys/apu-core.c b/drivers/soc/mediatek/apusys/apu-core.c index 069e18af7a5b..80652b1d056e 100644 --- a/drivers/soc/mediatek/apusys/apu-core.c +++ b/drivers/soc/mediatek/apusys/apu-core.c @@ -19,6 +19,7 @@ static struct apusys_core_info g_core_info; */ static int (*apusys_init_func[])(struct apusys_core_info *) = { apu_power_drv_init, + apu_rproc_init, }; /* @@ -26,6 +27,7 @@ static int (*apusys_init_func[])(struct apusys_core_info *) = { * call exit function in order at apu.ko exit stage */ static void (*apusys_exit_func[])(void) = { + apu_rproc_exit, apu_power_drv_exit, }; diff --git a/drivers/soc/mediatek/apusys/apu-core.h b/drivers/soc/mediatek/apusys/apu-core.h index 77f1b39424d1..b47d95f0a1ae 100644 --- a/drivers/soc/mediatek/apusys/apu-core.h +++ b/drivers/soc/mediatek/apusys/apu-core.h @@ -11,4 +11,6 @@ struct apusys_core_info { int apu_power_drv_init(struct apusys_core_info *info); void apu_power_drv_exit(void); +int apu_rproc_init(struct apusys_core_info *info); +void apu_rproc_exit(void); #endif diff --git a/drivers/soc/mediatek/apusys/apu-ipi.c b/drivers/soc/mediatek/apusys/apu-ipi.c new file mode 100644 index 000000000000..547e034b3620 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-ipi.c @@ -0,0 +1,486 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include + +#include "apu.h" +#include "apu-config.h" +#include "apu-mbox.h" + +#define IPI_BUF_SIZE (round_up(sizeof(struct mtk_share_obj) * 2, PAGE_SIZE)) + +static struct lock_class_key ipi_lock_key[APU_IPI_MAX]; +static unsigned int tx_serial_no; +static unsigned int rx_serial_no; + +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) +static inline void dump_msg_buf(struct mtk_apu *apu, void *data, u32 len) +{ + struct device *dev = apu->dev; + u32 i; + int size = 64, num; + u8 buf[64], *ptr = buf; + int ret; + + dev_info(dev, "===== dump message =====\n"); + for (i = 0; i < len; i++) { + num = snprintf(ptr, size, "%02x ", ((u8 *)data)[i]); + if (num <= 0) { + dev_info(dev, "%s: snprintf return error(num = %d)\n", + __func__, num); + return; + } + size -= num; + ptr += num; + + if ((i + 1) % 4 == 0) { + ret = snprintf(ptr++, size--, " "); + if (ret <= 0) { + dev_info(dev, "%s: snprintf return error(ret = %d)\n", + __func__, ret); + return; + } + } + + if ((i + 1) % 16 == 0 || (i + 1) >= len) { + dev_info(dev, "%s\n", buf); + size = 64; + ptr = buf; + } + } + dev_info(dev, "========================\n"); +} +#endif + +static u32 calculate_csum(void *data, u32 len) +{ + u32 csum = 0, res = 0, i; + u8 *ptr; + + for (i = 0; i < (len / sizeof(csum)); i++) + csum += *(((u32 *)data) + i); + + ptr = (u8 *)data + len / sizeof(csum) * sizeof(csum); + for (i = 0; i < (len % sizeof(csum)); i++) + res |= *(ptr + i) << i * 8; + + csum += res; + + return csum; +} + +static inline bool bypass_check(u32 id) +{ + /* whitelist IPI used in power off flow */ + return id == APU_IPI_DEEP_IDLE; +} + +static void ipi_usage_cnt_update(struct mtk_apu *apu, u32 id, int diff) +{ + struct apu_ipi_desc *ipi = &apu->ipi_desc[id]; + + if (apu->platdata->ipi_attrs[id].ack != IPI_WITH_ACK) + return; + + spin_lock(&apu->usage_cnt_lock); + ipi->usage_cnt += diff; + spin_unlock(&apu->usage_cnt_lock); +} + +int apu_ipi_send(struct mtk_apu *apu, u32 id, void *data, u32 len, + u32 wait_ms) +{ + struct timespec64 ts, te; + struct apu_mbox_hdr hdr; + unsigned long timeout; + int ret = 0; + + ktime_get_ts64(&ts); + + if (!apu || + id <= APU_IPI_INIT || + id >= APU_IPI_MAX || + id == APU_IPI_NS_SERVICE || + len > APU_SHARE_BUFFER_SIZE || + !data) + return -EINVAL; + + mutex_lock(&apu->send_lock); + if (apu->platdata->ipi_attrs[id].direction == IPI_HOST_INITIATE && + apu->ipi_inbound_locked == IPI_LOCKED && !bypass_check(id)) { + dev_info(apu->dev, "%s: ipi locked, ipi=%d\n", __func__, id); + mutex_unlock(&apu->send_lock); + return -EBUSY; + } + + /* re-init inbox mask everytime for aoc */ + apu_mbox_inbox_init(apu); + apu_deepidle_power_on_aputop(apu); + ret = apu_mbox_wait_inbox(apu); + if (ret) { + dev_info(apu->dev, "wait inbox fail, ret=%d\n", ret); + goto unlock_mutex; + } + + /* copy message payload to share buffer, need to do cache flush if + * the buffer is cacheable. currently not + */ + memcpy_toio(apu->send_buf, data, len); + + hdr.id = id; + hdr.len = len; + hdr.csum = calculate_csum(data, len); + hdr.serial_no = tx_serial_no++; + + apu_mbox_write_inbox(apu, &hdr); + apu->ipi_id_ack[id] = false; + + /* poll ack from remote processor if wait_ms specified */ + if (wait_ms) { + timeout = jiffies + msecs_to_jiffies(wait_ms); + ret = wait_event_timeout(apu->ack_wq, + &apu->ipi_id_ack[id], + timeout); + + apu->ipi_id_ack[id] = false; + + if (WARN(!ret, "apu ipi %d ack timeout!", id)) { + ret = -EIO; + goto unlock_mutex; + } else { + ret = 0; + } + } + ipi_usage_cnt_update(apu, id, 1); + +unlock_mutex: + mutex_unlock(&apu->send_lock); + ktime_get_ts64(&te); + ts = timespec64_sub(te, ts); + + return ret; +} + +int apu_ipi_lock(struct mtk_apu *apu) +{ + struct apu_ipi_desc *ipi; + int i; + bool ready_to_lock = true; + + if (mutex_trylock(&apu->send_lock) == 0) + return -EBUSY; + + if (apu->ipi_inbound_locked == IPI_LOCKED) { + dev_info(apu->dev, "%s: ipi already locked\n", __func__); + mutex_unlock(&apu->send_lock); + return 0; + } + + spin_lock(&apu->usage_cnt_lock); + for (i = 0; i < APU_IPI_MAX; i++) { + ipi = &apu->ipi_desc[i]; + + if (apu->platdata->ipi_attrs[i].ack == IPI_WITH_ACK && + ipi->usage_cnt != 0 && + !bypass_check(i)) { + dev_info(apu->dev, "%s: ipi %d is still in use %d\n", + __func__, i, ipi->usage_cnt); + ready_to_lock = false; + } + } + + if (!ready_to_lock) { + spin_unlock(&apu->usage_cnt_lock); + mutex_unlock(&apu->send_lock); + return -EBUSY; + } + + apu->ipi_inbound_locked = IPI_LOCKED; + spin_unlock(&apu->usage_cnt_lock); + mutex_unlock(&apu->send_lock); + + return 0; +} + +void apu_ipi_unlock(struct mtk_apu *apu) +{ + mutex_lock(&apu->send_lock); + if (apu->ipi_inbound_locked == IPI_UNLOCKED) + dev_info(apu->dev, "%s: ipi already unlocked\n", __func__); + + spin_lock(&apu->usage_cnt_lock); + apu->ipi_inbound_locked = IPI_UNLOCKED; + spin_unlock(&apu->usage_cnt_lock); + mutex_unlock(&apu->send_lock); +} + +int apu_ipi_register(struct mtk_apu *apu, u32 id, + ipi_handler_t handler, void *priv) +{ + if (!apu || id >= APU_IPI_MAX || WARN_ON(!handler)) { + if (apu) + dev_info(apu->dev, + "%s failed. apu=%p, id=%d, handler=%p, priv=%p\n", + __func__, apu, id, handler, priv); + return -EINVAL; + } + + mutex_lock(&apu->ipi_desc[id].lock); + apu->ipi_desc[id].handler = handler; + apu->ipi_desc[id].priv = priv; + mutex_unlock(&apu->ipi_desc[id].lock); + + return 0; +} + +void apu_ipi_unregister(struct mtk_apu *apu, u32 id) +{ + if (!apu || id >= APU_IPI_MAX) { + if (apu) + dev_info(apu->dev, "%s: invalid id=%d\n", __func__, id); + return; + } + + mutex_lock(&apu->ipi_desc[id].lock); + apu->ipi_desc[id].handler = NULL; + apu->ipi_desc[id].priv = NULL; + mutex_unlock(&apu->ipi_desc[id].lock); +} + +static void apu_init_ipi_handler(void *data, unsigned int len, void *priv) +{ + struct mtk_apu *apu = priv; + struct apu_run *run = data; + struct device *dev = apu->dev; + + strscpy(apu->run.fw_ver, data, APU_FW_VER_LEN); + apu->run.signaled = 1; + wake_up_interruptible(&apu->run.wq); + dev_info(dev, "fw_ver: %s\n", run->fw_ver); +} + +static irqreturn_t apu_ipi_handler(int irq, void *priv) +{ + struct timespec64 ts, te; + struct mtk_apu *apu = priv; + struct apu_mbox_hdr hdr; + struct mtk_share_obj *recv_obj = apu->recv_buf; + ipi_handler_t handler; + u32 id, len, calc_csum; + u32 temp_buf[APU_SHARE_BUFFER_SIZE / 4] = {0}; + + hdr.id = 0; + hdr.len = 0; + hdr.serial_no = 0; + hdr.csum = 0; + + ktime_get_ts64(&ts); + apu_mbox_read_outbox(apu, &hdr); + id = hdr.id; + len = hdr.len; + if (hdr.serial_no != rx_serial_no) { + dev_info(apu->dev, "unmatched serial_no: curr=%u, recv=%u\n", + rx_serial_no, hdr.serial_no); + dev_info(apu->dev, "outbox irq=%x\n", + ioread32(apu->apu_mbox + 0xc4)); + if (ioread32(apu->apu_mbox + 0xc4) == 0) { + dev_info(apu->dev, "abnormal isr call, skip\n"); + goto ack_irq; + } + } + rx_serial_no++; + + if (len > APU_SHARE_BUFFER_SIZE) { + dev_info(apu->dev, "IPI message too long(len %d, max %d)", + len, APU_SHARE_BUFFER_SIZE); + goto ack_irq; + } + + if (id >= APU_IPI_MAX) { + dev_info(apu->dev, "no such IPI id = %d", id); + goto ack_irq; + } + + mutex_lock(&apu->ipi_desc[id].lock); + handler = apu->ipi_desc[id].handler; + if (!handler) { + dev_info(apu->dev, "IPI id=%d is not registered", id); + mutex_unlock(&apu->ipi_desc[id].lock); + goto ack_irq; + } + + memcpy_fromio(temp_buf, &recv_obj->share_buf, len); + + calc_csum = calculate_csum(temp_buf, len); + if (calc_csum != hdr.csum) { + dev_info(apu->dev, "csum error: recv=0x%08x, calc=0x%08x\n", + hdr.csum, calc_csum); +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) + dump_msg_buf(apu, temp_buf, hdr.len); +#endif + } + + handler(temp_buf, len, apu->ipi_desc[id].priv); + ipi_usage_cnt_update(apu, id, -1); + mutex_unlock(&apu->ipi_desc[id].lock); + + apu->ipi_id_ack[id] = true; + wake_up(&apu->ack_wq); + +ack_irq: + apu_mbox_ack_outbox(apu); + ktime_get_ts64(&te); + ts = timespec64_sub(te, ts); + + return IRQ_HANDLED; +} + +static int apu_send_ipi(struct platform_device *pdev, u32 id, void *buf, + unsigned int len, unsigned int wait) +{ + struct mtk_apu *apu = platform_get_drvdata(pdev); + + return apu_ipi_send(apu, id, buf, len, wait); +} + +static int apu_register_ipi(struct platform_device *pdev, u32 id, + ipi_handler_t handler, void *priv) +{ + struct mtk_apu *apu = platform_get_drvdata(pdev); + + return apu_ipi_register(apu, id, handler, priv); +} + +static void apu_unregister_ipi(struct platform_device *pdev, u32 id) +{ + struct mtk_apu *apu = platform_get_drvdata(pdev); + + apu_ipi_unregister(apu, id); +} + +static struct mtk_rpmsg_info apu_rpmsg_info = { + .send_ipi = apu_send_ipi, + .register_ipi = apu_register_ipi, + .unregister_ipi = apu_unregister_ipi, + .ns_ipi_id = APU_IPI_NS_SERVICE, +}; + +static void apu_add_rpmsg_subdev(struct mtk_apu *apu) +{ + struct platform_device *pdev = to_platform_device(apu->dev); + + apu->rpmsg_subdev = mtk_rpmsg_create_rproc_subdev(pdev, + &apu_rpmsg_info); + if (apu->rpmsg_subdev) + rproc_add_subdev(apu->rproc, apu->rpmsg_subdev); +} + +static void apu_remove_rpmsg_subdev(struct mtk_apu *apu) +{ + if (apu->rpmsg_subdev) { + rproc_remove_subdev(apu->rproc, apu->rpmsg_subdev); + mtk_rpmsg_destroy_rproc_subdev(apu->rpmsg_subdev); + apu->rpmsg_subdev = NULL; + } +} + +void apu_ipi_config_remove(struct mtk_apu *apu) +{ + dma_free_coherent(apu->dev, IPI_BUF_SIZE, + apu->recv_buf, apu->recv_buf_da); +} + +int apu_ipi_config_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + struct apu_ipi_config *ipi_config; + void *ipi_buf = NULL; + dma_addr_t ipi_buf_da = 0; + + ipi_config = (struct apu_ipi_config *) + get_apu_config_user_ptr(apu->conf_buf, APU_IPI_CONFIG); + + /* initialize shared buffer */ + ipi_buf = dma_alloc_coherent(dev, IPI_BUF_SIZE, + &ipi_buf_da, GFP_KERNEL); + if (!ipi_buf || !ipi_buf_da) { + dev_info(dev, "failed to allocate ipi share memory\n"); + return -ENOMEM; + } + + memset_io(ipi_buf, 0, sizeof(struct mtk_share_obj) * 2); + apu->recv_buf = ipi_buf; + apu->recv_buf_da = ipi_buf_da; + apu->send_buf = ipi_buf + sizeof(struct mtk_share_obj); + apu->send_buf_da = ipi_buf_da + sizeof(struct mtk_share_obj); + ipi_config->in_buf_da = apu->send_buf_da; + ipi_config->out_buf_da = apu->recv_buf_da; + + return 0; +} + +void apu_ipi_remove(struct mtk_apu *apu) +{ + apu_mbox_hw_exit(apu); + apu_remove_rpmsg_subdev(apu); + apu_ipi_unregister(apu, APU_IPI_INIT); +} + +int apu_ipi_init(struct platform_device *pdev, struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + int i, ret; + + tx_serial_no = 0; + rx_serial_no = 0; + + mutex_init(&apu->send_lock); + spin_lock_init(&apu->usage_cnt_lock); + for (i = 0; i < APU_IPI_MAX; i++) { + mutex_init(&apu->ipi_desc[i].lock); + lockdep_set_class_and_name(&apu->ipi_desc[i].lock, + &ipi_lock_key[i], + apu->platdata->ipi_attrs[i].name); + } + + init_waitqueue_head(&apu->run.wq); + init_waitqueue_head(&apu->ack_wq); + + /* APU initialization IPI register */ + ret = apu_ipi_register(apu, APU_IPI_INIT, apu_init_ipi_handler, apu); + if (ret) { + dev_err(dev, "failed to register ipi for init, ret=%d\n", + ret); + return ret; + } + + /* add rpmsg subdev */ + apu_add_rpmsg_subdev(apu); + + /* register mailbox IRQ */ + apu->mbox0_irq_number = platform_get_irq_byname(pdev, "mbox0_irq"); + dev_info(&pdev->dev, "%s: mbox0_irq = %d\n", __func__, + apu->mbox0_irq_number); + + ret = devm_request_threaded_irq(&pdev->dev, apu->mbox0_irq_number, + NULL, apu_ipi_handler, IRQF_ONESHOT, + "apu_ipi", apu); + if (ret < 0) + goto remove_rpmsg_subdev; + + apu_mbox_hw_init(apu); + + return 0; + +remove_rpmsg_subdev: + apu_remove_rpmsg_subdev(apu); + apu_ipi_unregister(apu, APU_IPI_INIT); + + return ret; +} diff --git a/drivers/soc/mediatek/apusys/apu-mbox.c b/drivers/soc/mediatek/apusys/apu-mbox.c new file mode 100644 index 000000000000..dfd41f7c2640 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-mbox.c @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include + +#include "apu.h" +#include "apu-mbox.h" + +#define _INBOX(_m) ((_m)->apu_mbox + 0x0) +#define _OUTBOX(_m) ((_m)->apu_mbox + 0x20) +#define _DUMMY(_m) ((_m)->apu_mbox + 0x40) +#define _INBOX_IRQ(_m) ((_m)->apu_mbox + 0xc0) +#define _OUTBOX_IRQ(_m) ((_m)->apu_mbox + 0xc4) +#define _INBOX_IRQ_MASK(_m) ((_m)->apu_mbox + 0xd0) +#define _OUTBOX_IRQ_MASK(_m) ((_m)->apu_mbox + 0xd8) + +void apu_mbox_ack_outbox(struct mtk_apu *apu) +{ + iowrite32(ioread32(_OUTBOX_IRQ(apu)), + _OUTBOX_IRQ(apu)); +} + +void apu_mbox_read_outbox(struct mtk_apu *apu, struct apu_mbox_hdr *hdr) +{ + unsigned int i, val; + + for (i = 0; i < APU_MBOX_HDR_SLOTS; i++) { + val = ioread32(_OUTBOX(apu) + i * APU_MBOX_SLOT_SIZE); + ((unsigned int *)hdr)[i] = val; + } +} + +int apu_mbox_wait_inbox(struct mtk_apu *apu) +{ + unsigned long timeout; + unsigned char irq, mask; + + timeout = jiffies + msecs_to_jiffies(1000); + do { + if (time_after(jiffies, timeout)) { + dev_info(apu->dev, "timeout.\n"); + return -ETIMEDOUT; + } + + irq = ioread32(_INBOX_IRQ(apu)); + mask = ioread32(_INBOX_IRQ_MASK(apu)); + + } while (irq & ~mask); + + return 0; +} + +void apu_mbox_write_inbox(struct mtk_apu *apu, struct apu_mbox_hdr *hdr) +{ + unsigned int i, val; + + for (i = 0; i < APU_MBOX_HDR_SLOTS; i++) { + val = ((unsigned int *)hdr)[i]; + iowrite32(val, _INBOX(apu) + i * APU_MBOX_SLOT_SIZE); + } +} + +void apu_mbox_inbox_init(struct mtk_apu *apu) +{ + iowrite32(~(1 << (APU_MBOX_HDR_SLOTS - 1)), + _INBOX_IRQ_MASK(apu)); +} + +void apu_mbox_hw_init(struct mtk_apu *apu) +{ + apu_mbox_inbox_init(apu); + + /* clear outbox IRQ */ + apu_mbox_ack_outbox(apu); +} + +void apu_mbox_hw_exit(struct mtk_apu *apu) +{ + /* mask inbox IRQ */ + iowrite32(0xff, _INBOX_IRQ_MASK(apu)); +} diff --git a/drivers/soc/mediatek/apusys/apu-mbox.h b/drivers/soc/mediatek/apusys/apu-mbox.h new file mode 100644 index 000000000000..47c48d2a1c25 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-mbox.h @@ -0,0 +1,27 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef APU_MBOX_H +#define APU_MBOX_H + +struct apu_mbox_hdr { + unsigned int id; + unsigned int len; + unsigned int serial_no; + unsigned int csum; +}; + +#define APU_MBOX_SLOT_SIZE (4) +#define APU_MBOX_HDR_SLOTS \ + (sizeof(struct apu_mbox_hdr) / APU_MBOX_SLOT_SIZE) + +void apu_mbox_ack_outbox(struct mtk_apu *apu); +void apu_mbox_read_outbox(struct mtk_apu *apu, struct apu_mbox_hdr *hdr); +int apu_mbox_wait_inbox(struct mtk_apu *apu); +void apu_mbox_write_inbox(struct mtk_apu *apu, struct apu_mbox_hdr *hdr); +void apu_mbox_inbox_init(struct mtk_apu *apu); +void apu_mbox_hw_init(struct mtk_apu *apu); +void apu_mbox_hw_exit(struct mtk_apu *apu); +#endif /* APU_MBOX_H */ diff --git a/drivers/soc/mediatek/apusys/apu-rproc.c b/drivers/soc/mediatek/apusys/apu-rproc.c new file mode 100644 index 000000000000..e2fe63dd6cc1 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-rproc.c @@ -0,0 +1,806 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu.h" +#include "apu-config.h" +#include "apu-core.h" + +/* cmd */ +enum { + DPIDLE_CMD_LOCK_IPI = 0x5a00, + DPIDLE_CMD_UNLOCK_IPI = 0x5a01, + DPIDLE_CMD_PDN_UNLOCK = 0x5a02, +}; + +/* ack */ +enum { + DPIDLE_ACK_OK = 0, + DPIDLE_ACK_LOCK_BUSY, + DPIDLE_ACK_POWER_DOWN_FAIL, +}; + +static struct work_struct *apu_pwr_work; +static struct workqueue_struct *apu_pwr_wq; +static struct dentry *dbg_root; + +static void *apu_da_to_va(struct rproc *rproc, u64 da, size_t len, + bool *is_iomem) +{ + void *ptr = NULL; + struct mtk_apu *apu = (struct mtk_apu *)rproc->priv; + + if (da >= DRAM_OFFSET && da < DRAM_OFFSET + CODE_BUF_SIZE) { + ptr = apu->code_buf + (da - DRAM_OFFSET); + } else { + dev_err(apu->dev, "%s: invalid da: da = 0x%llx, len = %zu\n", + __func__, da, len); + } + return ptr; +} + +static int apu_run(struct rproc *rproc) +{ + struct mtk_apu *apu = (struct mtk_apu *)rproc->priv; + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + struct device *dev = apu->dev; + struct apu_run *run = &apu->run; + struct timespec64 begin, end, delta; + int ret; + + pm_runtime_get_sync(apu->dev); + hw_ops->start(apu); + + /* check if boot success */ + ktime_get_ts64(&begin); + ret = wait_event_interruptible_timeout(run->wq, + run->signaled, + msecs_to_jiffies(10000)); + ktime_get_ts64(&end); + if (ret == 0) { + dev_info(dev, "APU initialization timeout!!\n"); + ret = -ETIME; + goto stop; + } + if (ret == -ERESTARTSYS) { + dev_info(dev, "wait APU interrupted by a signal!!\n"); + goto stop; + } + + apu->boot_done = true; + delta = timespec64_sub(end, begin); + dev_info(dev, "APU uP boot success. boot time: %llu s, %llu ns\n", + (u64)delta.tv_sec, (u64)delta.tv_nsec); + + return 0; + +stop: + hw_ops->stop(apu); + + return ret; +} + +static int apu_start(struct rproc *rproc) +{ + return apu_run(rproc); +} + +static int apu_attach(struct rproc *rproc) +{ + return apu_run(rproc); +} + +static int apu_stop(struct rproc *rproc) +{ + struct mtk_apu *apu = (struct mtk_apu *)rproc->priv; + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + hw_ops->stop(apu); + + return 0; +} + +static const struct rproc_ops apu_ops = { + .start = apu_start, + .stop = apu_stop, + .attach = apu_attach, + .da_to_va = apu_da_to_va, +}; + +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) +static void apu_deepidle_pwron_dbg_fn(struct work_struct *work) +{ + struct mtk_apu *apu = container_of(work, struct mtk_apu, pwron_dbg_wk); + struct device *dev = apu->dev; + int i; + + dev_info(dev, "mbox dummy= 0x%08x 0x%08x 0x%08x 0x%08x\n", + ioread32(apu->apu_mbox + MBOX0_SPARE0), + ioread32(apu->apu_mbox + MBOX0_SPARE1), + ioread32(apu->apu_mbox + MBOX0_SPARE2), + ioread32(apu->apu_mbox + MBOX0_SPARE3)); + + usleep_range(0, 1000); + for (i = 0; i < 5; i++) { + dev_info(apu->dev, "apu boot: pc=%08x, sp=%08x\n", + ioread32(apu->md32_sysctrl + MD32_MON_PC), + ioread32(apu->md32_sysctrl + MD32_MON_SP)); + usleep_range(0, 1000); + } + + dev_info(dev, "%s: MD32_SYS_CTRL = 0x%x\n", + __func__, ioread32(apu->md32_sysctrl + MD32_SYS_CTRL)); +} +#endif + +static int apu_deepidle_send_ack(struct mtk_apu *apu, u32 cmd, u32 ack) +{ + struct dpidle_msg msg; + int ret; + + msg.cmd = cmd; + msg.ack = ack; + ret = apu_ipi_send(apu, APU_IPI_DEEP_IDLE, &msg, sizeof(msg), 0); + if (ret) + dev_info(apu->dev, + "%s: failed to send ack msg, ack=%d, ret=%d\n", + __func__, ack, ret); + + return ret; +} + +static void apu_deepidle_work_func(struct work_struct *work) +{ + struct mtk_apu *apu = container_of(work, struct mtk_apu, deepidle_work); + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + struct dpidle_msg *msg = &apu->recv_msg; + int ret; + + switch (msg->cmd) { + case DPIDLE_CMD_LOCK_IPI: + ret = apu_ipi_lock(apu); + if (ret) { + dev_info(apu->dev, "%s: failed to lock IPI, ret=%d\n", + __func__, ret); + apu_deepidle_send_ack(apu, DPIDLE_CMD_LOCK_IPI, + DPIDLE_ACK_LOCK_BUSY); + return; + } + apu_deepidle_send_ack(apu, DPIDLE_CMD_LOCK_IPI, + DPIDLE_ACK_OK); + break; + + case DPIDLE_CMD_UNLOCK_IPI: + apu_ipi_unlock(apu); + apu_deepidle_send_ack(apu, DPIDLE_CMD_UNLOCK_IPI, + DPIDLE_ACK_OK); + break; + + case DPIDLE_CMD_PDN_UNLOCK: + apu_deepidle_send_ack(apu, DPIDLE_CMD_PDN_UNLOCK, + DPIDLE_ACK_OK); + ret = hw_ops->power_off(apu); + if (ret) { + dev_info(apu->dev, "failed to power off ret=%d\n", ret); + apu_ipi_unlock(apu); + WARN_ON(0); + return; + } + apu_ipi_unlock(apu); + break; + + default: + dev_info(apu->dev, "unknown cmd %x\n", msg->cmd); + break; + } +} + +static void apu_deepidle_ipi_handler(void *data, unsigned int len, void *priv) +{ + struct mtk_apu *apu = (struct mtk_apu *)priv; + + memcpy(&apu->recv_msg, data, len); + queue_work(apu->apu_deepidle_workq, &apu->deepidle_work); +} + +static int apu_deepidle_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + int ret; + + apu->apu_deepidle_workq = alloc_workqueue("apu_deepidle", + WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!apu->apu_deepidle_workq) { + dev_info(apu->dev, "%s: failed to allocate rq for deep idle\n", + __func__); + return -ENOMEM; + } + INIT_WORK(&apu->deepidle_work, apu_deepidle_work_func); + + ret = apu_ipi_register(apu, APU_IPI_DEEP_IDLE, + apu_deepidle_ipi_handler, apu); + if (ret) { + dev_info(dev, + "%s: failed to register deepidle ipi, ret=%d\n", + __func__, ret); + } +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) + INIT_WORK(&apu->pwron_dbg_wk, apu_deepidle_pwron_dbg_fn); +#endif + + return ret; +} + +static void apu_deepidle_exit(struct mtk_apu *apu) +{ +#if IS_ENABLED(CONFIG_MTK_APU_DEBUG) + flush_work(&apu->pwron_dbg_wk); +#endif + apu_ipi_unregister(apu, APU_IPI_DEEP_IDLE); + if (apu->apu_deepidle_workq) + destroy_workqueue(apu->apu_deepidle_workq); +} + +void apu_deepidle_power_on_aputop(struct mtk_apu *apu) +{ + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + if (pm_runtime_suspended(apu->dev)) { + apu->conf_buf->time_offset = sched_clock(); + hw_ops->power_on(apu); + + #if IS_ENABLED(CONFIG_MTK_APU_DEBUG) + schedule_work(&apu->pwron_dbg_wk); + #endif + } +} + +static void apu_timesync_work_func(struct work_struct *work) +{ + struct mtk_apu *apu = container_of(work, struct mtk_apu, timesync_work); + int ret; + + apu->timesync_stamp = sched_clock(); + ret = apu_ipi_send(apu, APU_IPI_TIMESYNC, &apu->timesync_stamp, + sizeof(u64), 0); + if (ret) { + dev_err(apu->dev, "timsync ipi fail(%d)\n", ret); + return; + } +} + +static void apu_timesync_handler(void *data, u32 len, void *priv) +{ + struct mtk_apu *apu = (struct mtk_apu *)priv; + + queue_work(apu->timesync_wq, &apu->timesync_work); +} + +static int apu_timesync_init(struct mtk_apu *apu) +{ + int ret; + + apu->timesync_wq = alloc_workqueue("apu_timesync", + WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!apu->timesync_wq) { + dev_info(apu->dev, "%s: failed to allocate wq for timesync\n", + __func__); + return -ENOMEM; + } + INIT_WORK(&apu->timesync_work, apu_timesync_work_func); + + ret = apu_ipi_register(apu, APU_IPI_TIMESYNC, apu_timesync_handler, + apu); + if (ret) { + dev_info(apu->dev, "%s: failed to register IPI\n", __func__); + destroy_workqueue(apu->timesync_wq); + apu->timesync_wq = NULL; + return ret; + } + + pr_info("%s %d\n", __func__, __LINE__); + return 0; +} + +static void apu_timesync_remove(struct mtk_apu *apu) +{ + apu_ipi_unregister(apu, APU_IPI_TIMESYNC); + + if (apu->timesync_wq) + destroy_workqueue(apu->timesync_wq); +} + +static irqreturn_t apu_wdt_isr(int irq, void *private_data) +{ + unsigned long flags; + struct mtk_apu *apu = (struct mtk_apu *)private_data; + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + spin_lock_irqsave(&apu->reg_lock, flags); + if (hw_ops->cg_gating) + hw_ops->cg_gating(apu); + + /* disable apu wdt */ + iowrite32(ioread32(apu->apu_wdt + WDT_CTRL0) & ~WDT_EN, + apu->apu_wdt + WDT_CTRL0); + /* clear wdt interrupt */ + iowrite32(0x1, apu->apu_wdt); + spin_unlock_irqrestore(&apu->reg_lock, flags); + disable_irq_nosync(apu->wdt_irq_number); + + return IRQ_HANDLED; +} + +static int apu_excep_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + struct platform_device *pdev = to_platform_device(dev); + u32 irq_type = irq_get_trigger_type(apu->wdt_irq_number); + int ret = 0; + + apu->wdt_irq_number = platform_get_irq_byname(pdev, "apu_wdt"); + ret = devm_request_irq(dev, apu->wdt_irq_number, apu_wdt_isr, + irq_type, "apusys_wdt", apu); + if (ret < 0) + dev_err(dev, "%s Failed to request irq %d: %d\n", + __func__, apu->wdt_irq_number, ret); + + return ret; +} + +static void apu_excep_remove(struct mtk_apu *apu) +{ + unsigned long flags; + + spin_lock_irqsave(&apu->reg_lock, flags); + /* disable apu wdt */ + iowrite32(ioread32(apu->apu_wdt + WDT_CTRL0) & ~WDT_EN, + apu->apu_wdt + WDT_CTRL0); + /* clear wdt interrupt */ + iowrite32(0x1, apu->apu_wdt); + spin_unlock_irqrestore(&apu->reg_lock, flags); + disable_irq(apu->wdt_irq_number); +} + +#define CONFIG_SIZE (round_up(sizeof(struct config_v1), PAGE_SIZE)) +static void apu_config_user_ptr_init(const struct mtk_apu *apu) +{ + struct config_v1 *config; + struct config_v1_entry_table *entry_table; + + if (!apu || !apu->conf_buf) { + pr_err("%s: error\n", __func__); + return; + } + + config = apu->conf_buf; + config->header_magic = 0xc0de0101; + config->header_rev = 0x1; + config->entry_offset = offsetof(struct config_v1, entry_tbl); + config->config_size = sizeof(struct config_v1); + + entry_table = (struct config_v1_entry_table *)((void *)config + + config->entry_offset); + + entry_table->user_entry[0] = offsetof(struct config_v1, user0_data); + entry_table->user_entry[1] = offsetof(struct config_v1, user1_data); + entry_table->user_entry[2] = offsetof(struct config_v1, user2_data); + entry_table->user_entry[3] = offsetof(struct config_v1, user3_data); + entry_table->user_entry[4] = offsetof(struct config_v1, user4_data); +} + +static int apu_config_setup(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + unsigned long flags; + int ret; + + apu->conf_buf = dma_alloc_coherent(apu->dev, CONFIG_SIZE, + &apu->conf_da, GFP_KERNEL); + + if (!apu->conf_buf || apu->conf_da == 0) { + dev_info(dev, "%s: dma_alloc_coherent fail\n", __func__); + return -ENOMEM; + } + memset(apu->conf_buf, 0, CONFIG_SIZE); + + apu_config_user_ptr_init(apu); + spin_lock_irqsave(&apu->reg_lock, flags); + iowrite32((u32)apu->conf_da, apu->apu_mbox + HOST_CONFIG_ADDR); + spin_unlock_irqrestore(&apu->reg_lock, flags); + + apu->conf_buf->time_offset = sched_clock(); + ret = apu_ipi_config_init(apu); + if (ret) { + dev_info(dev, "apu ipi config init failed\n"); + goto out; + } + + ret = sw_logger_config_init(apu); + if (ret) { + dev_err(dev, "sw logger config init failed\n"); + goto err_sw_logger; + } + + return 0; + +err_sw_logger: + apu_ipi_config_remove(apu); +out: + return ret; +} + +static void apu_config_remove(struct mtk_apu *apu) +{ + sw_logger_config_remove(apu); + apu_ipi_config_remove(apu); + dma_free_coherent(apu->dev, CONFIG_SIZE, + apu->conf_buf, apu->conf_da); +} + +static int apu_dram_boot_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + int ret = 0; + int map_sg_sz = 0; + void *domain; + struct sg_table sgt; + phys_addr_t pa; + u32 boundary; + u64 iova; + + domain = iommu_get_domain_for_dev(apu->dev); + if (!domain) { + dev_err(dev, "%s: iommu_get_domain_for_dev fail\n", + __func__); + return -ENOMEM; + } + + /* Allocate code buffer */ + apu->code_buf = dma_alloc_coherent(apu->dev, CODE_BUF_SIZE, + &apu->code_da, GFP_KERNEL); + if (!apu->code_buf || apu->code_da == 0) { + dev_err(dev, "%s: dma_alloc_coherent fail\n", __func__); + return -ENOMEM; + } + memset(apu->code_buf, 0, CODE_BUF_SIZE); + boundary = (u32)upper_32_bits(apu->code_da); + iova = CODE_BUF_DA | ((u64)boundary << 32); + + /* Convert IOVA to sgtable */ + sgt.sgl = NULL; + ret = dma_get_sgtable(apu->dev, &sgt, apu->code_buf, + apu->code_da, CODE_BUF_SIZE); + if (ret < 0 || !sgt.sgl) { + dev_err(dev, "get sgtable fail\n"); + return -EINVAL; + } + + /* Map sg_list to MD32_BOOT_ADDR */ + map_sg_sz = iommu_map_sg(domain, iova, sgt.sgl, + sgt.nents, IOMMU_READ | IOMMU_WRITE); + if (map_sg_sz != CODE_BUF_SIZE) + return -EINVAL; + + pa = iommu_iova_to_phys(domain, iova + CODE_BUF_SIZE - SZ_4K); + if (!pa) + ret = -EPERM; + + return ret; +} + +static void apu_dram_boot_remove(struct mtk_apu *apu) +{ + void *domain = iommu_get_domain_for_dev(apu->dev); + u32 boundary = (u32)upper_32_bits(apu->code_da); + u64 iova = CODE_BUF_DA | ((u64)boundary << 32); + + if (domain) + iommu_unmap(domain, iova, CODE_BUF_SIZE); + + dma_free_coherent(apu->dev, CODE_BUF_SIZE, apu->code_buf, apu->code_da); +} + +static void apu_power_work_fn(struct work_struct *work) +{ + struct mtk_apu *apu = container_of(work, struct mtk_apu, pwr_work); + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + if (!apu->boot_done) { + pr_info("%s: uP not boot yet, skip pm nfy\n", __func__); + return; + } + hw_ops->stop(apu); +} + +static int apu_power_genpd_notifier(struct notifier_block *nb, + unsigned long event, void *data) +{ + switch (event) { + case GENPD_NOTIFY_OFF: + pr_info("%s: apu top off\n", __func__); + queue_work(apu_pwr_wq, apu_pwr_work); + break; + case GENPD_NOTIFY_ON: + pr_info("%s: apu top on\n", __func__); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static struct notifier_block apu_genpd_nb = { + .notifier_call = apu_power_genpd_notifier, +}; + +static int apu_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct device_node *np = dev->of_node; + struct rproc *rproc; + struct mtk_apu *apu; + struct mtk_apu_platdata *data; + struct mtk_apu_hw_ops *hw_ops; + char *fw_name = "mrv.elf"; + int ret = 0; + struct device_link *link; + + data = (struct mtk_apu_platdata *)of_device_get_match_data(dev); + if (!data) { + dev_info(dev, "%s: of_device_get_match_data fail\n", __func__); + return -EINVAL; + } + hw_ops = &data->ops; + + rproc = rproc_alloc(dev, + np->name, + &apu_ops, + fw_name, + sizeof(struct mtk_apu)); + + if (!rproc) { + dev_info(dev, "unable to allocate remoteproc\n"); + return -ENOMEM; + } + + if (data->flags & F_AUTO_BOOT) + rproc->auto_boot = true; + else + rproc->auto_boot = false; + + apu = (struct mtk_apu *)rproc->priv; + apu->rproc = rproc; + apu->dev = dev; + apu->platdata = data; + platform_set_drvdata(pdev, apu); + spin_lock_init(&apu->reg_lock); + + /* detect mandaotry platform data*/ + if (!hw_ops->apu_memmap_init || !hw_ops->apu_memmap_remove || + !hw_ops->start || !hw_ops->stop || + !hw_ops->power_init || + !hw_ops->power_on || !hw_ops->power_off || + !apu->platdata->ipi_attrs) { + WARN_ON(1); + return -EINVAL; + } + + if (data->flags & F_AUTO_BOOT) { + ret = hw_ops->power_init(apu); + if (ret) + goto out_free_rproc; + + link = device_link_add(dev, apu->power_dev, DL_FLAG_PM_RUNTIME); + if (!link) + dev_err(dev, "unable to link\n"); + } + pm_runtime_enable(&pdev->dev); + pm_runtime_get_sync(&pdev->dev); + + ret = dma_set_mask_and_coherent(apu->dev, DMA_BIT_MASK(64)); + if (ret) { + pr_info("%s: dma_set_mask_and_coherent fail(%d)\n", + __func__, ret); + goto out_free_rproc; + } + + ret = hw_ops->apu_memmap_init(apu); + if (ret) + goto remove_apu_memmap; + + apu->dbg_root = dbg_root; + ret = apu_sw_logger_init(apu); + if (ret) + goto remove_apu_sw_logger; + + ret = apu_config_setup(apu); + if (ret) + goto remove_apu_config_setup; + + ret = apu_dram_boot_init(apu); + if (ret) + goto remove_apu_dram_boot; + + ret = apu_ipi_init(pdev, apu); + if (ret) + goto remove_apu_ipi; + + if (data->flags & F_AUTO_BOOT) { + ret = apu_deepidle_init(apu); + if (ret < 0) + goto remove_apu_deepidle; + } + + ret = apu_timesync_init(apu); + if (ret) + goto remove_apu_timesync; + + ret = apu_excep_init(apu); + if (ret < 0) + goto remove_apu_excep; + + if (data->flags & F_PRELOAD_FIRMWARE) + rproc->state = RPROC_DETACHED; + + ret = rproc_add(rproc); + if (ret < 0) { + dev_info(dev, "boot fail ret:%d\n", ret); + goto remove_apu_excep; + } + + if (hw_ops->init) { + ret = hw_ops->init(apu); + if (ret) + goto del_rproc; + } + + apu_pwr_wq = alloc_workqueue("apu_pwr_wq", + WQ_UNBOUND | WQ_HIGHPRI, 0); + if (!apu_pwr_wq) { + dev_info(dev, "%s: failed to allocate wq for rv power\n", + __func__); + goto del_rproc; + } + INIT_WORK(&apu->pwr_work, apu_power_work_fn); + apu_pwr_work = &apu->pwr_work; + + pm_runtime_put_sync(&pdev->dev); + dev_pm_genpd_add_notifier(dev, &apu_genpd_nb); + + return 0; + +del_rproc: + rproc_del(rproc); + +remove_apu_excep: + apu_excep_remove(apu); + +remove_apu_timesync: + apu_timesync_remove(apu); + +remove_apu_deepidle: + apu_deepidle_exit(apu); + +remove_apu_ipi: + apu_ipi_remove(apu); + +remove_apu_dram_boot: + apu_dram_boot_remove(apu); + +remove_apu_config_setup: + apu_config_remove(apu); + +remove_apu_sw_logger: + apu_sw_logger_remove(apu); + +remove_apu_memmap: + hw_ops->apu_memmap_remove(apu); + +out_free_rproc: + pm_runtime_put_sync(&pdev->dev); + pm_runtime_disable(&pdev->dev); + rproc_free(rproc); + + return ret; +} + +static int apu_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_apu *apu = platform_get_drvdata(pdev); + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + if (hw_ops->exit) + hw_ops->exit(apu); + + dev_pm_genpd_remove_notifier(dev); + pm_runtime_put_sync(&pdev->dev); + destroy_workqueue(apu_pwr_wq); + rproc_del(apu->rproc); + apu_deepidle_exit(apu); + apu_excep_remove(apu); + apu_timesync_remove(apu); + apu_ipi_remove(apu); + apu_dram_boot_remove(apu); + apu_config_remove(apu); + apu_sw_logger_remove(apu); + hw_ops->apu_memmap_remove(apu); + pm_runtime_disable(dev); + rproc_free(apu->rproc); + + return 0; +} + +static const struct of_device_id apu_of_match[] = { + { .compatible = "mediatek,mt8192-apusys-rv", .data = &mt8192_platdata}, + {}, +}; +MODULE_DEVICE_TABLE(of, apu_of_match); + +static int apu_runtime_suspend(struct device *dev) +{ + return 0; +} + +static int apu_runtime_resume(struct device *dev) +{ + struct mtk_apu *apu = dev_get_drvdata(dev); + struct mtk_apu_hw_ops *hw_ops = &apu->platdata->ops; + + if (!apu->boot_done) + return 0; + + if (hw_ops->resume) + return hw_ops->resume(apu); + + return 0; +} + +static const struct dev_pm_ops apu_pm_ops = { + SET_RUNTIME_PM_OPS(apu_runtime_suspend, apu_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, + pm_runtime_force_resume) +}; + +static struct platform_driver apu_driver = { + .probe = apu_probe, + .remove = apu_remove, + .driver = { + .name = "mtk-apu", + .of_match_table = of_match_ptr(apu_of_match), + .pm = &apu_pm_ops, + }, +}; + +int apu_rproc_init(struct apusys_core_info *info) +{ + dbg_root = info->dbg_root; + return platform_driver_register(&apu_driver); +} + +void apu_rproc_exit(void) +{ + platform_driver_unregister(&apu_driver); +} + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("MediaTek APU control driver"); diff --git a/drivers/soc/mediatek/apusys/apu-sw-logger.c b/drivers/soc/mediatek/apusys/apu-sw-logger.c new file mode 100644 index 000000000000..818b11cbaa29 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-sw-logger.c @@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu.h" +#include "apu-core.h" + +#define SW_LOGGER_DEV_NAME "apu_sw_logger" +#define APUSYS_LOGGER_DIR "logger" + +#define LOG_LINE_MAX_LENS 128 +#define APU_LOG_SIZE (1024 * 1024) +#define APU_LOG_BUF_SIZE (1024 * 1024) + +static struct dentry *log_root; +static struct dentry *log_seqlog; +static struct dentry *log_seqlogl; + +static void sw_logger_buf_invalidate(struct mtk_apu *apu) +{ + dma_sync_single_for_cpu(apu->dev, apu->handle, APU_LOG_SIZE, + DMA_FROM_DEVICE); +} + +static int sw_logger_buf_alloc(struct device *dev) +{ + struct mtk_apu *apu = dev_get_drvdata(dev); + int ret; + + ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(64)); + if (ret) + return ret; + + apu->sw_log_buf = kzalloc(APU_LOG_SIZE, GFP_KERNEL); + if (!apu->sw_log_buf) + return -ENOMEM; + + apu->handle = dma_map_single(dev, apu->sw_log_buf, APU_LOG_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(dev, apu->handle) != 0) { + kfree(apu->sw_log_buf); + apu->sw_log_buf = NULL; + return -EFAULT; + } + + return 0; +} + +int sw_logger_config_init(struct mtk_apu *apu) +{ + int ret; + unsigned long flags; + struct logger_init_info *st_logger_init_info; + + if (!apu || !apu->conf_buf) + return -EINVAL; + + if (!apu->sw_log_buf) { + ret = sw_logger_buf_alloc(apu->dev); + if (ret) { + dev_err(apu->dev, "%s: sw_logger_buf_alloc fail\n", + __func__); + return ret; + } + } + + spin_lock_irqsave(&apu->sw_logger_spinlock, flags); + iowrite32(0, apu->apu_mbox + LOG_W_PTR); + iowrite32(0, apu->apu_mbox + LOG_R_PTR); + iowrite32(0, apu->apu_mbox + LOG_OV_FLG); + spin_unlock_irqrestore(&apu->sw_logger_spinlock, flags); + + st_logger_init_info = (struct logger_init_info *) + get_apu_config_user_ptr(apu->conf_buf, LOGGER_INIT_INFO); + + st_logger_init_info->iova = apu->handle; + + return 0; +} + +void sw_logger_config_remove(struct mtk_apu *apu) +{ + if (apu->handle) + dma_unmap_single(apu->dev, apu->handle, + APU_LOG_SIZE, DMA_FROM_DEVICE); + kfree(apu->sw_log_buf); +} + +/* + * seq_start() takes a position as an argument and returns an iterator which + * will start reading at that position. + * start->show->next->show...->next->show->next->stop->start->stop + */ +static void *seq_start(struct seq_file *s, loff_t *pos) +{ + struct mtk_apu *apu = (struct mtk_apu *)s->private; + u32 w_ptr, r_ptr, overflow_flg; + unsigned long flags; + + if (!apu->sw_log_buf) { + pr_err("%s: sw_log_buf == NULL\n", __func__); + return NULL; + } + + spin_lock_irqsave(&apu->sw_logger_spinlock, flags); + w_ptr = ioread32(apu->apu_mbox + LOG_W_PTR); + r_ptr = ioread32(apu->apu_mbox + LOG_R_PTR); + overflow_flg = ioread32(apu->apu_mbox + LOG_OV_FLG); + spin_unlock_irqrestore(&apu->sw_logger_spinlock, flags); + + sw_logger_buf_invalidate(apu); + + if (w_ptr == r_ptr && overflow_flg == 0) + return NULL; + + if (!apu->pseqdata) { + apu->pseqdata = kzalloc(sizeof(*apu->pseqdata), GFP_KERNEL); + if (apu->pseqdata) { + apu->pseqdata->w_ptr = w_ptr; + apu->pseqdata->r_ptr = r_ptr; + apu->pseqdata->overflow_flg = overflow_flg; + if (overflow_flg == 0) + apu->pseqdata->i = r_ptr; + else + apu->pseqdata->i = w_ptr; + + apu->pseqdata->is_finished = 0; + } + } + + return apu->pseqdata; +} + +/* + * seq_start() takes a position as an argument and returns an iterator which + * will start reading at that position. + */ +static void *seq_startl(struct seq_file *s, loff_t *pos) +{ + struct mtk_apu *apu = s->private; + u32 w_ptr, r_ptr, overflow_flg; + struct sw_logger_seq_data *pseqdata_lock = &apu->pseqdata_lock; + unsigned long flags; + + if (!apu->sw_log_buf) + return NULL; + + spin_lock_irqsave(&apu->sw_logger_spinlock, flags); + w_ptr = ioread32(apu->apu_mbox + LOG_W_PTR); + r_ptr = ioread32(apu->apu_mbox + LOG_R_PTR); + overflow_flg = ioread32(apu->apu_mbox + LOG_OV_FLG); + spin_unlock_irqrestore(&apu->sw_logger_spinlock, flags); + + sw_logger_buf_invalidate(apu); + + /* for ctrl-c to force exit the loop */ + while (!signal_pending(current) && w_ptr == r_ptr) { + usleep_range(10000, 12000); + + spin_lock_irqsave(&apu->sw_logger_spinlock, flags); + w_ptr = ioread32(apu->apu_mbox + LOG_W_PTR); + r_ptr = ioread32(apu->apu_mbox + LOG_R_PTR); + overflow_flg = ioread32(apu->apu_mbox + LOG_OV_FLG); + spin_unlock_irqrestore(&apu->sw_logger_spinlock, flags); + + sw_logger_buf_invalidate(apu); + + pseqdata_lock->w_ptr = w_ptr; + pseqdata_lock->r_ptr = r_ptr; + pseqdata_lock->overflow_flg = overflow_flg; + pseqdata_lock->i = r_ptr; + } + + if (pseqdata_lock->startl_first || + pseqdata_lock->i == pseqdata_lock->w_ptr) { + pseqdata_lock->startl_first = false; + pseqdata_lock->w_ptr = w_ptr; + pseqdata_lock->r_ptr = r_ptr; + pseqdata_lock->overflow_flg = overflow_flg; + pseqdata_lock->i = r_ptr; + } + + if (signal_pending(current)) + pseqdata_lock->startl_first = true; + + return pseqdata_lock; +} + +/* + * move the iterator forward to the next position in the sequence + */ +static void *seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + struct sw_logger_seq_data *psdata = v; + + if (!psdata) { + pr_err("%s: psdata == NULL\n", __func__); + return NULL; + } + + psdata->i = (psdata->i + LOG_LINE_MAX_LENS) % APU_LOG_SIZE; + + /* prevent kernel warning */ + *pos = psdata->i; + + if (psdata->i != psdata->w_ptr) + return v; + + psdata->is_finished = 1; + return NULL; +} + +/* + * move the iterator forward to the next position in the sequence + */ +static void *seq_next_lock(struct seq_file *s, void *v, loff_t *pos) +{ + struct mtk_apu *apu = s->private; + struct sw_logger_seq_data *psdata = v; + + if (!psdata) { + pr_err("%s: psdata == NULL\n", __func__); + return NULL; + } + + psdata->i = (psdata->i + LOG_LINE_MAX_LENS) % APU_LOG_SIZE; + + /* prevent kernel warning */ + *pos = psdata->i; + + if (psdata->i != psdata->w_ptr) + return v; + + iowrite32(psdata->i, apu->apu_mbox + LOG_R_PTR); + return NULL; +} + +/* + * stop() is called when iteration is complete (clean up) + */ +static void seq_stop(struct seq_file *s, void *v) +{ + struct mtk_apu *apu = (struct mtk_apu *)s->private; + unsigned long flags; + + if (apu->pseqdata) { + if (apu->pseqdata->is_finished == 1) { + spin_lock_irqsave(&apu->sw_logger_spinlock, flags); + iowrite32(apu->pseqdata->i, apu->apu_mbox + LOG_R_PTR); + /* fixme: assume next overflow won't happen + * until next seq_start + */ + iowrite32(0, apu->apu_mbox + LOG_OV_FLG); + spin_unlock_irqrestore(&apu->sw_logger_spinlock, flags); + kfree(apu->pseqdata); + apu->pseqdata = NULL; + } + } +} + +/* + * stop() is called when iteration is complete (clean up) + */ +static void seq_stopl(struct seq_file *s, void *v) +{ +} + +/* + * success return 0, otherwise return error code + */ +static int seq_show(struct seq_file *s, void *v) +{ + struct mtk_apu *apu = (struct mtk_apu *)s->private; + struct sw_logger_seq_data *psdata = v; + + seq_printf(s, "%s", apu->sw_log_buf + psdata->i); + + return 0; +} + +static int seq_showl(struct seq_file *s, void *v) +{ + struct mtk_apu *apu = (struct mtk_apu *)s->private; + struct sw_logger_seq_data *psdata = v; + + if (psdata->i != psdata->w_ptr) + seq_printf(s, "%s", apu->sw_log_buf + psdata->i); + + return 0; +} + +static const struct seq_operations seq_ops = { + .start = seq_start, + .next = seq_next, + .stop = seq_stop, + .show = seq_show +}; + +static const struct seq_operations seq_ops_lock = { + .start = seq_startl, + .next = seq_next_lock, + .stop = seq_stopl, + .show = seq_showl +}; + +static int debug_sqopen_lock(struct inode *inode, struct file *file) +{ + struct mtk_apu *apu = inode->i_private; + int ret; + + ret = seq_open(file, &seq_ops_lock); + if (ret) + return ret; + + ((struct seq_file *)file->private_data)->private = apu; + + return 0; +} + +static int debug_sqopen(struct inode *inode, struct file *file) +{ + struct mtk_apu *apu = inode->i_private; + int ret; + + ret = seq_open(file, &seq_ops); + if (ret) + return ret; + + ((struct seq_file *)file->private_data)->private = apu; + + return 0; +} + +static const struct file_operations seqlog_ops = { + .owner = THIS_MODULE, + .open = debug_sqopen, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static const struct file_operations seqlogl_ops = { + .owner = THIS_MODULE, + .open = debug_sqopen_lock, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release, +}; + +static int sw_logger_create_debugfs(struct device *dev) +{ + struct mtk_apu *apu = dev_get_drvdata(dev); + int ret = 0; + + log_root = debugfs_create_dir(APUSYS_LOGGER_DIR, apu->dbg_root); + ret = IS_ERR_OR_NULL(log_root); + if (ret) { + dev_err(dev, "(%d)failed to create apusys_logger dir\n", ret); + goto out; + } + + log_seqlog = debugfs_create_file("seq_log", 0444, + log_root, apu, &seqlog_ops); + ret = IS_ERR_OR_NULL(log_seqlog); + if (ret) { + dev_err(dev, "(%d)failed to create apusys_logger node(seqlog)\n", + ret); + goto out; + } + + log_seqlogl = debugfs_create_file("seq_logl", 0444, + log_root, apu, &seqlogl_ops); + ret = IS_ERR_OR_NULL(log_seqlogl); + if (ret) { + dev_err(dev, "(%d)failed to create apusys_logger node(seqlogL)\n", + ret); + goto out; + } + + return 0; + +out: + debugfs_remove_recursive(log_root); + return ret; +} + +static void sw_logger_remove_debugfs(struct device *dev) +{ + debugfs_remove_recursive(log_root); +} + +int apu_sw_logger_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + int ret = 0; + + spin_lock_init(&apu->sw_logger_spinlock); + ret = sw_logger_create_debugfs(dev); + if (ret) { + dev_err(dev, "%s fail\n", __func__); + goto remove_debugfs; + } + + return 0; + +remove_debugfs: + sw_logger_remove_debugfs(dev); + dev_err(dev, "%s error!!\n", __func__); + + return ret; +} + +void apu_sw_logger_remove(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + + sw_logger_remove_debugfs(dev); +} diff --git a/drivers/soc/mediatek/apusys/apu.h b/drivers/soc/mediatek/apusys/apu.h new file mode 100644 index 000000000000..5bbc46416a19 --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef APU_H +#define APU_H +#include +#include +#include + +#include "apu-config.h" + +/* setup the SMC command ops */ +#define MTK_SIP_APU_START_MCU 0x00 +#define MTK_SIP_APU_STOP_MCU 0x01 + +/* md32_sysctrl register definition */ +#define MD32_SYS_CTRL 0x0 +#define MD32_MON_PC 0x838 +#define MD32_MON_LR 0x83c +#define MD32_MON_SP 0x840 +#define MD32_STATUS 0x844 + +/*wdt register */ +#define WDT_INT 0x0 +#define WDT_CTRL0 0x4 +#define WDT_EN BIT(31) + +/* apu_mbox spare regiter */ +#define MBOX0_SPARE0 0x40 +#define MBOX0_SPARE1 0x44 +#define MBOX0_SPARE2 0x48 +#define MBOX0_SPARE3 0x4C +#define MBOX6_SPARE0 0x640 +#define MBOX6_SPARE1 0x644 +#define MBOX6_SPARE2 0x648 +#define MBOX6_SPARE3 0x64C + +#define HOST_CONFIG_ADDR MBOX0_SPARE2 + +#define LOG_W_PTR (MBOX0_SPARE0) +#define LOG_R_PTR (MBOX0_SPARE1) +#define LOG_OV_FLG (MBOX0_SPARE3) + +/* rv setup */ +#define F_PRELOAD_FIRMWARE BIT(0) +#define F_AUTO_BOOT BIT(1) + +#define TCM_SIZE (128UL * 1024UL) +#define CODE_BUF_SIZE (1024UL * 1024UL) +#define DRAM_DUMP_SIZE (CODE_BUF_SIZE - TCM_SIZE) +#define REG_SIZE (4UL * 151UL) +#define TBUF_SIZE (4UL * 32UL) +#define CACHE_DUMP_SIZE (37UL * 1024UL) +#define DRAM_OFFSET (0x00000UL) +#define DRAM_DUMP_OFFSET (TCM_SIZE) +#define TCM_OFFSET (0x1d700000UL) +#define CODE_BUF_DA (DRAM_OFFSET) + +/* ipi */ +#define APU_FW_VER_LEN 32 +#define APU_SHARE_BUFFER_SIZE 256 + +#define IPI_LOCKED 1 +#define IPI_UNLOCKED 0 + +#define IPI_HOST_INITIATE 0 +#define IPI_APU_INITIATE 1 +#define IPI_WITH_ACK 1 +#define IPI_WITHOUT_ACK 0 + +enum { + APU_IPI_INIT = 0, + APU_IPI_NS_SERVICE, + APU_IPI_DEEP_IDLE, + APU_IPI_CTRL_RPMSG, + APU_IPI_MIDDLEWARE, + APU_IPI_REVISER_RPMSG, + APU_IPI_PWR_TX, + APU_IPI_PWR_RX, + APU_IPI_MDLA_TX, + APU_IPI_MDLA_RX, + APU_IPI_TIMESYNC, + APU_IPI_EDMA_TX, + APU_IPI_MNOC_TX, + APU_IPI_MAX, +}; + +struct mtk_apu; + +struct mtk_apu_hw_ops { + int (*init)(struct mtk_apu *apu); + int (*exit)(struct mtk_apu *apu); + int (*start)(struct mtk_apu *apu); + int (*stop)(struct mtk_apu *apu); + int (*resume)(struct mtk_apu *apu); + int (*apu_memmap_init)(struct mtk_apu *apu); + void (*apu_memmap_remove)(struct mtk_apu *apu); + void (*cg_gating)(struct mtk_apu *apu); + void (*cg_ungating)(struct mtk_apu *apu); + void (*rv_cachedump)(struct mtk_apu *apu); + + /* power related ops */ + int (*power_init)(struct mtk_apu *apu); + int (*power_on)(struct mtk_apu *apu); + int (*power_off)(struct mtk_apu *apu); +}; + +struct apu_ipi { + char *name; + unsigned int direction:1; + unsigned int ack:1; +}; + +struct mtk_apu_platdata { + u32 flags; + struct mtk_apu_hw_ops ops; + const struct apu_ipi *ipi_attrs; +}; + +struct dpidle_msg { + u32 cmd; + u32 ack; +}; + +struct apu_run { + s8 fw_ver[APU_FW_VER_LEN]; + u32 signaled; + wait_queue_head_t wq; +}; + +struct apu_ipi_desc { + struct mutex lock; /*ipi hanlder mutex */ + ipi_handler_t handler; + void *priv; + /* + * positive: host-initiated ipi outstanding count + * negative: apu-initiated ipi outstanding count + */ + int usage_cnt; +}; + +struct mtk_share_obj { + u8 share_buf[APU_SHARE_BUFFER_SIZE]; +}; + +struct sw_logger_seq_data { + u32 w_ptr; + u32 r_ptr; + u32 overflow_flg; + int i; + int is_finished; + char *data; + bool startl_first; +}; + +struct mtk_apu { + struct rproc *rproc; + struct device *dev; + void __iomem *apu_mbox; + void __iomem *md32_sysctrl; + void __iomem *apu_wdt; + int mbox0_irq_number; + int wdt_irq_number; + spinlock_t reg_lock; /* register r/w lock */ + + /* Buffer to place execution area */ + void *code_buf; + dma_addr_t code_da; + + /* Buffer to place config area */ + struct config_v1 *conf_buf; + dma_addr_t conf_da; + + /* to synchronize boot status of remote processor */ + struct apu_run run; + + /* to prevent multiple ipi_send run concurrently */ + struct mutex send_lock; + spinlock_t usage_cnt_lock; /* ipi occipued lock */ + struct apu_ipi_desc ipi_desc[APU_IPI_MAX]; + bool ipi_id_ack[APU_IPI_MAX]; /* per-ipi ack */ + bool ipi_inbound_locked; + wait_queue_head_t ack_wq; /* for waiting for ipi ack */ + + /* ipi */ + struct rproc_subdev *rpmsg_subdev; + dma_addr_t recv_buf_da; + struct mtk_share_obj *recv_buf; + dma_addr_t send_buf_da; + struct mtk_share_obj *send_buf; + + /* time sync */ + struct work_struct timesync_work; + struct workqueue_struct *timesync_wq; + u64 timesync_stamp; + + /*deep idle */ + struct dpidle_msg recv_msg; + struct work_struct deepidle_work; + struct workqueue_struct *apu_deepidle_workq; + struct work_struct pwron_dbg_wk; + + struct mtk_apu_platdata *platdata; + + /* link power deive */ + struct device *power_dev; + bool boot_done; + struct work_struct pwr_work; + + /* logger and debug */ + struct dentry *dbg_root; + dma_addr_t handle; + char *sw_log_buf; + spinlock_t sw_logger_spinlock; /* logger status update lock */ + struct sw_logger_seq_data pseqdata_lock; + struct sw_logger_seq_data *pseqdata; +}; + +struct apu_coredump { + char tcmdump[TCM_SIZE]; + char ramdump[DRAM_DUMP_SIZE]; + char regdump[REG_SIZE]; + char tbufdump[TBUF_SIZE]; + u32 cachedump[CACHE_DUMP_SIZE / sizeof(u32)]; +} __packed; + +int apu_ipi_config_init(struct mtk_apu *apu); +void apu_ipi_config_remove(struct mtk_apu *apu); +void apu_ipi_remove(struct mtk_apu *apu); +int apu_ipi_init(struct platform_device *pdev, struct mtk_apu *apu); +int apu_ipi_register(struct mtk_apu *apu, u32 id, + ipi_handler_t handler, void *priv); +void apu_ipi_unregister(struct mtk_apu *apu, u32 id); +int apu_ipi_send(struct mtk_apu *apu, u32 id, void *data, u32 len, + u32 wait_ms); +int apu_ipi_lock(struct mtk_apu *apu); +void apu_ipi_unlock(struct mtk_apu *apu); + +void apu_deepidle_power_on_aputop(struct mtk_apu *apu); + +#if IS_ENABLED(CONFIG_DEBUG_FS) +int sw_logger_config_init(struct mtk_apu *apu); +void sw_logger_config_remove(struct mtk_apu *apu); +int apu_sw_logger_init(struct mtk_apu *apu); +void apu_sw_logger_remove(struct mtk_apu *apu); +#else +static inline int sw_logger_config_init(struct mtk_apu *apu) { return 0; } +static inline void sw_logger_config_remove(struct mtk_apu *apu) { } +static inline int apu_sw_logger_init(struct mtk_apu *apu) { return 0; } +static inline void apu_sw_logger_remove(struct mtk_apu *apu) { } +#endif + +extern const struct mtk_apu_platdata mt8192_platdata; +#endif /* APU_H */ diff --git a/drivers/soc/mediatek/apusys/mt81xx-plat.c b/drivers/soc/mediatek/apusys/mt81xx-plat.c new file mode 100644 index 000000000000..54f75c8d07c3 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mt81xx-plat.c @@ -0,0 +1,320 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu.h" + +static const struct apu_ipi mt81xx_ipi_attrs[APU_IPI_MAX] = { + [APU_IPI_INIT] = { + .name = "init", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITHOUT_ACK, + }, + [APU_IPI_NS_SERVICE] = { + .name = "name-service", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITHOUT_ACK, + }, + [APU_IPI_DEEP_IDLE] = { + .name = "deep_idle", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_CTRL_RPMSG] = { + .name = "apu-ctrl-rpmsg", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_MIDDLEWARE] = { + .name = "apu-mdw-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_REVISER_RPMSG] = { + .name = "apu-reviser-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_PWR_TX] = { + .name = "apupwr-tx-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_PWR_RX] = { + .name = "apupwr-rx-rpmsg", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_MDLA_TX] = { + .name = "mdla-tx-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_MDLA_RX] = { + .name = "mdla-rx-rpmsg", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_TIMESYNC] = { + .name = "apu-timesync", + .direction = IPI_APU_INITIATE, + .ack = IPI_WITH_ACK, + }, + [APU_IPI_EDMA_TX] = { + .name = "apu-edma-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITHOUT_ACK, + }, + [APU_IPI_MNOC_TX] = { + .name = "apu-mnoc-rpmsg", + .direction = IPI_HOST_INITIATE, + .ack = IPI_WITHOUT_ACK, + }, +}; + +static void apu_reset_mcu(struct mtk_apu *apu) +{ + u32 reg; + + /* assert mcu reset */ + reg = ioread32(apu->md32_sysctrl); + iowrite32(reg & ~0x1, apu->md32_sysctrl); + mdelay(10); + iowrite32(reg | 0x1, apu->md32_sysctrl); +} + +static int apu_start_mcu(struct mtk_apu *apu) +{ + struct arm_smccc_res ares; + + /* initialize IOMMU and ACP config (iommu_tr_en=1, acp_en=0) */ + iowrite32(0xEA9, apu->md32_sysctrl); + + arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_SIP_APU_START_MCU, + 0, 0, 0, 0, 0, 0, &ares); + if (ares.a0) + dev_err(apu->dev, "start mcu fail: %lu\n", ares.a0); + + return 0; +} + +static int apu_stop_mcu(struct mtk_apu *apu) +{ + struct arm_smccc_res ares; + + arm_smccc_smc(MTK_SIP_APUSYS_CONTROL, MTK_SIP_APU_STOP_MCU, + 0, 0, 0, 0, 0, 0, &ares); + if (ares.a0) + dev_err(apu->dev, "stop mcufail: %lu\n", ares.a0); + + return 0; +} + +static int mt8192_rproc_start(struct mtk_apu *apu) +{ + apu_reset_mcu(apu); + apu_start_mcu(apu); + + return 0; +} + +static int mt8192_rproc_resume(struct mtk_apu *apu) +{ + apu_start_mcu(apu); + + return 0; +} + +static int mt8192_rproc_stop(struct mtk_apu *apu) +{ + unsigned long flags; + + spin_lock_irqsave(&apu->reg_lock, flags); + /* disable apu wdt */ + iowrite32(ioread32(apu->apu_wdt + WDT_CTRL0) & ~WDT_EN, + apu->apu_wdt + WDT_CTRL0); + /* clear wdt interrupt */ + iowrite32(0x1, apu->apu_wdt); + spin_unlock_irqrestore(&apu->reg_lock, flags); + + /* Hold runstall */ + apu_stop_mcu(apu); + return 0; +} + +static int mt81xx_apu_power_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + struct device_node *np; + struct platform_device *pdev; + + /* power dev */ + np = of_parse_phandle(dev->of_node, "mediatek,apusys-power", 0); + if (!np) { + dev_info(dev, "failed to parse apusys_power node\n"); + return -EINVAL; + } + + if (!of_device_is_available(np)) { + dev_info(dev, "unable to find apusys_power node\n"); + of_node_put(np); + return -ENODEV; + } + + pdev = of_find_device_by_node(np); + if (!pdev) { + dev_info(dev, "apusys_power is not ready yet\n"); + of_node_put(np); + return -EPROBE_DEFER; + } + + dev_info(dev, "%s: get power_dev, name=%s\n", __func__, pdev->name); + + apu->power_dev = &pdev->dev; + of_node_put(np); + + return 0; +} + +static int mt81xx_apu_power_on(struct mtk_apu *apu) +{ + int ret; + + ret = pm_runtime_get_sync(apu->dev); + if (ret < 0) { + dev_info(apu->dev, + "%s: call to get_sync(dev) failed, ret=%d\n", + __func__, ret); + return ret; + } + + return 0; +} + +static int mt81xx_apu_power_off(struct mtk_apu *apu) +{ + int ret, timeout; + u32 val; + + /* wait remote power state */ + ret = readl_relaxed_poll_timeout(apu->apu_mbox + MBOX6_SPARE3, + val, + (val & BIT(0)), + 10, 25000); + if (ret) { + dev_err(apu->dev, "Remote WFI not ready\n"); + return ret; + } + + ret = pm_runtime_put_sync(apu->dev); + if (ret) { + dev_info(apu->dev, + "%s: call to put_sync(dev) failed, ret=%d\n", + __func__, ret); + return ret; + } + + /* polling APU TOP rpm state till suspended */ + dev_info(apu->dev, "start polling power off\n"); + timeout = 500; + while (!pm_runtime_suspended(apu->power_dev) && timeout-- > 0) + msleep(20); + if (timeout <= 0) { + dev_info(apu->dev, "%s: polling power off timeout!!\n", + __func__); + apu_ipi_unlock(apu); + WARN_ON(0); + ret = -ETIMEDOUT; + goto error_get_power_dev; + } + + dev_info(apu->dev, "polling power done\n"); + + return 0; + +error_get_power_dev: + pm_runtime_get_sync(apu->power_dev); + + return ret; +} + +static int mt8192_apu_memmap_init(struct mtk_apu *apu) +{ + struct device *dev = apu->dev; + struct platform_device *pdev = to_platform_device(dev); + struct resource *res; + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apu_mbox"); + if (!res) { + dev_info(dev, "%s: apu_mbox get resource fail\n", __func__); + return -ENODEV; + } + apu->apu_mbox = ioremap(res->start, res->end - res->start + 1); + if (IS_ERR((void const *)apu->apu_mbox)) { + dev_info(dev, "%s: apu_mbox remap base fail\n", __func__); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, + IORESOURCE_MEM, "md32_sysctrl"); + if (!res) { + dev_info(dev, "%s: md32_sysctrl get resource fail\n", __func__); + return -ENODEV; + } + apu->md32_sysctrl = ioremap(res->start, res->end - res->start + 1); + if (IS_ERR((void const *)apu->md32_sysctrl)) { + dev_info(dev, "%s: md32_sysctrl remap base fail\n", __func__); + return -ENOMEM; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "apu_wdt"); + if (!res) { + dev_info(dev, "%s: apu_wdt get resource fail\n", __func__); + return -ENODEV; + } + apu->apu_wdt = ioremap(res->start, res->end - res->start + 1); + if (IS_ERR((void const *)apu->apu_wdt)) { + dev_info(dev, "%s: apu_wdt remap base fail\n", __func__); + return -ENOMEM; + } + + return 0; +} + +static void mt8192_apu_memmap_remove(struct mtk_apu *apu) +{ + iounmap(apu->apu_wdt); + iounmap(apu->md32_sysctrl); + iounmap(apu->apu_mbox); +} + +const struct mtk_apu_platdata mt8192_platdata = { + .flags = F_AUTO_BOOT, + .ipi_attrs = mt81xx_ipi_attrs, + .ops = { + .init = NULL, + .exit = NULL, + .start = mt8192_rproc_start, + .stop = mt8192_rproc_stop, + .resume = mt8192_rproc_resume, + .apu_memmap_init = mt8192_apu_memmap_init, + .apu_memmap_remove = mt8192_apu_memmap_remove, + .cg_gating = NULL, + .cg_ungating = NULL, + .rv_cachedump = NULL, + .power_init = mt81xx_apu_power_init, + .power_on = mt81xx_apu_power_on, + .power_off = mt81xx_apu_power_off, + }, +}; From patchwork Sat Oct 23 11:14:05 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579567 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6623FC433EF for ; Sat, 23 Oct 2021 11:18:57 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 285B360FD8 for ; Sat, 23 Oct 2021 11:18:57 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 285B360FD8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=xw+YjAZE1ZnUIRTTUt63LIYYmX+h36Wo26dnH/kAgkI=; b=lUpZEvyzOjqzIh nAGVNqknS8Na4NcVg0dl2U8lgzCR/kdzQJZKeXHQeLEZvuKe9FNuptHYPdbYGVF/hf/GLQDcf9nIO Zlqv8UtLHP5WW7vu1U56GRgxnDv9LCP11+wy1KMFlDKpFODz+cxDmkJegIthbsPdhRYj40dqWPMKM 396DDxbB5SxnO1QldDX7hWENxknnCkOvgdZ0S9wPE61QbiT/7XqMw+5zPN+O7MoKh4OVGiXvHA1Gz 1IVhlvRunQqoZxE1cIpDGTDNRjE+IRgt+xsg6dU/6IYPwfaTJbwNkZkv/5W+tE8CVYAxMwR22l9kE jjhLcOzdtTWy9pQ4mCaw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF1D-00CdTR-FK; Sat, 23 Oct 2021 11:16:56 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzQ-00CcPQ-Vr; Sat, 23 Oct 2021 11:15:10 +0000 X-UUID: 426d6375ab02410cbc1a22ac48354495-20211023 X-UUID: 426d6375ab02410cbc1a22ac48354495-20211023 Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1299922170; Sat, 23 Oct 2021 04:15:01 -0700 Received: from mtkmbs10n1.mediatek.inc (172.21.101.34) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:14:59 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Sat, 23 Oct 2021 19:14:57 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:57 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen , JB Tsai Subject: [RFC 09/13] soc: mediatek: apu: Add middleware driver Date: Sat, 23 Oct 2021 19:14:05 +0800 Message-ID: <20211023111409.30463-10-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041505_198022_55108E25 X-CRM114-Status: GOOD ( 25.04 ) X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org APU middleware is responsible to receive all user's requests and control command and device related flow. In Kernel side, the middleware use the IPI to send command to remote tinysys to dispatch commands to AI engines in APU. Signed-off-by: JB Tsai Signed-off-by: Flora Fu --- drivers/soc/mediatek/apusys/Makefile | 9 + drivers/soc/mediatek/apusys/apu-core.c | 2 + drivers/soc/mediatek/apusys/apu-core.h | 2 + drivers/soc/mediatek/apusys/apu-device.h | 39 + drivers/soc/mediatek/apusys/mdw-cmd.c | 618 +++++++++++++++ drivers/soc/mediatek/apusys/mdw-drv.c | 211 +++++ drivers/soc/mediatek/apusys/mdw-ioctl.c | 331 ++++++++ drivers/soc/mediatek/apusys/mdw-ioctl.h | 256 +++++++ drivers/soc/mediatek/apusys/mdw-mem.c | 938 +++++++++++++++++++++++ drivers/soc/mediatek/apusys/mdw-mem.h | 23 + drivers/soc/mediatek/apusys/mdw-rv-cmd.c | 158 ++++ drivers/soc/mediatek/apusys/mdw-rv-dev.c | 386 ++++++++++ drivers/soc/mediatek/apusys/mdw-rv-msg.h | 90 +++ drivers/soc/mediatek/apusys/mdw-rv.c | 131 ++++ drivers/soc/mediatek/apusys/mdw-rv.h | 98 +++ drivers/soc/mediatek/apusys/mdw-sysfs.c | 200 +++++ drivers/soc/mediatek/apusys/mdw.h | 208 +++++ 17 files changed, 3700 insertions(+) create mode 100644 drivers/soc/mediatek/apusys/apu-device.h create mode 100644 drivers/soc/mediatek/apusys/mdw-cmd.c create mode 100644 drivers/soc/mediatek/apusys/mdw-drv.c create mode 100644 drivers/soc/mediatek/apusys/mdw-ioctl.c create mode 100644 drivers/soc/mediatek/apusys/mdw-ioctl.h create mode 100644 drivers/soc/mediatek/apusys/mdw-mem.c create mode 100644 drivers/soc/mediatek/apusys/mdw-mem.h create mode 100644 drivers/soc/mediatek/apusys/mdw-rv-cmd.c create mode 100644 drivers/soc/mediatek/apusys/mdw-rv-dev.c create mode 100644 drivers/soc/mediatek/apusys/mdw-rv-msg.h create mode 100644 drivers/soc/mediatek/apusys/mdw-rv.c create mode 100644 drivers/soc/mediatek/apusys/mdw-rv.h create mode 100644 drivers/soc/mediatek/apusys/mdw-sysfs.c create mode 100644 drivers/soc/mediatek/apusys/mdw.h diff --git a/drivers/soc/mediatek/apusys/Makefile b/drivers/soc/mediatek/apusys/Makefile index 490de0ee4727..dee3b1f0a1e7 100644 --- a/drivers/soc/mediatek/apusys/Makefile +++ b/drivers/soc/mediatek/apusys/Makefile @@ -13,3 +13,12 @@ apu-objs += apu-ipi.o apu-objs += apu-mbox.o apu-objs += mt81xx-plat.o apu-$(CONFIG_DEBUG_FS) += apu-sw-logger.o + +apu-objs += mdw-drv.o +apu-objs += mdw-ioctl.o +apu-objs += mdw-mem.o +apu-objs += mdw-cmd.o +apu-objs += mdw-rv.o +apu-objs += mdw-rv-cmd.o +apu-objs += mdw-rv-dev.o +apu-$(CONFIG_DEBUG_FS) += mdw-sysfs.o diff --git a/drivers/soc/mediatek/apusys/apu-core.c b/drivers/soc/mediatek/apusys/apu-core.c index 80652b1d056e..ecad5660ee18 100644 --- a/drivers/soc/mediatek/apusys/apu-core.c +++ b/drivers/soc/mediatek/apusys/apu-core.c @@ -19,6 +19,7 @@ static struct apusys_core_info g_core_info; */ static int (*apusys_init_func[])(struct apusys_core_info *) = { apu_power_drv_init, + mdw_init, apu_rproc_init, }; @@ -28,6 +29,7 @@ static int (*apusys_init_func[])(struct apusys_core_info *) = { */ static void (*apusys_exit_func[])(void) = { apu_rproc_exit, + mdw_exit, apu_power_drv_exit, }; diff --git a/drivers/soc/mediatek/apusys/apu-core.h b/drivers/soc/mediatek/apusys/apu-core.h index b47d95f0a1ae..7d8d6033ab07 100644 --- a/drivers/soc/mediatek/apusys/apu-core.h +++ b/drivers/soc/mediatek/apusys/apu-core.h @@ -11,6 +11,8 @@ struct apusys_core_info { int apu_power_drv_init(struct apusys_core_info *info); void apu_power_drv_exit(void); +int mdw_init(struct apusys_core_info *info); +void mdw_exit(void); int apu_rproc_init(struct apusys_core_info *info); void apu_rproc_exit(void); #endif diff --git a/drivers/soc/mediatek/apusys/apu-device.h b/drivers/soc/mediatek/apusys/apu-device.h new file mode 100644 index 000000000000..dddd8a3ddf8d --- /dev/null +++ b/drivers/soc/mediatek/apusys/apu-device.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef APUSYS_DEVICE_H +#define APUSYS_DEVICE_H + +#include + +/* device type */ +enum { + APUSYS_DEVICE_NONE, + + APUSYS_DEVICE_SAMPLE, + APUSYS_DEVICE_MDLA, + APUSYS_DEVICE_VPU, + APUSYS_DEVICE_EDMA, + APUSYS_DEVICE_RT = 32, + APUSYS_DEVICE_SAMPLE_RT, + APUSYS_DEVICE_MDLA_RT, + APUSYS_DEVICE_VPU_RT, + + APUSYS_DEVICE_MAX = 64, +}; + +/* device definition */ +#define APUSYS_DEVICE_META_SIZE (32) + +struct apusys_device { + int dev_type; + int idx; + int preempt_type; + u8 preempt_level; + char meta_data[APUSYS_DEVICE_META_SIZE]; + void *private; + int (*send_cmd)(int type, void *hnd, struct apusys_device *dev); +}; +#endif diff --git a/drivers/soc/mediatek/apusys/mdw-cmd.c b/drivers/soc/mediatek/apusys/mdw-cmd.c new file mode 100644 index 000000000000..231a82b4ba0e --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-cmd.c @@ -0,0 +1,618 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include + +#include "mdw.h" +#include "mdw-mem.h" + +static struct mdw_mem *mdw_cmd_get_mem(u64 handle) +{ + struct mdw_mem *m = NULL; + + m = mdw_mem_get(handle); + if (!m) + return NULL; + + mdw_mem_dma_map(m); + + return m; +} + +static int mdw_cmd_put_mem(struct mdw_mem *m) +{ + return mdw_mem_dma_unmap(m); +} + +static void mdw_cmd_put_cmdbufs(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + struct mdw_subcmd_kinfo *ksubcmd = NULL; + unsigned int i = 0, j = 0; + + if (!c->cmdbufs) + return; + + /* flush cmdbufs and execinfos */ + apusys_mem_invalidate_kva(c->cmdbufs->vaddr, c->cmdbufs->size); + + for (i = 0; i < c->num_subcmds; i++) { + ksubcmd = &c->ksubcmds[i]; + for (j = 0; j < ksubcmd->info->num_cmdbufs; j++) { + if (!ksubcmd->ori_cbs[j]) + continue; + + /* cmdbuf copy out */ + if (ksubcmd->cmdbufs[j].direction != MDW_CB_IN) + memcpy + (ksubcmd->ori_cbs[j]->vaddr, + (void *)ksubcmd->kvaddrs[j], + ksubcmd->ori_cbs[j]->size + ); + + mdw_cmd_put_mem(ksubcmd->ori_cbs[j]); + ksubcmd->ori_cbs[j] = NULL; + } + } + mdw_mem_unmap(c->cmdbufs); + mdw_mem_free(c->cmdbufs); + + c->cmdbufs = NULL; +} + +static int mdw_cmd_get_cmdbufs(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + unsigned int i = 0, j = 0, ofs = 0; + int ret = -EINVAL; + struct mdw_subcmd_kinfo *ksubcmd = NULL; + struct mdw_mem *m = NULL; + struct device *dev = mpriv->mdev->dev; + + if (!c->size_cmdbufs || c->cmdbufs) + goto out; + + /* alloc cmdbuf by dmabuf */ + c->cmdbufs = mdw_mem_alloc + (mpriv, c->size_cmdbufs, MDW_DEFAULT_ALIGN, + (1ULL << MDW_MEM_IOCTL_ALLOC_CACHEABLE | + 1ULL << MDW_MEM_IOCTL_ALLOC_32BIT), + MDW_MEM_TYPE_INTERNAL); + if (!c->cmdbufs) { + dev_err(dev, "mem alloc fail\n"); + ret = -ENOMEM; + goto out; + } + + ret = mdw_mem_map(c->cmdbufs); + if (ret) { + dev_err(dev, "mem map fail\n"); + mdw_mem_free(c->cmdbufs); + ret = -ENOMEM; + goto out; + } + + /* alloc mem for duplicated cmdbuf */ + for (i = 0; i < c->num_subcmds; i++) { + ksubcmd = &c->ksubcmds[i]; + for (j = 0; j < ksubcmd->info->num_cmdbufs; j++) { + /* calc align */ + if (ksubcmd->cmdbufs[j].align) + ofs = MDW_ALIGN(ofs, ksubcmd->cmdbufs[j].align); + else + ofs = MDW_ALIGN(ofs, MDW_DEFAULT_ALIGN); + + /* get mem from handle */ + m = mdw_cmd_get_mem(ksubcmd->cmdbufs[j].handle); + if (!m) { + dev_err(dev, "cmd get mem fail\n"); + goto free_cmdbufs; + } + /* check mem boundary */ + if (!m->vaddr || ksubcmd->cmdbufs[j].size != m->size) { + dev_err(dev, "size of cmdbuf is invalid\n"); + goto free_cmdbufs; + } + + /* cmdbuf copy in */ + if (ksubcmd->cmdbufs[j].direction != MDW_CB_OUT) + memcpy(c->cmdbufs->vaddr + ofs, + m->vaddr, + ksubcmd->cmdbufs[j].size); + + /* record buffer info */ + ksubcmd->ori_cbs[j] = m; + ksubcmd->kvaddrs[j] = + (u64)(c->cmdbufs->vaddr + ofs); + ksubcmd->daddrs[j] = + (u64)(c->cmdbufs->device_va + ofs); + ofs += ksubcmd->cmdbufs[j].size; + } + } + /* flush cmdbufs */ + apusys_mem_flush_kva(c->cmdbufs->vaddr, c->cmdbufs->size); + + ret = 0; + goto out; + +free_cmdbufs: + mdw_cmd_put_cmdbufs(mpriv, c); +out: + return ret; +} + +static unsigned int mdw_cmd_create_infos(struct mdw_fpriv *mpriv, + struct mdw_cmd *c) +{ + unsigned int i = 0, j = 0, total_size = 0; + struct mdw_subcmd_exec_info *sc_einfo = NULL; + int ret = -ENOMEM; + + c->einfos = c->exec_infos->vaddr; + if (!c->einfos) { + dev_err(mpriv->mdev->dev, "invalid exec info addr\n"); + return -EINVAL; + } + sc_einfo = &c->einfos->sc; + + for (i = 0; i < c->num_subcmds; i++) { + c->ksubcmds[i].info = &c->subcmds[i]; + + c->ksubcmds[i].ori_cbs = kvzalloc(c->subcmds[i].num_cmdbufs * + sizeof(c->ksubcmds[i].ori_cbs), GFP_KERNEL); + if (!c->ksubcmds[i].ori_cbs) + goto free_cmdbufs; + + c->ksubcmds[i].kvaddrs = kvzalloc(c->subcmds[i].num_cmdbufs * + sizeof(*c->ksubcmds[i].kvaddrs), GFP_KERNEL); + if (!c->ksubcmds[i].kvaddrs) + goto free_cmdbufs; + + c->ksubcmds[i].daddrs = kvzalloc(c->subcmds[i].num_cmdbufs * + sizeof(*c->ksubcmds[i].daddrs), GFP_KERNEL); + if (!c->ksubcmds[i].daddrs) + goto free_cmdbufs; + + c->ksubcmds[i].cmdbufs = kvzalloc(c->subcmds[i].num_cmdbufs * + sizeof(*c->ksubcmds[i].cmdbufs), GFP_KERNEL); + if (!c->ksubcmds[i].cmdbufs) + goto free_cmdbufs; + + if (copy_from_user(c->ksubcmds[i].cmdbufs, + (void __user *)c->subcmds[i].cmdbufs, + c->subcmds[i].num_cmdbufs * + sizeof(*c->ksubcmds[i].cmdbufs))) + goto free_cmdbufs; + + c->ksubcmds[i].sc_einfo = &sc_einfo[i]; + + /* accumulate cmdbuf size with alignment */ + for (j = 0; j < c->subcmds[i].num_cmdbufs; j++) { + c->num_cmdbufs++; + if (c->ksubcmds[i].cmdbufs[j].align) + total_size = + MDW_ALIGN(total_size, + c->ksubcmds[i].cmdbufs[j].align) + + c->ksubcmds[i].cmdbufs[j].size; + else + total_size += c->ksubcmds[i].cmdbufs[j].size; + } + } + c->size_cmdbufs = total_size; + + ret = mdw_cmd_get_cmdbufs(mpriv, c); + if (ret) + goto free_cmdbufs; + + goto out; + +free_cmdbufs: + for (i = 0; i < c->num_subcmds; i++) { + /* free dvaddrs */ + if (c->ksubcmds[i].daddrs) { + kvfree(c->ksubcmds[i].daddrs); + c->ksubcmds[i].daddrs = NULL; + } + /* free kvaddrs */ + if (c->ksubcmds[i].kvaddrs) { + kvfree(c->ksubcmds[i].kvaddrs); + c->ksubcmds[i].kvaddrs = NULL; + } + /* free ori kvas */ + if (c->ksubcmds[i].ori_cbs) { + kvfree(c->ksubcmds[i].ori_cbs); + c->ksubcmds[i].ori_cbs = NULL; + } + /* free cmdbufs */ + if (c->ksubcmds[i].cmdbufs) { + kvfree(c->ksubcmds[i].cmdbufs); + c->ksubcmds[i].cmdbufs = NULL; + } + } + +out: + return ret; +} + +static void mdw_cmd_delete_infos(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + unsigned int i = 0; + + mdw_cmd_put_cmdbufs(mpriv, c); + + for (i = 0; i < c->num_subcmds; i++) { + /* free dvaddrs */ + if (c->ksubcmds[i].daddrs) { + kvfree(c->ksubcmds[i].daddrs); + c->ksubcmds[i].daddrs = NULL; + } + /* free kvaddrs */ + if (c->ksubcmds[i].kvaddrs) { + kvfree(c->ksubcmds[i].kvaddrs); + c->ksubcmds[i].kvaddrs = NULL; + } + /* free ori kvas */ + if (c->ksubcmds[i].ori_cbs) { + kvfree(c->ksubcmds[i].ori_cbs); + c->ksubcmds[i].ori_cbs = NULL; + } + /* free cmdbufs */ + if (c->ksubcmds[i].cmdbufs) { + kvfree(c->ksubcmds[i].cmdbufs); + c->ksubcmds[i].cmdbufs = NULL; + } + } +} + +static const char *mdw_fence_get_driver_name(struct dma_fence *fence) +{ + return "apu_mdw"; +} + +static const char *mdw_fence_get_timeline_name(struct dma_fence *fence) +{ + struct mdw_fence *f = + container_of(fence, struct mdw_fence, base_fence); + + return dev_name(f->mdev->misc_dev.this_device); +} + +static bool mdw_fence_enable_signaling(struct dma_fence *fence) +{ + return true; +} + +static void mdw_fence_release(struct dma_fence *fence) +{ + struct mdw_fence *mf = + container_of(fence, struct mdw_fence, base_fence); + + kvfree(mf); +} + +static const struct dma_fence_ops mdw_fence_ops = { + .get_driver_name = mdw_fence_get_driver_name, + .get_timeline_name = mdw_fence_get_timeline_name, + .enable_signaling = mdw_fence_enable_signaling, + .wait = dma_fence_default_wait, + .release = mdw_fence_release, +}; + +static int mdw_fence_init(struct mdw_cmd *c) +{ + int ret = 0; + + c->fence = kvzalloc(sizeof(*c->fence), GFP_KERNEL); + if (!c->fence) + return -ENOMEM; + + c->fence->mdev = c->mpriv->mdev; + dma_fence_init(&c->fence->base_fence, &mdw_fence_ops, + &c->fence->lock, 0, 0); + spin_lock_init(&c->fence->lock); + + return ret; +} + +static int mdw_cmd_run(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + struct mdw_device *mdev = mpriv->mdev; + int ret = 0; + + ktime_get_ts64(&c->start_ts); + ret = mdev->dev_funcs->run_cmd(mpriv, c); + if (ret) { + dev_err(mpriv->mdev->dev, "run cmd(0x%llx/0x%llx) fail(%d)\n", + (u64)c->mpriv, c->kid, ret); + + dma_fence_set_error(&c->fence->base_fence, ret); + dma_fence_signal(&c->fence->base_fence); + dma_fence_put(&c->fence->base_fence); + } + + return ret; +} + +static void mdw_cmd_delete(struct mdw_cmd *c) +{ + struct mdw_fpriv *mpriv = c->mpriv; + + mdw_cmd_delete_infos(c->mpriv, c); + mdw_cmd_put_mem(c->exec_infos); + kvfree(c->adj_matrix); + kvfree(c->ksubcmds); + kvfree(c->subcmds); + mutex_lock(&mpriv->mtx); + list_del(&c->u_item); + mutex_unlock(&mpriv->mtx); + kvfree(c); + + mpriv->put(mpriv); +} + +static int mdw_cmd_complete(struct mdw_cmd *c, int ret) +{ + struct dma_fence *f = &c->fence->base_fence; + + ktime_get_ts64(&c->end_ts); + c->einfos->c.total_us = + (c->end_ts.tv_sec - c->start_ts.tv_sec) * 1000000; + c->einfos->c.total_us += + ((c->end_ts.tv_nsec - c->start_ts.tv_nsec) / 1000); + + /* check subcmds return value */ + if (c->einfos->c.sc_rets) + if (!ret) + ret = -EIO; + + c->einfos->c.ret = ret; + + if (ret) + pr_debug("cmd(%p/0x%llx) ret(%d/0x%llx) time(%llu) pid(%d/%d)\n", + c->mpriv, c->kid, ret, c->einfos->c.sc_rets, + c->einfos->c.total_us, c->pid, c->tgid); + + mdw_cmd_put_cmdbufs(c->mpriv, c); + if (ret) + dma_fence_set_error(&c->fence->base_fence, ret); + + dma_fence_signal(f); + mdw_cmd_delete(c); + dma_fence_put(f); + + return 0; +} + +static void mdw_cmd_trigger_func(struct work_struct *wk) +{ + struct mdw_cmd *c = + container_of(wk, struct mdw_cmd, t_wk); + + if (c->wait_fence) { + dma_fence_wait(c->wait_fence, false); + dma_fence_put(c->wait_fence); + } + + mdw_cmd_run(c->mpriv, c); +} + +static int mdw_cmd_sanity_check(struct mdw_cmd *c) +{ + if (c->priority >= MDW_PRIORITY_MAX || + c->num_subcmds > MDW_SUBCMD_MAX) { + pr_err("cmd invalid (0x%llx/0x%llx/0x%llx)(%u/%u)\n", + c->uid, (u64)c->mpriv, c->kid, + c->priority, c->num_subcmds); + return -EINVAL; + } + + if (c->exec_infos->size != sizeof(struct mdw_cmd_exec_info) + + c->num_subcmds * sizeof(struct mdw_subcmd_exec_info)) { + pr_err("cmd invalid (0x%llx/0x%llx/0x%llx) einfo(%u/%lu)\n", + c->uid, (u64)c->mpriv, c->kid, + c->exec_infos->size, + sizeof(struct mdw_cmd_exec_info) + + c->num_subcmds * sizeof(struct mdw_subcmd_exec_info)); + return -EINVAL; + } + + return 0; +} + +static int mdw_cmd_sc_sanity_check(struct mdw_cmd *c) +{ + unsigned int i = 0; + + for (i = 0; i < c->num_subcmds; i++) { + if (c->subcmds[i].type >= MDW_DEV_MAX || + c->subcmds[i].vlm_ctx_id >= MDW_SUBCMD_MAX || + c->subcmds[i].boost > MDW_BOOST_MAX || + c->subcmds[i].pack_id >= MDW_SUBCMD_MAX) { + pr_err("subcmd(%u) invalid (%u/%u/%u)\n", + i, c->subcmds[i].type, + c->subcmds[i].boost, + c->subcmds[i].pack_id); + return -EINVAL; + } + } + + return 0; +} + +static struct mdw_cmd *mdw_cmd_create(struct mdw_fpriv *mpriv, + union mdw_cmd_args *args) +{ + struct mdw_cmd_in *in = (struct mdw_cmd_in *)args; + struct mdw_cmd *c = NULL; + + if (in->exec.num_subcmds > MDW_SUBCMD_MAX) { + dev_err(mpriv->mdev->dev, "too much subcmds(%u)\n", + in->exec.num_subcmds); + goto out; + } + + c = kvzalloc(sizeof(*c), GFP_KERNEL); + if (!c) + goto out; + + c->mpriv = mpriv; + c->pid = current->pid; + c->tgid = current->tgid; + c->kid = (u64)c; + c->uid = in->exec.uid; + c->usr_id = in->exec.usr_id; + c->priority = in->exec.priority; + c->hardlimit = in->exec.hardlimit; + c->softlimit = in->exec.softlimit; + c->power_save = in->exec.power_save; + c->power_plcy = in->exec.power_plcy; + c->power_dtime = in->exec.power_dtime; + c->app_type = in->exec.app_type; + c->num_subcmds = in->exec.num_subcmds; + c->exec_infos = mdw_cmd_get_mem(in->exec.exec_infos); + if (!c->exec_infos) { + dev_err(mpriv->mdev->dev, "get exec info fail\n"); + goto free_cmd; + } + + if (mdw_cmd_sanity_check(c)) { + dev_err(mpriv->mdev->dev, "cmd sanity check fail\n"); + goto free_cmd; + } + + c->subcmds = kvzalloc(c->num_subcmds * sizeof(*c->subcmds), GFP_KERNEL); + if (!c->subcmds) + goto free_cmd; + if (copy_from_user(c->subcmds, (void __user *)in->exec.subcmd_infos, + c->num_subcmds * sizeof(*c->subcmds))) { + dev_err(mpriv->mdev->dev, "copy subcmds fail\n"); + goto free_subcmds; + } + if (mdw_cmd_sc_sanity_check(c)) { + dev_err(mpriv->mdev->dev, "sc sanity check fail\n"); + goto free_subcmds; + } + + c->ksubcmds = kvzalloc(c->num_subcmds * sizeof(*c->ksubcmds), + GFP_KERNEL); + if (!c->ksubcmds) + goto free_subcmds; + + /* adj matrix */ + c->adj_matrix = kvzalloc(c->num_subcmds * + c->num_subcmds * sizeof(u8), GFP_KERNEL); + if (!c->adj_matrix) + goto free_ksubcmds; + if (copy_from_user(c->adj_matrix, (void __user *)in->exec.adj_matrix, + (c->num_subcmds * c->num_subcmds * sizeof(u8))) + ) { + dev_err(mpriv->mdev->dev, "copy adj matrix fail\n"); + goto free_adj; + } + if (mdw_cmd_create_infos(mpriv, c)) { + dev_err(mpriv->mdev->dev, "create cmd info fail\n"); + goto put_execinfo; + } + if (mdw_fence_init(c)) { + dev_err(mpriv->mdev->dev, "cmd init fence fail\n"); + goto delete_infos; + } + + c->mpriv->get(c->mpriv); + c->complete = mdw_cmd_complete; + INIT_WORK(&c->t_wk, &mdw_cmd_trigger_func); + mutex_lock(&mpriv->mtx); + list_add_tail(&c->u_item, &mpriv->cmds); + mutex_unlock(&mpriv->mtx); + + goto out; + +delete_infos: + mdw_cmd_delete_infos(mpriv, c); +put_execinfo: + mdw_cmd_put_mem(c->exec_infos); +free_adj: + kvfree(c->adj_matrix); +free_ksubcmds: + kvfree(c->ksubcmds); +free_subcmds: + kvfree(c->subcmds); +free_cmd: + kvfree(c); + c = NULL; +out: + return c; +} + +static int mdw_cmd_ioctl_run(struct mdw_fpriv *mpriv, union mdw_cmd_args *args) +{ + struct mdw_cmd_in *in = (struct mdw_cmd_in *)args; + struct mdw_cmd *c = NULL; + struct sync_file *sync_file = NULL; + int ret = 0, fd = 0, wait_fd = 0; + + wait_fd = in->exec.fence; + + c = mdw_cmd_create(mpriv, args); + if (!c) { + dev_err(mpriv->mdev->dev, "create cmd fail\n"); + ret = -EINVAL; + goto out; + } + memset(args, 0, sizeof(*args)); + + fd = get_unused_fd_flags(O_CLOEXEC); + if (fd < 0) { + dev_err(mpriv->mdev->dev, "get unused fd fail\n"); + ret = -EINVAL; + goto delete_cmd; + } + sync_file = sync_file_create(&c->fence->base_fence); + if (!sync_file) { + dev_err(mpriv->mdev->dev, "create sync file fail\n"); + ret = -ENOMEM; + goto put_file; + } + + /* check wait fence from other module */ + c->wait_fence = sync_file_get_fence(wait_fd); + if (!c->wait_fence) + ret = mdw_cmd_run(mpriv, c); + else + schedule_work(&c->t_wk); + + if (ret) + goto put_file; + + fd_install(fd, sync_file->file); + args->out.exec.fence = fd; + goto out; + +delete_cmd: + mdw_cmd_delete(c); +put_file: + put_unused_fd(fd); +out: + + return ret; +} + +int mdw_cmd_ioctl(struct mdw_fpriv *mpriv, void *data) +{ + union mdw_cmd_args *args = (union mdw_cmd_args *)data; + int ret = 0; + + switch (args->in.op) { + case MDW_CMD_IOCTL_RUN: + ret = mdw_cmd_ioctl_run(mpriv, args); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} diff --git a/drivers/soc/mediatek/apusys/mdw-drv.c b/drivers/soc/mediatek/apusys/mdw-drv.c new file mode 100644 index 000000000000..9c01a383a080 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-drv.c @@ -0,0 +1,211 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include + +#include "apu-core.h" +#include "mdw.h" +#include "mdw-mem.h" + +int mdw_dev_init(struct mdw_device *mdev) +{ + int ret = -ENODEV; + + mdw_rv_set_func(mdev); + + if (mdev->dev_funcs) + ret = mdev->dev_funcs->late_init(mdev); + + return ret; +} + +void mdw_dev_deinit(struct mdw_device *mdev) +{ + if (mdev->dev_funcs) { + mdev->dev_funcs->late_deinit(mdev); + mdev->dev_funcs = NULL; + } +} + +static void mdw_drv_priv_delete(struct kref *ref) +{ + struct mdw_fpriv *mpriv = + container_of(ref, struct mdw_fpriv, ref); + + kfree(mpriv); +} + +static void mdw_drv_priv_get(struct mdw_fpriv *mpriv) +{ + kref_get(&mpriv->ref); +} + +static void mdw_drv_priv_put(struct mdw_fpriv *mpriv) +{ + kref_put(&mpriv->ref, mdw_drv_priv_delete); +} + +static int mdw_drv_open(struct inode *inode, struct file *filp) +{ + struct mdw_device *mdev; + struct mdw_fpriv *mpriv = NULL; + int ret = 0; + + mdev = container_of(filp->private_data, struct mdw_device, misc_dev); + if (!mdev) { + pr_warn("apusys/mdw: apu mdw no dev\n"); + return -ENODEV; + } + + if (!mdev->inited) { + dev_dbg(mdev->dev, "apu mdw dev not init"); + return -EBUSY; + } + + if (!atomic_read(&mdev->sw_inited)) { + ret = mdev->dev_funcs->sw_init(mdev); + if (ret) { + dev_err(mdev->dev, "mdw sw init fail(%d)\n", ret); + return -EFAULT; + } + atomic_inc(&mdev->sw_inited); + } + + mpriv = kzalloc(sizeof(*mpriv), GFP_KERNEL); + if (!mpriv) + return -ENOMEM; + + mpriv->mdev = mdev; + filp->private_data = mpriv; + mutex_init(&mpriv->mtx); + INIT_LIST_HEAD(&mpriv->mems); + INIT_LIST_HEAD(&mpriv->cmds); + + mpriv->get = mdw_drv_priv_get; + mpriv->put = mdw_drv_priv_put; + kref_init(&mpriv->ref); + + return ret; +} + +static int mdw_drv_close(struct inode *inode, struct file *filp) +{ + struct mdw_fpriv *mpriv = NULL; + + mpriv = filp->private_data; + mutex_lock(&mpriv->mtx); + mdw_mem_mpriv_release(mpriv); + mutex_unlock(&mpriv->mtx); + mpriv->put(mpriv); + + return 0; +} + +static const struct file_operations mdw_fops = { + .owner = THIS_MODULE, + .open = mdw_drv_open, + .release = mdw_drv_close, + .unlocked_ioctl = mdw_ioctl, + .compat_ioctl = mdw_ioctl, +}; + +static int mdw_rpmsg_probe(struct rpmsg_device *rpdev) +{ + struct device *dev = &rpdev->dev; + struct mdw_device *mdev = NULL; + int ret = 0; + + mdev = kzalloc(sizeof(*mdev), GFP_KERNEL); + if (!mdev) + return -ENOMEM; + + mdev->rpdev = rpdev; + mdev->dev = dev; + mdev->dma_dev = dev->parent; + mdev->misc_dev.minor = MISC_DYNAMIC_MINOR; + mdev->misc_dev.name = MDW_NAME; + mdev->misc_dev.fops = &mdw_fops; + ret = misc_register(&mdev->misc_dev); + + if (ret) + goto out; + + dev_set_drvdata(dev, mdev); + + ret = mdw_mem_init(mdev); + if (ret) + goto misc_unreg; +#ifdef CONFIG_DEBUG_FS + ret = mdw_sysfs_init(mdev); + if (ret) + goto deinit_mem; +#endif + ret = mdw_dev_init(mdev); + if (ret) + goto deinit_dbg; + + goto out; + +#ifdef CONFIG_DEBUG_FS +deinit_dbg: + mdw_sysfs_deinit(mdev); +#endif +deinit_mem: + mdw_mem_deinit(mdev); +misc_unreg: + misc_deregister(&mdev->misc_dev); +out: + return ret; +} + +static void mdw_rpmsg_remove(struct rpmsg_device *rpdev) +{ + struct mdw_device *mdev = dev_get_drvdata(&rpdev->dev); + + mdev->dev_funcs->sw_deinit(mdev); + mdw_dev_deinit(mdev); +#ifdef CONFIG_DEBUG_FS + mdw_sysfs_deinit(mdev); +#endif + mdw_mem_deinit(mdev); + misc_deregister(&mdev->misc_dev); + kfree(mdev); +} + +static const struct of_device_id mdw_rpmsg_of_match[] = { + { .compatible = "mediatek,apu-mdw-rpmsg", }, + { }, +}; + +static struct rpmsg_driver mdw_rpmsg_driver = { + .drv = { + .name = "apu-mdw-rpmsg", + .owner = THIS_MODULE, + .of_match_table = mdw_rpmsg_of_match, + }, + .probe = mdw_rpmsg_probe, + .remove = mdw_rpmsg_remove, +}; + +int mdw_init(struct apusys_core_info *info) +{ + int ret = 0; + + ret = register_rpmsg_driver(&mdw_rpmsg_driver); + if (ret) + pr_err("Failed to register apu mdw rpmsg driver\n"); + + return ret; +} + +void mdw_exit(void) +{ + unregister_rpmsg_driver(&mdw_rpmsg_driver); +} diff --git a/drivers/soc/mediatek/apusys/mdw-ioctl.c b/drivers/soc/mediatek/apusys/mdw-ioctl.c new file mode 100644 index 000000000000..4e543c257f1b --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-ioctl.c @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include + +#include "mdw-ioctl.h" +#include "mdw.h" +#include "mdw-mem.h" + +static int mdw_mem_ioctl_alloc(struct mdw_fpriv *mpriv, + union mdw_mem_args *args) +{ + struct mdw_mem_in *in = (struct mdw_mem_in *)args; + struct mdw_mem *m = NULL; + int ret = 0; + + if (!in->alloc.size) { + dev_err(mpriv->mdev->dev, "invalid size(%u)\n", in->alloc.size); + return -EINVAL; + } + + m = mdw_mem_alloc(mpriv, in->alloc.size, in->alloc.align, + in->alloc.flags, MDW_MEM_TYPE_ALLOC); + memset(args, 0, sizeof(*args)); + if (!m) { + dev_err(mpriv->mdev->dev, "mdw_mem_alloc fail\n"); + return -ENOMEM; + } + + args->out.alloc.handle = m->handle; + + mutex_lock(&mpriv->mtx); + list_add_tail(&m->u_item, &mpriv->mems); + mutex_unlock(&mpriv->mtx); + + return ret; +} + +static int mdw_mem_ioctl_map(struct mdw_fpriv *mpriv, + union mdw_mem_args *args) +{ + struct mdw_mem_in *in = (struct mdw_mem_in *)args; + struct mdw_mem *m = NULL; + int ret = -ENOMEM, handle = (int)in->map.handle; + u32 size = in->map.size; + + memset(args, 0, sizeof(*args)); + + mutex_lock(&mpriv->mtx); + m = mdw_mem_get(handle); + if (!m) { + /* mem not alloc from apu, import buffer */ + m = mdw_mem_import(mpriv, handle, size); + if (m) + ret = 0; + goto out; + } + + /* already exist */ + ret = mdw_mem_map(m); + if (ret) + dev_err(mpriv->mdev->dev, "map fail\n"); + +out: + if (m) + args->out.map.device_va = m->device_va; + mutex_unlock(&mpriv->mtx); + + return ret; +} + +static int mdw_mem_ioctl_unmap(struct mdw_fpriv *mpriv, + union mdw_mem_args *args) +{ + struct mdw_mem_in *in = (struct mdw_mem_in *)args; + struct mdw_mem *m = NULL; + int ret = -ENOMEM, handle = in->unmap.handle; + + memset(args, 0, sizeof(*args)); + + mutex_lock(&mpriv->mtx); + m = mdw_mem_get(handle); + if (!m) + goto out; + + ret = mdw_mem_unmap(m); + +out: + mutex_unlock(&mpriv->mtx); + + return ret; +} + +static int mdw_mem_ioctl_flush(struct mdw_fpriv *mpriv, + union mdw_mem_args *args) +{ + struct mdw_mem_in *in = (struct mdw_mem_in *)args; + struct mdw_mem *m = NULL; + int ret = -ENOMEM, handle = in->flush.handle; + + memset(args, 0, sizeof(*args)); + + mutex_lock(&mpriv->mtx); + m = mdw_mem_get(handle); + if (!m) + goto out; + + ret = mdw_mem_flush(m); +out: + mutex_unlock(&mpriv->mtx); + return ret; +} + +static int mdw_mem_ioctl_invalidate(struct mdw_fpriv *mpriv, + union mdw_mem_args *args) +{ + struct mdw_mem_in *in = (struct mdw_mem_in *)args; + struct mdw_mem *m = NULL; + int ret = -ENOMEM, handle = in->invalidate.handle; + + memset(args, 0, sizeof(*args)); + + mutex_lock(&mpriv->mtx); + m = mdw_mem_get(handle); + if (!m) + goto out; + + ret = mdw_mem_invalidate(m); +out: + mutex_unlock(&mpriv->mtx); + return ret; +} + +static int mdw_mem_ioctl(struct mdw_fpriv *mpriv, void *data) +{ + union mdw_mem_args *args = (union mdw_mem_args *)data; + int ret = 0; + + switch (args->in.op) { + case MDW_MEM_IOCTL_ALLOC: + ret = mdw_mem_ioctl_alloc(mpriv, args); + break; + + case MDW_MEM_IOCTL_MAP: + ret = mdw_mem_ioctl_map(mpriv, args); + break; + + case MDW_MEM_IOCTL_FREE: + pr_warn("not suppot free\n"); + ret = -EFAULT; + break; + + case MDW_MEM_IOCTL_UNMAP: + ret = mdw_mem_ioctl_unmap(mpriv, args); + break; + + case MDW_MEM_IOCTL_FLUSH: + ret = mdw_mem_ioctl_flush(mpriv, args); + break; + + case MDW_MEM_IOCTL_INVALIDATE: + ret = mdw_mem_ioctl_invalidate(mpriv, args); + break; + + default: + ret = -EINVAL; + break; + } + + return ret; +} + +static int mdw_hs_ioctl(struct mdw_fpriv *mpriv, void *data) +{ + union mdw_hs_args *args = (union mdw_hs_args *)data; + struct mdw_device *mdev = mpriv->mdev; + unsigned int type = 0; + int ret = 0; + + switch (args->in.op) { + case MDW_HS_IOCTL_OP_BASIC: + memset(args, 0, sizeof(*args)); + args->out.basic.version = mdev->uapi_ver; + memcpy(&args->out.basic.dev_bitmask, + mdev->dev_mask, sizeof(args->out.basic.dev_bitmask)); + args->out.basic.meta_size = MDW_DEV_META_SIZE; + args->out.basic.vlm_start = mdev->vlm_start; + args->out.basic.vlm_size = mdev->vlm_size; + break; + + case MDW_HS_IOCTL_OP_DEV: + type = args->in.dev.type; + if (type >= MDW_DEV_MAX) { + ret = -EINVAL; + break; + } + + if (!mdev->dinfos[type]) { + ret = -EINVAL; + break; + } + + memset(args, 0, sizeof(*args)); + args->out.dev.type = type; + args->out.dev.num = mdev->dinfos[type]->num; + memcpy(args->out.dev.meta, mdev->dinfos[type]->meta, + sizeof(args->out.dev.meta)); + break; + + default: + dev_err(mpriv->mdev->dev, + "invalid handshake op code(%d)\n", args->in.op); + ret = -EINVAL; + break; + } + + return ret; +} + +static int mdw_util_ioctl(struct mdw_fpriv *mpriv, void *data) +{ + union mdw_util_args *args = (union mdw_util_args *)data; + struct mdw_util_in *in = (struct mdw_util_in *)args; + struct mdw_device *mdev = mpriv->mdev; + void *mem_ucmd = NULL; + int ret = 0; + + switch (args->in.op) { + case MDW_UTIL_IOCTL_SETPOWER: + ret = mdev->dev_funcs->set_power(mdev, in->power.dev_type, + in->power.core_idx, in->power.boost); + break; + + case MDW_UTIL_IOCTL_UCMD: + if (!in->ucmd.size || !in->ucmd.handle) { + dev_err(mpriv->mdev->dev, "invalid ucmd param\n"); + ret = -EINVAL; + break; + } + + mem_ucmd = vzalloc(args->in.ucmd.size); + if (!mem_ucmd) { + ret = -ENOMEM; + break; + } + + if (copy_from_user(mem_ucmd, + (void __user *)in->ucmd.handle, + in->ucmd.size)) { + ret = -EFAULT; + goto free_ucmd; + } + ret = mdev->dev_funcs->ucmd(mdev, in->ucmd.dev_type, + mem_ucmd, in->ucmd.size); + if (ret) { + dev_err(mpriv->mdev->dev, "dev(%d) ucmd fail\n", + in->ucmd.dev_type); + goto free_ucmd; + } + + if (copy_to_user((void __user *)in->ucmd.handle, + mem_ucmd, in->ucmd.size)) + ret = -EFAULT; + +free_ucmd: + vfree(mem_ucmd); + break; + + default: + dev_err(mpriv->mdev->dev, "invalid util op code(%d)\n", + args->in.op); + ret = -EINVAL; + break; + } + + return ret; +} + +long mdw_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + int ret = 0; + unsigned int usize = 0; + void *kdata = NULL; + struct mdw_fpriv *mpriv = filp->private_data; + + usize = _IOC_SIZE(cmd); + kdata = kzalloc(usize, GFP_KERNEL); + if (!kdata) + return -ENOMEM; + + if (cmd & IOC_IN) { + if (copy_from_user(kdata, (void __user *)arg, usize)) { + ret = -EFAULT; + goto out; + } + } + + switch (cmd) { + case APU_MDW_IOCTL_HANDSHAKE: + ret = mdw_hs_ioctl(mpriv, kdata); + break; + case APU_MDW_IOCTL_MEM: + ret = mdw_mem_ioctl(mpriv, kdata); + break; + case APU_MDW_IOCTL_CMD: + ret = mdw_cmd_ioctl(mpriv, kdata); + break; + case APU_MDW_IOCTL_UTIL: + ret = mdw_util_ioctl(mpriv, kdata); + break; + default: + ret = -EFAULT; + goto out; + } + + if (cmd & IOC_OUT) { + if (copy_to_user((void __user *)arg, kdata, usize)) { + ret = -EFAULT; + goto out; + } + } + +out: + kfree(kdata); + + return ret; +} diff --git a/drivers/soc/mediatek/apusys/mdw-ioctl.h b/drivers/soc/mediatek/apusys/mdw-ioctl.h new file mode 100644 index 000000000000..1f735b400f4b --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-ioctl.h @@ -0,0 +1,256 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_APU_IOCTL_H__ +#define __MTK_APU_IOCTL_H__ + +#include +#include + +#define APUSYS_MAGICNO 'A' + +enum mdw_hs_ioctl_op { + MDW_HS_IOCTL_OP_BASIC, + MDW_HS_IOCTL_OP_DEV, +}; + +struct mdw_hs_in { + enum mdw_hs_ioctl_op op; + u64 flags; + union { + struct { + u32 type; + } dev; + }; +}; + +#define MDW_DEV_META_SIZE (32) + +struct mdw_hs_out { + union { + struct { + u64 version; + u64 dev_bitmask; + u64 flags; + u32 meta_size; + u64 vlm_start; + u32 vlm_size; + } basic; + + struct { + u32 type; + u32 num; + char meta[MDW_DEV_META_SIZE]; + } dev; + }; +}; + +union mdw_hs_args { + struct mdw_hs_in in; + struct mdw_hs_out out; +}; + +#define APU_MDW_IOCTL_HANDSHAKE \ + _IOWR(APUSYS_MAGICNO, 32, union mdw_hs_args) + +enum mdw_mem_ioctl_op { + MDW_MEM_IOCTL_ALLOC, + MDW_MEM_IOCTL_FREE, + MDW_MEM_IOCTL_MAP, + MDW_MEM_IOCTL_UNMAP, + MDW_MEM_IOCTL_FLUSH, + MDW_MEM_IOCTL_INVALIDATE, +}; + +enum MDW_MEM_IOCTL_ALLOC_BITMASK { + MDW_MEM_IOCTL_ALLOC_CACHEABLE, + MDW_MEM_IOCTL_ALLOC_32BIT, + MDW_MEM_IOCTL_ALLOC_HIGHADDR, +}; + +struct mdw_mem_in { + enum mdw_mem_ioctl_op op; + u64 flags; + union { + /* alloc */ + struct { + u32 size; + u32 align; + u64 flags; /* enum MDW_MEM_IOCTL_ALLOC_BITMASK */ + } alloc; + struct { + u64 handle; + } free; + + /* map */ + struct { + u64 handle; + u32 size; + } map; + struct { + u64 handle; + } unmap; + + /* cache operation */ + struct { + u64 handle; + } flush; + struct { + u64 handle; + } invalidate; + }; +}; + +struct mdw_mem_out { + union { + struct { + u64 handle; + } alloc; + struct { + u64 device_va; + } map; + struct { + u64 device_va; + u32 size; + } import; + }; +}; + +union mdw_mem_args { + struct mdw_mem_in in; + struct mdw_mem_out out; +}; + +#define APU_MDW_IOCTL_MEM \ + _IOWR(APUSYS_MAGICNO, 33, union mdw_mem_args) + +enum mdw_cmd_ioctl_op { + MDW_CMD_IOCTL_RUN, +}; + +enum { + /* cmdbuf copy in before execution and copy out after exection */ + MDW_CB_BIDIRECTIONAL, + /* cmdbuf copy in before execution */ + MDW_CB_IN, + /* cmdbuf copy out after execution */ + MDW_CB_OUT, +}; + +struct mdw_subcmd_exec_info { + u32 driver_time; + u32 ip_time; + u32 ip_start_ts; + u32 ip_end_ts; + u32 bw; + u32 boost; + u32 tcm_usage; + s32 ret; +}; + +struct mdw_cmd_exec_info { + u64 sc_rets; + s64 ret; + u64 total_us; + u64 reserved; +}; + +struct mdw_subcmd_cmdbuf { + u64 handle; + u32 size; + u32 align; + u32 direction; +}; + +struct mdw_subcmd_info { + u32 type; + u32 suggest_time; + u32 vlm_usage; + u32 vlm_ctx_id; + u32 vlm_force; + u32 boost; + u32 turbo_boost; + u32 min_boost; + u32 max_boost; + u32 hse_en; + u32 pack_id; + u32 driver_time; + u32 ip_time; + u32 bw; + + u32 num_cmdbufs; + u64 cmdbufs; +}; + +struct mdw_cmd_in { + enum mdw_cmd_ioctl_op op; + union { + struct { + u64 usr_id; + u64 uid; + u32 priority; + u32 hardlimit; + u32 softlimit; + u32 power_save; + u32 power_plcy; + u32 power_dtime; + u32 app_type; + u32 flags; + u32 num_subcmds; + u64 subcmd_infos; + u64 adj_matrix; + u64 fence; + u64 exec_infos; + } exec; + }; +}; + +struct mdw_cmd_out { + union { + struct { + u64 id; + u64 fence; + } exec; + }; +}; + +union mdw_cmd_args { + struct mdw_cmd_in in; + struct mdw_cmd_out out; +}; + +#define APU_MDW_IOCTL_CMD \ + _IOWR(APUSYS_MAGICNO, 34, union mdw_cmd_args) + +enum mdw_util_ioctl_op { + MDW_UTIL_IOCTL_SETPOWER, + MDW_UTIL_IOCTL_UCMD, +}; + +struct mdw_util_in { + enum mdw_util_ioctl_op op; + union { + struct { + u32 dev_type; + u32 core_idx; + u32 boost; + u64 reserve; + } power; + struct { + u32 dev_type; + u32 size; + u64 handle; + } ucmd; + }; +}; + +union mdw_util_args { + struct mdw_util_in in; +}; + +#define APU_MDW_IOCTL_UTIL \ + _IOWR(APUSYS_MAGICNO, 35, union mdw_util_args) + +#endif diff --git a/drivers/soc/mediatek/apusys/mdw-mem.c b/drivers/soc/mediatek/apusys/mdw-mem.c new file mode 100644 index 000000000000..c5aea746f6a8 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-mem.c @@ -0,0 +1,938 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include + +#include "apu-device.h" +#include "mdw.h" +#include "mdw-mem.h" + +#define APU_MEM_DMA_MASK 0x00000003ffffffff + +struct mdw_mem_dma_attachment { + struct sg_table *sgt; + struct device *dev; + struct list_head node; + bool mapped; + bool uncached; +}; + +struct mdw_mem_dma { + struct dma_buf *dbuf; + dma_addr_t dma_addr; + u32 dma_size; + u32 size; + struct { + int handle; + void *vaddr; + struct list_head attachments; + struct sg_table sgt; + void *buf; + } a; + struct { + struct dma_buf_attachment *attach; + struct sg_table *sgt; + } m; + bool uncached; + struct kref attach_ref; + + struct mutex mtx; /* protect attachments */ + + struct mdw_mem *mmem; + struct device *mem_dev; + struct list_head m_item; +}; + +struct mdw_mem_dma_mgr { + struct list_head mems; + struct mutex mtx; /* protect mems */ +}; + +static struct mdw_mem_dma_mgr mdmgr; + +static struct sg_table *mdw_mem_dma_dup_sg(struct sg_table *table) +{ + struct sg_table *new_table; + int ret, i; + struct scatterlist *sg, *new_sg; + + new_table = kzalloc(sizeof(*new_table), GFP_KERNEL); + if (!new_table) + return ERR_PTR(-ENOMEM); + + ret = sg_alloc_table(new_table, table->orig_nents, GFP_KERNEL); + if (ret) { + kfree(new_table); + return ERR_PTR(-ENOMEM); + } + + new_sg = new_table->sgl; + for_each_sgtable_sg(table, sg, i) { + sg_set_page(new_sg, sg_page(sg), sg->length, sg->offset); + new_sg = sg_next(new_sg); + } + + return new_table; +} + +static int mdw_mem_dma_allocate_sgt(const char *buf, size_t len, + struct sg_table *sgt, bool uncached, + void **vaddr) +{ + struct page **pages = NULL; + unsigned int nr_pages; + unsigned int index; + const char *p; + int ret; + pgprot_t pgprot = PAGE_KERNEL; + void *va; + + nr_pages = DIV_ROUND_UP((unsigned long)buf + len, PAGE_SIZE) + - ((unsigned long)buf / PAGE_SIZE); + pages = kmalloc_array(nr_pages, sizeof(struct page *), GFP_KERNEL); + + if (!pages) + return -ENOMEM; + + p = buf - offset_in_page(buf); + + for (index = 0; index < nr_pages; index++) { + if (is_vmalloc_addr(p)) + pages[index] = vmalloc_to_page(p); + else + pages[index] = kmap_to_page((void *)p); + if (!pages[index]) { + kfree(pages); + return -EFAULT; + } + p += PAGE_SIZE; + } + if (uncached) + pgprot = pgprot_writecombine(PAGE_KERNEL); + + va = vmap(pages, nr_pages, VM_MAP, pgprot); + ret = sg_alloc_table_from_pages(sgt, pages, index, offset_in_page(buf), + len, GFP_KERNEL); + kfree(pages); + if (ret) + return ret; + + *vaddr = va; + + return 0; +} + +static int mdw_mem_dma_free_sgt(struct sg_table *sgt) +{ + int ret = 0; + + sg_free_table(sgt); + + return ret; +} + +static int mdw_dmabuf_attach(struct dma_buf *dbuf, + struct dma_buf_attachment *attach) +{ + struct mdw_mem_dma_attachment *a = NULL; + struct mdw_mem_dma *mdbuf = dbuf->priv; + int ret = 0; + struct sg_table *table; + + a = kzalloc(sizeof(*a), GFP_KERNEL); + if (!a) + return -ENOMEM; + + table = mdw_mem_dma_dup_sg(&mdbuf->a.sgt); + if (IS_ERR(table)) { + kfree(a); + return -ENOMEM; + } + + a->sgt = table; + a->dev = attach->dev; + INIT_LIST_HEAD(&a->node); + a->mapped = false; + a->uncached = mdbuf->uncached; + attach->priv = a; + + mutex_lock(&mdbuf->mtx); + list_add(&a->node, &mdbuf->a.attachments); + mutex_unlock(&mdbuf->mtx); + + return ret; +} + +static void mdw_dmabuf_detach(struct dma_buf *dbuf, + struct dma_buf_attachment *attach) +{ + struct mdw_mem_dma_attachment *a = attach->priv; + struct mdw_mem_dma *mdbuf = dbuf->priv; + + mutex_lock(&mdbuf->mtx); + list_del(&a->node); + mutex_unlock(&mdbuf->mtx); + + sg_free_table(a->sgt); + kfree(a->sgt); + kfree(a); +} + +static struct sg_table *mdw_dmabuf_map_dma(struct dma_buf_attachment *attach, + enum dma_data_direction dir) +{ + struct mdw_mem_dma_attachment *a = attach->priv; + struct sg_table *table = NULL; + int attr = 0; + int ret = 0; + + table = a->sgt; + if (a->uncached) + attr |= DMA_ATTR_SKIP_CPU_SYNC; + + ret = dma_map_sgtable(attach->dev, table, dir, attr); + if (ret) + table = ERR_PTR(ret); + + a->mapped = true; + + return table; +} + +static void mdw_dmabuf_unmap_dma(struct dma_buf_attachment *attach, + struct sg_table *sgt, + enum dma_data_direction dir) +{ + struct mdw_mem_dma_attachment *a = attach->priv; + int attr = 0; + + if (a->uncached) + attr |= DMA_ATTR_SKIP_CPU_SYNC; + + a->mapped = false; + dma_unmap_sgtable(attach->dev, sgt, dir, attr); +} + +static int mdw_dmabuf_vmap(struct dma_buf *dbuf, struct dma_buf_map *dbuf_map) +{ + struct mdw_mem_dma *mdbuf = dbuf->priv; + + dbuf_map->vaddr = mdbuf->a.vaddr; + return 0; +} + +static void mdw_dmabuf_release(struct dma_buf *dbuf) +{ + struct mdw_mem_dma *mdbuf = dbuf->priv; + struct mdw_mem *m = mdbuf->mmem; + + mutex_lock(&mdmgr.mtx); + list_del(&mdbuf->m_item); + mutex_unlock(&mdmgr.mtx); + + if (m->type != MDW_MEM_TYPE_IMPORT) { + mdw_mem_dma_free_sgt(&mdbuf->a.sgt); + vunmap(mdbuf->a.vaddr); + kvfree(mdbuf->a.buf); + } + + kfree(mdbuf); + m->release(m); +} + +static int mdw_dmabuf_mmap(struct dma_buf *dbuf, + struct vm_area_struct *vma) +{ + struct mdw_mem_dma *mdbuf = dbuf->priv; + struct sg_table *table = &mdbuf->a.sgt; + unsigned long addr = vma->vm_start; + struct sg_page_iter piter; + int ret = 0; + + if (mdbuf->uncached) + vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot); + + for_each_sgtable_page(table, &piter, vma->vm_pgoff) { + struct page *page = sg_page_iter_page(&piter); + + ret = remap_pfn_range(vma, addr, page_to_pfn(page), PAGE_SIZE, + vma->vm_page_prot); + if (ret) + return ret; + addr += PAGE_SIZE; + if (addr >= vma->vm_end) + return 0; + } + return ret; +} + +static struct dma_buf_ops mdw_dmabuf_ops = { + .attach = mdw_dmabuf_attach, + .detach = mdw_dmabuf_detach, + .map_dma_buf = mdw_dmabuf_map_dma, + .unmap_dma_buf = mdw_dmabuf_unmap_dma, + .vmap = mdw_dmabuf_vmap, + .mmap = mdw_dmabuf_mmap, + .release = mdw_dmabuf_release, +}; + +static struct mdw_mem *mdw_mem_dma_get(int handle) +{ + struct dma_buf *dbuf = NULL; + struct mdw_mem_dma *m = NULL, *pos = NULL, *tmp = NULL; + + dbuf = dma_buf_get(handle); + if (IS_ERR_OR_NULL(dbuf)) + return NULL; + + mutex_lock(&mdmgr.mtx); + list_for_each_entry_safe(pos, tmp, &mdmgr.mems, m_item) { + if (pos->dbuf == dbuf) { + m = pos; + break; + } + } + mutex_unlock(&mdmgr.mtx); + + dma_buf_put(dbuf); + if (!m) { + pr_err("handle(%d) not belong to apu\n", handle); + return NULL; + } + + return m->mmem; +} + +static int mdw_mem_dma_alloc(struct mdw_mem *mem) +{ + struct mdw_mem_dma *mdbuf = NULL; + int ret = 0; + DEFINE_DMA_BUF_EXPORT_INFO(exp_info); + struct device *dev; + void *kva; + bool uncached = true; + + /* alloc mdw dma-buf container */ + mdbuf = kzalloc(sizeof(*mdbuf), GFP_KERNEL); + if (!mdbuf) + return -ENOMEM; + + mutex_init(&mdbuf->mtx); + INIT_LIST_HEAD(&mdbuf->a.attachments); + + /* alloc buffer by dma */ + mdbuf->dma_size = PAGE_ALIGN(mem->size); + + dev = mem->mpriv->mdev->dma_dev; + + if (!dev) { + pr_err("dev invalid\n"); + ret = -ENOMEM; + goto free_mdw_dbuf; + } + + kva = kvzalloc(mdbuf->dma_size, GFP_KERNEL); + if (!kva) { + ret = -ENOMEM; + goto free_mdw_dbuf; + } + + mdbuf->a.buf = kva; + + if (mdw_mem_dma_allocate_sgt(kva, mdbuf->dma_size, &mdbuf->a.sgt, + uncached, &mdbuf->a.vaddr)) { + dev_err(dev, "get sgt: failed\n"); + ret = -ENOMEM; + goto free_buf; + } + + exp_info.ops = &mdw_dmabuf_ops; + exp_info.size = mdbuf->dma_size; + exp_info.flags = O_RDWR | O_CLOEXEC; + exp_info.priv = mdbuf; + + mdbuf->dbuf = dma_buf_export(&exp_info); + if (IS_ERR(mdbuf->dbuf)) { + dev_err(dev, "dma_buf_export Fail\n"); + ret = -ENOMEM; + goto free_sgt; + } + + mdbuf->dbuf->priv = mdbuf; + mdbuf->mmem = mem; + mdbuf->mem_dev = dev; + mdbuf->size = mem->size; + mdbuf->uncached = uncached; + mem->device_va = mdbuf->dma_addr; + mem->vaddr = mdbuf->a.vaddr; + mem->priv = mdbuf; + mutex_lock(&mdmgr.mtx); + list_add_tail(&mdbuf->m_item, &mdmgr.mems); + mutex_unlock(&mdmgr.mtx); + + dma_sync_sgtable_for_device(mdbuf->mem_dev, &mdbuf->a.sgt, + DMA_TO_DEVICE); + + /* internal use, don't export fd */ + if (!mem->need_handle) { + mem->handle = -1; + goto out; + } + + mdbuf->a.handle = dma_buf_fd(mdbuf->dbuf, + (O_RDWR | O_CLOEXEC) & ~O_ACCMODE); + if (mdbuf->a.handle < 0) { + ret = -EINVAL; + dev_err(dev, "dma_buf_fd Fail\n"); + dma_buf_put(mdbuf->dbuf); + return ret; + } + mem->handle = mdbuf->a.handle; + +out: + return ret; + +free_sgt: + mdw_mem_dma_free_sgt(&mdbuf->a.sgt); +free_buf: + kvfree(kva); +free_mdw_dbuf: + kfree(mdbuf); + + return ret; +} + +static int mdw_mem_dma_free(struct mdw_mem *mem) +{ + struct mdw_mem_dma *mdbuf = mem->priv; + + dma_buf_put(mdbuf->dbuf); + + return 0; +} + +int mdw_mem_dma_map(struct mdw_mem *mem) +{ + struct mdw_mem_dma *mdbuf = NULL; + int ret = 0; + + mdbuf = (struct mdw_mem_dma *)mem->priv; + + if (IS_ERR_OR_NULL(mdbuf->dbuf)) + return -EINVAL; + + get_dma_buf(mdbuf->dbuf); + + /* Only Attach after First Map */ + if (kref_read(&mdbuf->attach_ref)) { + kref_get(&mdbuf->attach_ref); + goto out; + } else { + kref_init(&mdbuf->attach_ref); + } + + mdbuf->m.attach = dma_buf_attach(mdbuf->dbuf, mdbuf->mem_dev); + if (IS_ERR(mdbuf->m.attach)) { + ret = PTR_ERR(mdbuf->m.attach); + dev_err(mdbuf->mem_dev, "dma_buf_attach failed: %d\n", ret); + goto put_dbuf; + } + + mdbuf->m.sgt = dma_buf_map_attachment(mdbuf->m.attach, + DMA_BIDIRECTIONAL); + if (IS_ERR(mdbuf->m.sgt)) { + ret = PTR_ERR(mdbuf->m.sgt); + dev_err(mdbuf->mem_dev, "dma_buf_map_attachment failed: %d\n", + ret); + goto detach_dbuf; + } + + mdbuf->dma_addr = sg_dma_address(mdbuf->m.sgt->sgl); + mdbuf->dma_size = sg_dma_len(mdbuf->m.sgt->sgl); + if (!mdbuf->dma_addr || !mdbuf->dma_size) { + dev_err(mdbuf->mem_dev, "can't get mem(0x%llx) dva(0x%llx/%u)\n", + (u64)mem, mdbuf->dma_addr, mdbuf->dma_size); + ret = -ENOMEM; + goto unmap_dbuf; + } + + mem->device_va = mdbuf->dma_addr; + mem->dva_size = mdbuf->dma_size; +out: + return ret; + +unmap_dbuf: + dma_buf_unmap_attachment(mdbuf->m.attach, mdbuf->m.sgt, + DMA_BIDIRECTIONAL); +detach_dbuf: + dma_buf_detach(mdbuf->dbuf, mdbuf->m.attach); +put_dbuf: + dma_buf_put(mdbuf->dbuf); + + return ret; +} + +static void mdw_mem_dma_detach(struct kref *ref) +{ + struct mdw_mem_dma *mdbuf; + + mdbuf = container_of(ref, struct mdw_mem_dma, attach_ref); + dma_buf_unmap_attachment(mdbuf->m.attach, mdbuf->m.sgt, + DMA_BIDIRECTIONAL); + dma_buf_detach(mdbuf->dbuf, mdbuf->m.attach); +} + +int mdw_mem_dma_unmap(struct mdw_mem *mem) +{ + struct mdw_mem_dma *mdbuf = mem->priv; + int ret = 0; + + /* Only Detach after last Map */ + kref_put(&mdbuf->attach_ref, mdw_mem_dma_detach); + + dma_buf_put(mdbuf->dbuf); + + return ret; +} + +static int mdw_mem_dma_import(struct mdw_mem *mem) +{ + int ret = 0; + struct mdw_mem_dma *mdbuf = NULL; + struct dma_buf *dbuf = NULL; + struct device *dev; + + if (mem->device_va || mem->priv) + return -EINVAL; + + dbuf = dma_buf_get(mem->handle); + if (IS_ERR_OR_NULL(dbuf)) + return -ENOMEM; + + /* Import Use 32 Bit Buffer */ + dev = mem->mpriv->mdev->dma_dev; + if (!dev) { + pr_err("dev invalid\n"); + ret = -ENOMEM; + goto put_dbuf; + } + + mdbuf = kzalloc(sizeof(*mdbuf), GFP_KERNEL); + if (!mdbuf) { + ret = -ENOMEM; + goto put_dbuf; + } + + mdbuf->mmem = mem; + mdbuf->dbuf = dbuf; + mdbuf->mem_dev = dev; + mdbuf->size = mem->size; + + /* Only Attach after First Map */ + if (kref_read(&mdbuf->attach_ref)) { + kref_get(&mdbuf->attach_ref); + goto out; + } else { + kref_init(&mdbuf->attach_ref); + } + + mdbuf->m.attach = dma_buf_attach(mdbuf->dbuf, dev); + if (IS_ERR(mdbuf->m.attach)) { + ret = PTR_ERR(mdbuf->m.attach); + dev_err(dev, "dma_buf_attach failed: %d\n", ret); + goto free_mdbuf; + } + + mdbuf->m.sgt = dma_buf_map_attachment(mdbuf->m.attach, + DMA_BIDIRECTIONAL); + if (IS_ERR(mdbuf->m.sgt)) { + ret = PTR_ERR(mdbuf->m.sgt); + dev_err(dev, "dma_buf_map_attachment failed: %d\n", ret); + goto detach_dbuf; + } + + mdbuf->dma_addr = sg_dma_address(mdbuf->m.sgt->sgl); + mdbuf->dma_size = sg_dma_len(mdbuf->m.sgt->sgl); + if (!mdbuf->dma_addr || !mdbuf->dma_size) { + dev_err(dev, "can't get mem(0x%llx) dva(0x%llx/%u)\n", + (u64)mem, mdbuf->dma_addr, mdbuf->dma_size); + ret = -ENOMEM; + goto unmap_dbuf; + } + mem->device_va = mdbuf->dma_addr; + mem->priv = mdbuf; + mutex_lock(&mdmgr.mtx); + list_add_tail(&mdbuf->m_item, &mdmgr.mems); + mutex_unlock(&mdmgr.mtx); + +out: + return ret; + +unmap_dbuf: + dma_buf_unmap_attachment(mdbuf->m.attach, mdbuf->m.sgt, + DMA_BIDIRECTIONAL); +detach_dbuf: + dma_buf_detach(mdbuf->dbuf, mdbuf->m.attach); +free_mdbuf: + kfree(mdbuf); +put_dbuf: + dma_buf_put(dbuf); + + return ret; +} + +static int mdw_mem_dma_unimport(struct mdw_mem *mem) +{ + struct mdw_mem_dma *mdbuf = NULL; + int ret = 0; + + if (IS_ERR_OR_NULL(mem->priv)) + return -EINVAL; + + mdbuf = (struct mdw_mem_dma *)mem->priv; + + if (IS_ERR_OR_NULL(mdbuf->m.attach) || + IS_ERR_OR_NULL(mdbuf->m.sgt)) + return -EINVAL; + + mutex_lock(&mdmgr.mtx); + list_del(&mdbuf->m_item); + mutex_unlock(&mdmgr.mtx); + + /* Only Detach after last Map */ + kref_put(&mdbuf->attach_ref, mdw_mem_dma_detach); + + mem->device_va = 0; + mem->priv = NULL; + + dma_buf_put(mdbuf->dbuf); + kfree(mdbuf); + + return ret; +} + +static int mdw_mem_dma_flush(struct mdw_mem *mem) +{ + int ret = 0; + struct mdw_mem_dma *mdbuf = mem->priv; + + if (!mdbuf->a.vaddr) { + pr_warn("mdbuf vaddr NULL\n"); + goto out; + } + + if (!mdbuf->uncached) + dma_sync_sgtable_for_device(mdbuf->mem_dev, &mdbuf->a.sgt, + DMA_TO_DEVICE); +out: + return ret; +} + +static int mdw_mem_dma_invalidate(struct mdw_mem *mem) +{ + int ret = 0; + struct mdw_mem_dma *mdbuf = mem->priv; + + if (!mdbuf->a.vaddr) { + pr_warn("mdbuf vaddr NULL\n"); + goto out; + } + + if (!mdbuf->uncached) + dma_sync_sgtable_for_cpu(mdbuf->mem_dev, &mdbuf->a.sgt, + DMA_FROM_DEVICE); + +out: + return ret; +} + +static struct mdw_mem *mdw_mem_dma_query_mem(u64 kva) +{ + struct mdw_mem_dma *pos = NULL, *tmp = NULL; + struct mdw_mem *m = NULL; + struct mdw_mem *target = NULL; + + mutex_lock(&mdmgr.mtx); + list_for_each_entry_safe(pos, tmp, &mdmgr.mems, m_item) { + m = pos->mmem; + if (kva >= (u64)m->vaddr && + kva < (u64)m->vaddr + m->size) + target = m; + } + mutex_unlock(&mdmgr.mtx); + + return target; +} + +static int mdw_mem_dma_init(void) +{ + mutex_init(&mdmgr.mtx); + INIT_LIST_HEAD(&mdmgr.mems); + + return 0; +} + +static void mdw_mem_dma_deinit(void) +{ +} + +struct mdw_mem *mdw_mem_get(int handle) +{ + return mdw_mem_dma_get(handle); +} + +static void mdw_mem_delete(struct mdw_mem *m) +{ + struct mdw_fpriv *mpriv = m->mpriv; + + switch (m->type) { + case MDW_MEM_TYPE_ALLOC: + mutex_lock(&mpriv->mtx); + list_del(&m->u_item); + mutex_unlock(&mpriv->mtx); + break; + case MDW_MEM_TYPE_IMPORT: + list_del(&m->u_item); + break; + default: + break; + } + + vfree(m); + mpriv->put(mpriv); +} + +static struct mdw_mem *mdw_mem_create(struct mdw_fpriv *mpriv) +{ + struct mdw_mem *m = NULL; + + m = vzalloc(sizeof(*m)); + if (m) { + m->mpriv = mpriv; + m->release = mdw_mem_delete; + mpriv->get(mpriv); + } + + return m; +} + +static void mdw_mem_map_release(struct kref *ref) +{ + struct mdw_mem *m = + container_of(ref, struct mdw_mem, map_ref); + + switch (m->type) { + case MDW_MEM_TYPE_INTERNAL: + mdw_mem_dma_unmap(m); + break; + + case MDW_MEM_TYPE_ALLOC: + mdw_mem_dma_unmap(m); + break; + + case MDW_MEM_TYPE_IMPORT: + mdw_mem_dma_unimport(m); + mdw_mem_delete(m); + break; + + default: + break; + } +} + +struct mdw_mem *mdw_mem_alloc(struct mdw_fpriv *mpriv, u32 size, + u32 align, u64 flags, + enum mdw_mem_type type) +{ + struct mdw_mem *m = NULL; + int ret = 0; + + m = mdw_mem_create(mpriv); + if (!m) + goto out; + + if (type == MDW_MEM_TYPE_INTERNAL) + m->need_handle = false; + else + m->need_handle = true; + m->size = size; + m->align = align; + m->flags = flags; + ret = mdw_mem_dma_alloc(m); + if (ret) { + dev_err(mpriv->mdev->dev, "mdw_mem_dma_alloc Fail (%d)\n", ret); + goto free_mem; + } + m->type = type; + + goto out; + +free_mem: + mdw_mem_delete(m); + m = NULL; +out: + return m; +} + +int mdw_mem_free(struct mdw_mem *m) +{ + return mdw_mem_dma_free(m); +} + +int mdw_mem_map(struct mdw_mem *m) +{ + int ret = 0; + + if (kref_read(&m->map_ref)) { + kref_get(&m->map_ref); + ret = 0; + } else { + ret = mdw_mem_dma_map(m); + if (ret) { + dev_err(m->mpriv->mdev->dev, "map fail %d\n", ret); + goto out; + } + kref_init(&m->map_ref); + } +out: + return ret; +} + +int mdw_mem_unmap(struct mdw_mem *m) +{ + if (!kref_read(&m->map_ref)) { + dev_warn(m->mpriv->mdev->dev, "can't unmap mem\n"); + return -EINVAL; + } + kref_put(&m->map_ref, mdw_mem_map_release); + + return 0; +} + +int mdw_mem_flush(struct mdw_mem *m) +{ + int ret = 0; + + ret = mdw_mem_dma_flush(m); + if (ret) { + dev_err(m->mpriv->mdev->dev, "Flush Fail\n"); + ret = -EINVAL; + goto out; + } +out: + return ret; +} + +int mdw_mem_invalidate(struct mdw_mem *m) +{ + int ret = 0; + + ret = mdw_mem_dma_invalidate(m); + if (ret) { + dev_err(m->mpriv->mdev->dev, "Invalidate Fail\n"); + ret = -EINVAL; + goto out; + } +out: + return ret; +} + +struct mdw_mem *mdw_mem_import(struct mdw_fpriv *mpriv, u64 handle, u32 size) +{ + struct mdw_mem *m = NULL; + + m = mdw_mem_create(mpriv); + if (!m) + return NULL; + + m->size = size; + m->handle = handle; + if (mdw_mem_dma_import(m)) { + dev_err(mpriv->mdev->dev, "import fail\n"); + goto free_mem; + } + + m->type = MDW_MEM_TYPE_IMPORT; + kref_init(&m->map_ref); + list_add_tail(&m->u_item, &mpriv->mems); + + goto out; + +free_mem: + mdw_mem_delete(m); + m = NULL; +out: + return m; +} + +void mdw_mem_mpriv_release(struct mdw_fpriv *mpriv) +{ + struct mdw_mem *m = NULL, *tmp = NULL; + int i = 0, ref_cnt = 0; + + list_for_each_entry_safe(m, tmp, &mpriv->mems, u_item) { + ref_cnt = kref_read(&m->map_ref); + for (i = 0; i < ref_cnt; i++) + kref_put(&m->map_ref, mdw_mem_map_release); + } +} + +int mdw_mem_init(struct mdw_device *mdev) +{ + int ret = 0; + + ret = dma_set_mask_and_coherent(mdev->dma_dev, APU_MEM_DMA_MASK); + if (ret) { + dev_info(mdev->dev, "unable to set DMA mask coherent: %d\n", + ret); + return ret; + } + + return mdw_mem_dma_init(); +} + +void mdw_mem_deinit(struct mdw_device *mdev) +{ + mdw_mem_dma_deinit(); +} + +int apusys_mem_flush_kva(void *kva, u32 size) +{ + struct mdw_mem *m = NULL; + int ret = 0; + + m = mdw_mem_dma_query_mem((u64)kva); + if (!m) { + pr_err("No Mem\n"); + ret = -ENOMEM; + goto out; + } + + ret = mdw_mem_flush(m); + +out: + return ret; +} + +int apusys_mem_invalidate_kva(void *kva, u32 size) +{ + struct mdw_mem *m = NULL; + int ret = 0; + + m = mdw_mem_dma_query_mem((u64)kva); + if (!m) { + pr_err("No Mem\n"); + ret = -ENOMEM; + goto out; + } + + ret = mdw_mem_invalidate(m); +out: + return ret; +} diff --git a/drivers/soc/mediatek/apusys/mdw-mem.h b/drivers/soc/mediatek/apusys/mdw-mem.h new file mode 100644 index 000000000000..cb744f41d15e --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-mem.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_APU_MDW_MEM_H__ +#define __MTK_APU_MDW_MEM_H__ + +struct mdw_mem *mdw_mem_alloc(struct mdw_fpriv *mpriv, u32 size, + u32 align, u64 flags, + enum mdw_mem_type type); +struct mdw_mem *mdw_mem_import(struct mdw_fpriv *mpriv, u64 handle, u32 size); +struct mdw_mem *mdw_mem_get(int handle); +int mdw_mem_map(struct mdw_mem *m); +int mdw_mem_unmap(struct mdw_mem *m); +int mdw_mem_init(struct mdw_device *mdev); +void mdw_mem_deinit(struct mdw_device *mdev); +int mdw_mem_free(struct mdw_mem *mem); +int mdw_mem_dma_map(struct mdw_mem *mem); +int mdw_mem_dma_unmap(struct mdw_mem *mem); +int apusys_mem_flush_kva(void *kva, u32 size); +int apusys_mem_invalidate_kva(void *kva, u32 size); +#endif diff --git a/drivers/soc/mediatek/apusys/mdw-rv-cmd.c b/drivers/soc/mediatek/apusys/mdw-rv-cmd.c new file mode 100644 index 000000000000..13d5febf5b61 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-rv-cmd.c @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include "mdw.h" +#include "mdw-mem.h" +#include "mdw-rv.h" + +#define MDW_IS_HIGHADDR(addr) (((addr) & 0xffffffff00000000) ? true : false) + +struct mdw_rv_cmd *mdw_rv_cmd_create(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + struct mdw_rv_cmd *rc = NULL; + u32 cb_size = 0, acc_cb = 0, i = 0, j = 0; + u32 subcmds_ofs = 0, cmdbuf_infos_ofs = 0, adj_matrix_ofs = 0; + struct mdw_rv_msg_cmd *rmc = NULL; + struct mdw_rv_msg_sc *rmsc = NULL; + struct mdw_rv_msg_cb *rmcb = NULL; + int ret = 0; + + /* check mem address for rv */ + if (MDW_IS_HIGHADDR(c->exec_infos->device_va) || + MDW_IS_HIGHADDR(c->cmdbufs->device_va)) { + dev_err(mpriv->mdev->dev, "rv dva high addr(0x%llx/0x%llx)\n", + c->cmdbufs->device_va, c->exec_infos->device_va); + goto out; + } + + rc = vzalloc(sizeof(*rc)); + if (!rc) + goto out; + + init_completion(&rc->s_msg.cmplt); + /* set start timestamp */ + rc->start_ts_ns = c->start_ts.tv_sec * 1000000000 + c->start_ts.tv_nsec; + + /* calc size and offset */ + rc->c = c; + cb_size += sizeof(struct mdw_rv_msg_cmd); + cb_size = MDW_ALIGN(cb_size, MDW_DEFAULT_ALIGN); + adj_matrix_ofs = cb_size; + cb_size += (c->num_subcmds * c->num_subcmds * sizeof(u8)); + cb_size = MDW_ALIGN(cb_size, MDW_DEFAULT_ALIGN); + subcmds_ofs = cb_size; + cb_size += (c->num_subcmds * sizeof(struct mdw_rv_msg_sc)); + cb_size = MDW_ALIGN(cb_size, MDW_DEFAULT_ALIGN); + cmdbuf_infos_ofs = cb_size; + cb_size += (c->num_cmdbufs * sizeof(struct mdw_rv_msg_cb)); + + /* allocate communicate buffer */ + rc->cb = mdw_mem_alloc(mpriv, cb_size, MDW_DEFAULT_ALIGN, + (1ULL << MDW_MEM_IOCTL_ALLOC_CACHEABLE | + 1ULL << MDW_MEM_IOCTL_ALLOC_32BIT), + MDW_MEM_TYPE_INTERNAL); + if (!rc->cb) { + dev_err(mpriv->mdev->dev, "c(0x%llx) alloc cb size(%u) fail\n", + c->kid, cb_size); + goto free_rc; + } + + ret = mdw_mem_map(rc->cb); + if (ret) { + dev_err(mpriv->mdev->dev, "c(0x%llx) map cb size(%u) fail\n", + c->kid, cb_size); + goto free_mem; + } + + /* assign cmd info */ + rmc = (struct mdw_rv_msg_cmd *)rc->cb->vaddr; + rmc->session_id = (u64)c->mpriv; + rmc->cmd_id = c->kid; + rmc->exec_infos = c->exec_infos->device_va; + rmc->exec_size = c->exec_infos->size; + rmc->priority = c->priority; + rmc->hardlimit = c->hardlimit; + rmc->softlimit = c->softlimit; + rmc->power_save = c->power_save; + rmc->power_plcy = c->power_plcy; + rmc->power_dtime = c->power_dtime; + rmc->app_type = c->app_type; + rmc->num_subcmds = c->num_subcmds; + rmc->num_cmdbufs = c->num_cmdbufs; + rmc->subcmds_offset = subcmds_ofs; + rmc->cmdbuf_infos_offset = cmdbuf_infos_ofs; + rmc->adj_matrix_offset = adj_matrix_ofs; + + memcpy((void *)rmc + rmc->adj_matrix_offset, c->adj_matrix, + c->num_subcmds * c->num_subcmds * sizeof(u8)); + + rmsc = (void *)rmc + rmc->subcmds_offset; + rmcb = (void *)rmc + rmc->cmdbuf_infos_offset; + for (i = 0; i < c->num_subcmds; i++) { + rmsc[i].type = c->subcmds[i].type; + rmsc[i].suggest_time = c->subcmds[i].suggest_time; + rmsc[i].vlm_usage = c->subcmds[i].vlm_usage; + rmsc[i].vlm_ctx_id = c->subcmds[i].vlm_ctx_id; + rmsc[i].vlm_force = c->subcmds[i].vlm_force; + rmsc[i].boost = c->subcmds[i].boost; + rmsc[i].ip_time = c->subcmds[i].ip_time; + rmsc[i].driver_time = c->subcmds[i].driver_time; + rmsc[i].bw = c->subcmds[i].bw; + rmsc[i].turbo_boost = c->subcmds[i].turbo_boost; + rmsc[i].min_boost = c->subcmds[i].min_boost; + rmsc[i].max_boost = c->subcmds[i].max_boost; + rmsc[i].hse_en = c->subcmds[i].hse_en; + rmsc[i].pack_id = c->subcmds[i].pack_id; + rmsc[i].num_cmdbufs = c->subcmds[i].num_cmdbufs; + rmsc[i].cmdbuf_start_idx = acc_cb; + + for (j = 0; j < rmsc[i].num_cmdbufs; j++) { + rmcb[acc_cb + j].size = + c->ksubcmds[i].cmdbufs[j].size; + rmcb[acc_cb + j].device_va = + c->ksubcmds[i].daddrs[j]; + } + acc_cb += c->subcmds[i].num_cmdbufs; + } + + /* clear exec ret */ + c->einfos->c.ret = 0; + c->einfos->c.sc_rets = 0; + + apusys_mem_flush_kva(rc->cb->vaddr, rc->cb->size); + apusys_mem_flush_kva(c->exec_infos->vaddr, c->exec_infos->size); + + goto out; + +free_mem: + mdw_mem_free(rc->cb); +free_rc: + vfree(rc); + rc = NULL; +out: + return rc; +} + +int mdw_rv_cmd_delete(struct mdw_rv_cmd *rc) +{ + if (!rc) + return -EINVAL; + mdw_mem_unmap(rc->cb); + mdw_mem_free(rc->cb); + vfree(rc); + + return 0; +} + +void mdw_rv_cmd_done(struct mdw_rv_cmd *rc, int ret) +{ + struct mdw_cmd *c = rc->c; + + apusys_mem_invalidate_kva(rc->cb->vaddr, rc->cb->size); + apusys_mem_invalidate_kva(c->exec_infos->vaddr, c->exec_infos->size); + + mdw_rv_cmd_delete(rc); + c->complete(c, ret); +} diff --git a/drivers/soc/mediatek/apusys/mdw-rv-dev.c b/drivers/soc/mediatek/apusys/mdw-rv-dev.c new file mode 100644 index 000000000000..3c708bda7249 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-rv-dev.c @@ -0,0 +1,386 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include + +#include "mdw.h" +#include "mdw-rv.h" +#include "mdw-rv-msg.h" + +#define MDW_CMD_IPI_TIMEOUT (2 * 1000) /* ms */ + +static struct mdw_ipi_msg_sync *mdw_rv_dev_get_msg(struct mdw_rv_dev *mrdev, + u64 sync_id) +{ + struct mdw_ipi_msg_sync *s_msg = NULL; + struct list_head *tmp = NULL, *list_ptr = NULL; + + mutex_lock(&mrdev->msg_mtx); + list_for_each_safe(list_ptr, tmp, &mrdev->s_list) { + s_msg = list_entry(list_ptr, struct mdw_ipi_msg_sync, ud_item); + if (s_msg->msg.sync_id == sync_id) + break; + s_msg = NULL; + } + mutex_unlock(&mrdev->msg_mtx); + + return s_msg; +} + +static int mdw_rv_dev_send_msg(struct mdw_rv_dev *mrdev, + struct mdw_ipi_msg_sync *s_msg) +{ + int ret = 0; + u32 cnt = 50, i = 0; + + s_msg->msg.sync_id = (u64)s_msg; + + mutex_lock(&mrdev->msg_mtx); + list_add_tail(&s_msg->ud_item, &mrdev->s_list); + mutex_unlock(&mrdev->msg_mtx); + + for (i = 0; i < cnt; i++) { + ret = rpmsg_send(mrdev->ept, &s_msg->msg, sizeof(s_msg->msg)); + + /* send busy, retry */ + if (ret == -EBUSY) { + msleep(20); + continue; + } + + break; + } + + if (ret) { + dev_err(mrdev->mdev->dev, "send ipi msg(0x%llx) fail(%d)\n", + s_msg->msg.sync_id, ret); + mutex_lock(&mrdev->msg_mtx); + list_del(&s_msg->ud_item); + mutex_unlock(&mrdev->msg_mtx); + } + + return ret; +} + +static void mdw_rv_ipi_cmplt_sync(struct mdw_ipi_msg_sync *s_msg) +{ + complete(&s_msg->cmplt); +} + +static int mdw_rv_dev_send_sync(struct mdw_rv_dev *mrdev, + struct mdw_ipi_msg *msg) +{ + int ret = 0; + struct mdw_ipi_msg_sync *s_msg = NULL; + unsigned long timeout = msecs_to_jiffies(MDW_CMD_IPI_TIMEOUT); + + s_msg = vzalloc(sizeof(*s_msg)); + if (!s_msg) + return -ENOMEM; + + memcpy(&s_msg->msg, msg, sizeof(*msg)); + init_completion(&s_msg->cmplt); + s_msg->complete = mdw_rv_ipi_cmplt_sync; + + mutex_lock(&mrdev->mtx); + ret = mdw_rv_dev_send_msg(mrdev, s_msg); + if (ret) { + dev_err(mrdev->mdev->dev, "send msg fail\n"); + goto fail_send_sync; + } + mutex_unlock(&mrdev->mtx); + + if (!wait_for_completion_timeout(&s_msg->cmplt, timeout)) { + dev_err(mrdev->mdev->dev, "ipi no response\n"); + mutex_lock(&mrdev->msg_mtx); + list_del(&s_msg->ud_item); + mutex_unlock(&mrdev->msg_mtx); + ret = -ETIME; + } else { + memcpy(msg, &s_msg->msg, sizeof(*msg)); + ret = msg->ret; + if (ret) + dev_err(mrdev->mdev->dev, "up return fail(%d)\n", ret); + } + + goto out; + +fail_send_sync: + mutex_unlock(&mrdev->mtx); +out: + vfree(s_msg); + + return ret; +} + +static void mdw_rv_ipi_cmplt_cmd(struct mdw_ipi_msg_sync *s_msg) +{ + int ret = 0; + struct mdw_rv_cmd *rc = + container_of(s_msg, struct mdw_rv_cmd, s_msg); + + switch (s_msg->msg.ret) { + case MDW_IPI_MSG_STATUS_BUSY: + ret = -EBUSY; + break; + + case MDW_IPI_MSG_STATUS_ERR: + ret = -EREMOTEIO; + break; + + case MDW_IPI_MSG_STATUS_TIMEOUT: + ret = -ETIME; + break; + + default: + break; + } + + mdw_rv_cmd_done(rc, ret); +} + +static int mdw_rv_dev_send_cmd(struct mdw_rv_dev *mrdev, struct mdw_rv_cmd *rc) +{ + int ret = 0; + + rc->s_msg.msg.id = MDW_IPI_APU_CMD; + rc->s_msg.msg.c.iova = rc->cb->device_va; + rc->s_msg.msg.c.size = rc->cb->size; + rc->s_msg.msg.c.start_ts_ns = rc->start_ts_ns; + rc->s_msg.complete = mdw_rv_ipi_cmplt_cmd; + + ret = mdw_rv_dev_send_msg(mrdev, &rc->s_msg); + if (ret) + dev_err(mrdev->mdev->dev, "pid(%d) send msg fail\n", + current->pid); + + return ret; +} + +int mdw_rv_dev_run_cmd(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + struct mdw_rv_dev *mrdev = + (struct mdw_rv_dev *)mpriv->mdev->dev_specific; + struct mdw_rv_cmd *rc = NULL; + int ret = 0; + + rc = mdw_rv_cmd_create(mpriv, c); + if (!rc) { + ret = -EINVAL; + goto out; + } + + mutex_lock(&mrdev->mtx); + ret = mdw_rv_dev_send_cmd(mrdev, rc); + if (ret) + mdw_rv_cmd_delete(rc); + mutex_unlock(&mrdev->mtx); + +out: + return ret; +} + +static int mdw_rv_callback(struct rpmsg_device *rpdev, void *data, int len, + void *priv, u32 src) +{ + struct mdw_ipi_msg *msg = (struct mdw_ipi_msg *)data; + struct mdw_ipi_msg_sync *s_msg = NULL; + struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)priv; + + s_msg = mdw_rv_dev_get_msg(mrdev, msg->sync_id); + if (s_msg) { + memcpy(&s_msg->msg, msg, sizeof(*msg)); + mutex_lock(&mrdev->msg_mtx); + list_del(&s_msg->ud_item); + mutex_unlock(&mrdev->msg_mtx); + s_msg->complete(s_msg); + } + + return 0; +} + +int mdw_rv_dev_set_param(struct mdw_rv_dev *mrdev, enum mdw_info_type type, + u32 val) +{ + struct mdw_ipi_msg msg; + int ret = 0; + + memset(&msg, 0, sizeof(msg)); + msg.id = MDW_IPI_PARAM; + memcpy(&msg.p, &mrdev->param, sizeof(msg.p)); + switch (type) { + case MDW_INFO_ULOG: + msg.p.uplog = val; + break; + case MDW_INFO_PREEMPT_POLICY: + msg.p.preempt_policy = val; + break; + case MDW_INFO_SCHED_POLICY: + msg.p.sched_policy = val; + break; + default: + ret = -EINVAL; + goto out; + } + ret = mdw_rv_dev_send_sync(mrdev, &msg); + if (!ret) + memcpy(&mrdev->param, &msg.p, sizeof(msg.p)); +out: + return ret; +} + +u32 mdw_rv_dev_get_param(struct mdw_rv_dev *mrdev, enum mdw_info_type type) +{ + u32 ret = 0; + + switch (type) { + case MDW_INFO_ULOG: + ret = (int)mrdev->param.uplog; + break; + case MDW_INFO_PREEMPT_POLICY: + ret = (int)mrdev->param.preempt_policy; + break; + case MDW_INFO_SCHED_POLICY: + ret = (int)mrdev->param.sched_policy; + break; + case MDW_INFO_NORMAL_TASK_DLA: + case MDW_INFO_NORMAL_TASK_DSP: + case MDW_INFO_NORMAL_TASK_DMA: + dev_warn(mrdev->mdev->dev, "not support(%d)\n", type); + break; + default: + dev_warn(mrdev->mdev->dev, "unknown type(%d)\n", type); + ret = -EINVAL; + break; + } + + return ret; +} + +static int mdw_rv_dev_handshake(struct mdw_rv_dev *mrdev) +{ + struct mdw_ipi_msg msg; + int ret = 0, type = 0; + + memset(&msg, 0, sizeof(msg)); + msg.id = MDW_IPI_HANDSHAKE; + msg.h.h_id = MDW_IPI_HANDSHAKE_BASIC_INFO; + ret = mdw_rv_dev_send_sync(mrdev, &msg); + if (ret) + goto out; + + if (msg.id != MDW_IPI_HANDSHAKE || + msg.h.h_id != MDW_IPI_HANDSHAKE_BASIC_INFO) { + ret = -EINVAL; + goto out; + } + + memcpy(mrdev->dev_mask, &msg.h.basic.dev_bmp, sizeof(mrdev->dev_mask)); + mrdev->rv_version = msg.h.basic.version; + + do { + type = find_next_bit(mrdev->dev_mask, APUSYS_DEVICE_MAX, type); + if (type >= APUSYS_DEVICE_MAX) + break; + + memset(&msg, 0, sizeof(msg)); + msg.id = MDW_IPI_HANDSHAKE; + msg.h.h_id = MDW_IPI_HANDSHAKE_DEV_NUM; + msg.h.dev.type = type; + ret = mdw_rv_dev_send_sync(mrdev, &msg); + if (ret) + break; + + if (msg.id != MDW_IPI_HANDSHAKE || + msg.h.h_id != MDW_IPI_HANDSHAKE_DEV_NUM) { + ret = -EINVAL; + break; + } + + mrdev->dev_num[msg.h.dev.type] = msg.h.dev.num; + memcpy(&mrdev->meta_data[msg.h.dev.type][0], + msg.h.dev.meta, sizeof(msg.h.dev.meta)); + type++; + } while (type < APUSYS_DEVICE_MAX); + +out: + return ret; +} + +static void mdw_rv_dev_init_func(struct work_struct *wk) +{ + struct mdw_rv_dev *mrdev = container_of(wk, struct mdw_rv_dev, init_wk); + struct mdw_device *mdev = mrdev->mdev; + int ret = 0; + + ret = mdw_rv_dev_handshake(mrdev); + if (ret) { + pr_err("handshake fail(%d)\n", ret); + return; + } + + memcpy(mdev->dev_mask, mrdev->dev_mask, sizeof(mrdev->dev_mask)); + mdev->inited = true; +} + +int mdw_rv_dev_init(struct mdw_device *mdev) +{ + struct rpmsg_channel_info chinfo = {}; + struct mdw_rv_dev *mrdev = NULL; + int ret = 0; + + if (!mdev->rpdev) { + dev_err(mdev->dev, "rpdev is NULL\n"); + ret = -EINVAL; + goto out; + } + + mrdev = kvzalloc(sizeof(*mrdev), GFP_KERNEL); + if (!mrdev) + return -ENOMEM; + + mdev->dev_specific = mrdev; + mrdev->mdev = mdev; + mrdev->rpdev = mdev->rpdev; + + strscpy(chinfo.name, mrdev->rpdev->id.name, RPMSG_NAME_SIZE); + chinfo.src = mrdev->rpdev->src; + chinfo.dst = RPMSG_ADDR_ANY; + mrdev->ept = rpmsg_create_ept(mrdev->rpdev, mdw_rv_callback, mrdev, + chinfo); + if (!mrdev->ept) { + dev_err(mdev->dev, "create ept fail\n"); + ret = -ENODEV; + goto free_mrdev; + } + + /* init up dev */ + mutex_init(&mrdev->msg_mtx); + mutex_init(&mrdev->mtx); + INIT_LIST_HEAD(&mrdev->s_list); + INIT_WORK(&mrdev->init_wk, &mdw_rv_dev_init_func); + + schedule_work(&mrdev->init_wk); + + goto out; + +free_mrdev: + kvfree(mrdev); + mdev->dev_specific = NULL; +out: + return ret; +} + +void mdw_rv_dev_deinit(struct mdw_device *mdev) +{ + struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific; + + if (!mrdev) + return; + + rpmsg_destroy_ept(mrdev->ept); + kvfree(mrdev); + mdev->dev_specific = NULL; +} diff --git a/drivers/soc/mediatek/apusys/mdw-rv-msg.h b/drivers/soc/mediatek/apusys/mdw-rv-msg.h new file mode 100644 index 000000000000..b0a21bd50060 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-rv-msg.h @@ -0,0 +1,90 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_APU_MDW_RV_MSG__ +#define __MTK_APU_MDW_RV_MSG__ + +/* mdw queue cmd type */ +enum { + MDW_IPI_NONE, + MDW_IPI_APU_CMD, + MDW_IPI_HANDSHAKE, + MDW_IPI_PARAM, + MDW_IPI_USER, + MDW_IPI_MAX = 0x20, +}; + +enum { + MDW_IPI_HANDSHAKE_BASIC_INFO, + MDW_IPI_HANDSHAKE_DEV_NUM, + MDW_IPI_HANDSHAKE_TASK_NUM, +}; + +enum { + MDW_IPI_MSG_STATUS_OK, + MDW_IPI_MSG_STATUS_BUSY, + MDW_IPI_MSG_STATUS_ERR, + MDW_IPI_MSG_STATUS_TIMEOUT, +}; + +struct mdw_ipi_ucmd { + u32 dev_type; + u32 dev_idx; + u64 iova; + u32 size; +}; + +struct mdw_ipi_apu_cmd { + u64 start_ts_ns; // cmd time + u64 iova; + u32 size; +}; + +struct mdw_ipi_handshake { + u32 h_id; + union { + struct { + u64 magic; + u32 version; + u64 dev_bmp; + } basic; + struct { + u32 type; + u32 num; + u8 meta[MDW_DEV_META_SIZE]; + } dev; + struct { + u32 type; + u32 norm_task_num; + u32 deadline_task_num; + } task; + }; +}; + +struct mdw_ipi_param { + u32 uplog; + u32 preempt_policy; + u32 sched_policy; +}; + +struct mdw_ipi_msg { + u64 sync_id; + u32 id; //ipi id + s32 ret; + union { + struct mdw_ipi_apu_cmd c; + struct mdw_ipi_handshake h; + struct mdw_ipi_param p; + struct mdw_ipi_ucmd u; + }; +} __packed; + +struct mdw_ipi_msg_sync { + struct mdw_ipi_msg msg; + struct list_head ud_item; + struct completion cmplt; + void (*complete)(struct mdw_ipi_msg_sync *s_msg); +}; +#endif diff --git a/drivers/soc/mediatek/apusys/mdw-rv.c b/drivers/soc/mediatek/apusys/mdw-rv.c new file mode 100644 index 000000000000..3c825b89b3e9 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-rv.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include "mdw.h" +#include "mdw-rv.h" + +static int mdw_rv_sw_init(struct mdw_device *mdev) +{ + int ret = 0, i = 0; + struct mdw_rv_dev *rdev = (struct mdw_rv_dev *)mdev->dev_specific; + struct mdw_dinfo *d = NULL; + + /* update device info */ + for (i = 0; i < MDW_DEV_MAX; i++) { + if (!test_bit(i, rdev->dev_mask) || mdev->dinfos[i]) + continue; + + /* setup mdev's info */ + d = kvzalloc(sizeof(*d), GFP_KERNEL); + if (!d) + goto free_dinfo; + + d->num = rdev->dev_num[i]; + d->type = i; + + memcpy(d->meta, &rdev->meta_data[i][0], sizeof(d->meta)); + + mdev->dinfos[i] = d; + bitmap_set(mdev->dev_mask, i, 1); + } + + goto out; + +free_dinfo: + for (i = 0; i < MDW_DEV_MAX; i++) { + if (mdev->dinfos[i]) { + kvfree(mdev->dinfos[i]); + mdev->dinfos[i] = NULL; + } + } + ret = -ENOMEM; +out: + return ret; +} + +static void mdw_rv_sw_deinit(struct mdw_device *mdev) +{ + unsigned int i = 0; + + for (i = 0; i < MDW_DEV_MAX; i++) { + if (mdev->dinfos[i]) { + kvfree(mdev->dinfos[i]); + mdev->dinfos[i] = NULL; + } + } +} + +static int mdw_rv_late_init(struct mdw_device *mdev) +{ + int ret = 0; + + ret = mdw_rv_dev_init(mdev); + if (ret || !mdev->dev_specific) { + dev_err(mdev->dev, "init mdw rvdev fail(%d)\n", ret); + goto dev_deinit; + } + + goto out; + +dev_deinit: + mdw_rv_dev_deinit(mdev); +out: + return ret; +} + +static void mdw_rv_late_deinit(struct mdw_device *mdev) +{ + mdw_rv_dev_deinit(mdev); +} + +static int mdw_rv_run_cmd(struct mdw_fpriv *mpriv, struct mdw_cmd *c) +{ + return mdw_rv_dev_run_cmd(mpriv, c); +} + +static int mdw_rv_set_power(struct mdw_device *mdev, u32 type, u32 idx, + u32 boost) +{ + return -EINVAL; +} + +static int mdw_rv_ucmd(struct mdw_device *mdev, u32 type, void *vaddr, + u32 size) +{ + return -EINVAL; +} + +static int mdw_rv_set_param(struct mdw_device *mdev, enum mdw_info_type type, + u32 val) +{ + struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific; + + return mdw_rv_dev_set_param(mrdev, type, val); +} + +static u32 mdw_rv_get_info(struct mdw_device *mdev, enum mdw_info_type type) +{ + struct mdw_rv_dev *mrdev = (struct mdw_rv_dev *)mdev->dev_specific; + + return mdw_rv_dev_get_param(mrdev, type); +} + +static const struct mdw_dev_func mdw_rv_func = { + .sw_init = mdw_rv_sw_init, + .sw_deinit = mdw_rv_sw_deinit, + .late_init = mdw_rv_late_init, + .late_deinit = mdw_rv_late_deinit, + .run_cmd = mdw_rv_run_cmd, + .set_power = mdw_rv_set_power, + .ucmd = mdw_rv_ucmd, + .set_param = mdw_rv_set_param, + .get_info = mdw_rv_get_info, +}; + +void mdw_rv_set_func(struct mdw_device *mdev) +{ + mdev->dev_funcs = &mdw_rv_func; + mdev->uapi_ver = MDW_UAPI_VERSION; +} diff --git a/drivers/soc/mediatek/apusys/mdw-rv.h b/drivers/soc/mediatek/apusys/mdw-rv.h new file mode 100644 index 000000000000..dbaffc228091 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-rv.h @@ -0,0 +1,98 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_APU_MDW_RV_H__ +#define __MTK_APU_MDW_RV_H__ + +#include "mdw.h" +#include "mdw-rv-msg.h" + +struct mdw_rv_dev { + struct rpmsg_device *rpdev; + struct rpmsg_endpoint *ept; + struct mdw_device *mdev; + + struct mdw_ipi_param param; + + struct list_head s_list; /* for sync msg */ + struct mutex msg_mtx; + struct mutex mtx; /* protect send cmd */ + + struct work_struct init_wk; + + /* rv information */ + u32 rv_version; + unsigned long dev_mask[BITS_TO_LONGS(MDW_DEV_MAX)]; + u8 dev_num[MDW_DEV_MAX]; + u8 meta_data[MDW_DEV_MAX][MDW_DEV_META_SIZE]; +}; + +struct mdw_rv_cmd { + struct mdw_cmd *c; + struct mdw_mem *cb; + struct list_head u_item; /* to usr list */ + struct mdw_ipi_msg_sync s_msg; /* for ipi */ + u64 start_ts_ns; /* create time at ap */ +}; + +struct mdw_rv_msg_cmd { + /* ids */ + u64 session_id; + u64 cmd_id; + /* exec infos */ + u64 exec_infos; + u32 exec_size; + /* params */ + u32 priority; + u32 hardlimit; + u32 softlimit; + u32 power_save; + u32 power_plcy; + u32 power_dtime; + u32 app_type; + u32 num_subcmds; + u32 subcmds_offset; + u32 num_cmdbufs; + u32 cmdbuf_infos_offset; + u32 adj_matrix_offset; +} __packed; + +struct mdw_rv_msg_sc { + /* params */ + u32 type; + u32 suggest_time; + u32 vlm_usage; + u32 vlm_ctx_id; + u32 vlm_force; + u32 boost; + u32 turbo_boost; + u32 min_boost; + u32 max_boost; + u32 hse_en; + u32 driver_time; + u32 ip_time; + u32 bw; + u32 pack_id; + /* cmdbufs info */ + u32 cmdbuf_start_idx; + u32 num_cmdbufs; +} __packed; + +struct mdw_rv_msg_cb { + u64 device_va; + u32 size; +} __packed; + +int mdw_rv_dev_init(struct mdw_device *mdev); +void mdw_rv_dev_deinit(struct mdw_device *mdev); +int mdw_rv_dev_run_cmd(struct mdw_fpriv *mpriv, struct mdw_cmd *c); +int mdw_rv_dev_set_param(struct mdw_rv_dev *mrdev, u32 idx, u32 val); +u32 mdw_rv_dev_get_param(struct mdw_rv_dev *mrdev, u32 idx); + +struct mdw_rv_cmd *mdw_rv_cmd_create(struct mdw_fpriv *mpriv, + struct mdw_cmd *c); +int mdw_rv_cmd_delete(struct mdw_rv_cmd *rc); +void mdw_rv_cmd_done(struct mdw_rv_cmd *rc, int ret); +#endif diff --git a/drivers/soc/mediatek/apusys/mdw-sysfs.c b/drivers/soc/mediatek/apusys/mdw-sysfs.c new file mode 100644 index 000000000000..46538ab9c196 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw-sysfs.c @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#include +#include +#include +#include +#include + +#include "mdw.h" + +static ssize_t dsp_task_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + int ret = 0; + u32 num = 0; + + num = mdev->dev_funcs->get_info(mdev, MDW_INFO_NORMAL_TASK_DSP); + ret = sprintf(buf, "%u\n", num); + + return ret; +} +static DEVICE_ATTR_RO(dsp_task_num); + +static ssize_t dla_task_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + int ret = 0; + u32 num = 0; + + num = mdev->dev_funcs->get_info(mdev, MDW_INFO_NORMAL_TASK_DLA); + ret = sprintf(buf, "%u\n", num); + + return ret; +} +static DEVICE_ATTR_RO(dla_task_num); + +static ssize_t dma_task_num_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + int ret = 0; + u32 num = 0; + + num = mdev->dev_funcs->get_info(mdev, MDW_INFO_NORMAL_TASK_DMA); + ret = sprintf(buf, "%u\n", num); + + return ret; +} +static DEVICE_ATTR_RO(dma_task_num); + +static struct attribute *mdw_task_attrs[] = { + &dev_attr_dsp_task_num.attr, + &dev_attr_dla_task_num.attr, + &dev_attr_dma_task_num.attr, + NULL, +}; + +static struct attribute_group mdw_devinfo_attr_group = { + .name = "queue", + .attrs = mdw_task_attrs, +}; + +static ssize_t policy_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return -EINVAL; +} + +static ssize_t policy_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + return -EINVAL; +} +static DEVICE_ATTR_RW(policy); + +static struct attribute *mdw_sched_attrs[] = { + &dev_attr_policy.attr, + NULL, +}; + +static struct attribute_group mdw_sched_attr_group = { + .name = "sched", + .attrs = mdw_sched_attrs, +}; + +static ssize_t mem_statistics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int n = 0; + + return n; +} +static DEVICE_ATTR_RO(mem_statistics); + +static struct attribute *mdw_mem_attrs[] = { + &dev_attr_mem_statistics.attr, + NULL, +}; + +static struct attribute_group mdw_mem_attr_group = { + .name = "memory", + .attrs = mdw_mem_attrs, +}; + +static ssize_t ulog_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + int ret = 0; + u32 log_lv = 0; + + log_lv = mdev->dev_funcs->get_info(mdev, MDW_INFO_ULOG); + ret = sprintf(buf, "%u\n", log_lv); + + return ret; +} + +static ssize_t ulog_store(struct device *dev, struct device_attribute *attr, + const char *buf, + size_t count) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + u32 val = 0; + + if (!kstrtouint(buf, 10, &val)) + mdev->dev_funcs->set_param(mdev, MDW_INFO_ULOG, val); + + return count; +} +static DEVICE_ATTR_RW(ulog); + +static ssize_t klog_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + int ret = 0; + u32 log_lv = 0; + + log_lv = mdev->dev_funcs->get_info(mdev, MDW_INFO_KLOG); + ret = sprintf(buf, "%u\n", log_lv); + + return ret; +} + +static ssize_t klog_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct mdw_device *mdev = dev_get_drvdata(dev); + u32 val = 0; + + if (!kstrtouint(buf, 10, &val)) + mdev->dev_funcs->set_param(mdev, MDW_INFO_KLOG, val); + + return count; +} +static DEVICE_ATTR_RW(klog); + +static struct attribute *mdw_log_attrs[] = { + &dev_attr_ulog.attr, + &dev_attr_klog.attr, + NULL, +}; + +static struct attribute_group mdw_log_attr_group = { + .name = "log", + .attrs = mdw_log_attrs, +}; + +int mdw_sysfs_init(struct mdw_device *mdev) +{ + int ret = 0; + + dev_set_drvdata(mdev->misc_dev.this_device, mdev); + + ret = sysfs_create_group(&mdev->misc_dev.this_device->kobj, + &mdw_devinfo_attr_group); + ret |= sysfs_create_group(&mdev->misc_dev.this_device->kobj, + &mdw_sched_attr_group); + ret |= sysfs_create_group(&mdev->misc_dev.this_device->kobj, + &mdw_log_attr_group); + ret |= sysfs_create_group(&mdev->misc_dev.this_device->kobj, + &mdw_mem_attr_group); + + return ret; +} + +void mdw_sysfs_deinit(struct mdw_device *mdev) +{ + struct device *dev = mdev->misc_dev.this_device; + + sysfs_remove_group(&dev->kobj, &mdw_mem_attr_group); + sysfs_remove_group(&dev->kobj, &mdw_log_attr_group); + sysfs_remove_group(&dev->kobj, &mdw_sched_attr_group); + sysfs_remove_group(&dev->kobj, &mdw_devinfo_attr_group); +} diff --git a/drivers/soc/mediatek/apusys/mdw.h b/drivers/soc/mediatek/apusys/mdw.h new file mode 100644 index 000000000000..e65e246f6494 --- /dev/null +++ b/drivers/soc/mediatek/apusys/mdw.h @@ -0,0 +1,208 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2021 MediaTek Inc. + */ + +#ifndef __MTK_APU_MDW_H__ +#define __MTK_APU_MDW_H__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apu-core.h" +#include "apu-device.h" +#include "mdw-ioctl.h" + +#define MDW_NAME "apusys" +#define MDW_DEV_MAX (APUSYS_DEVICE_MAX) +#define MDW_SUBCMD_MAX (63) +#define MDW_PRIORITY_MAX (32) +#define MDW_BOOST_MAX (100) +#define MDW_DEFAULT_ALIGN (16) +#define MDW_UAPI_VERSION (2) + +#define MDW_ALIGN(x, align) (((x) + (align) - 1) & (~((align) - 1))) + +enum mdw_info_type { + MDW_INFO_KLOG, + MDW_INFO_ULOG, + MDW_INFO_PREEMPT_POLICY, + MDW_INFO_SCHED_POLICY, + + MDW_INFO_NORMAL_TASK_DLA, + MDW_INFO_NORMAL_TASK_DSP, + MDW_INFO_NORMAL_TASK_DMA, + + MDW_INFO_MAX, +}; + +struct mdw_fpriv; +struct mdw_device; + +enum mdw_mem_type { + MDW_MEM_TYPE_NONE, + MDW_MEM_TYPE_INTERNAL, + MDW_MEM_TYPE_ALLOC, + MDW_MEM_TYPE_IMPORT, +}; + +struct mdw_mem { + /* in */ + unsigned int size; + unsigned int align; + u64 flags; + struct mdw_fpriv *mpriv; + bool need_handle; + + /* out */ + int handle; + void *vaddr; + u64 device_va; + u32 dva_size; + void *priv; + + /* control */ + enum mdw_mem_type type; + struct list_head u_item; + struct list_head m_item; + struct kref map_ref; + void (*release)(struct mdw_mem *m); +}; + +struct mdw_dinfo { + u32 type; + u32 num; + u8 meta[MDW_DEV_META_SIZE]; +}; + +struct mdw_device { + struct rpmsg_device *rpdev; + struct device *dev; + struct miscdevice misc_dev; + struct device *dma_dev; + + bool inited; + atomic_t sw_inited; + + u64 vlm_start; + u32 vlm_size; + + u32 uapi_ver; + + unsigned long dev_mask[BITS_TO_LONGS(MDW_DEV_MAX)]; + struct mdw_dinfo *dinfos[MDW_DEV_MAX]; + + const struct mdw_dev_func *dev_funcs; + void *dev_specific; +}; + +struct mdw_fpriv { + struct mdw_device *mdev; + + struct list_head mems; + struct list_head cmds; + struct mutex mtx; /* protect mems */ + + /* ref count for cmd/mem */ + struct kref ref; + void (*get)(struct mdw_fpriv *mpriv); + void (*put)(struct mdw_fpriv *mpriv); +}; + +struct mdw_exec_info { + struct mdw_cmd_exec_info c; + struct mdw_subcmd_exec_info sc; +}; + +struct mdw_subcmd_kinfo { + struct mdw_subcmd_info *info; /* c->subcmds */ + struct mdw_subcmd_cmdbuf *cmdbufs; /* from usr */ + struct mdw_mem **ori_cbs; /* pointer to original cmdbuf */ + struct mdw_subcmd_exec_info *sc_einfo; + u64 *kvaddrs; /* pointer to duplicated buf */ + u64 *daddrs; /* pointer to duplicated buf */ + void *priv; /* mdw_ap_sc */ +}; + +struct mdw_fence { + struct dma_fence base_fence; + struct mdw_device *mdev; + spinlock_t lock; /* used by dma_fence_init */ +}; + +struct mdw_cmd { + pid_t pid; + pid_t tgid; + u64 kid; + u64 uid; + u64 usr_id; + u32 priority; + u32 hardlimit; + u32 softlimit; + u32 power_save; + u32 power_plcy; + u32 power_dtime; + u32 app_type; + u32 num_subcmds; + struct mdw_subcmd_info *subcmds; /* from usr */ + struct mdw_subcmd_kinfo *ksubcmds; + u32 num_cmdbufs; + u32 size_cmdbufs; + struct mdw_mem *cmdbufs; + struct mdw_mem *exec_infos; + struct mdw_exec_info *einfos; + u8 *adj_matrix; + + struct list_head u_item; + + struct timespec64 start_ts; + struct timespec64 end_ts; + + struct mdw_fpriv *mpriv; + int (*complete)(struct mdw_cmd *c, int ret); + + struct mdw_fence *fence; + struct work_struct t_wk; + struct dma_fence *wait_fence; +}; + +struct mdw_dev_func { + int (*late_init)(struct mdw_device *mdev); + void (*late_deinit)(struct mdw_device *mdev); + int (*sw_init)(struct mdw_device *mdev); + void (*sw_deinit)(struct mdw_device *mdev); + + int (*run_cmd)(struct mdw_fpriv *mpriv, struct mdw_cmd *c); + int (*set_power)(struct mdw_device *mdev, u32 type, u32 idx, u32 boost); + int (*ucmd)(struct mdw_device *mdev, u32 type, void *vaddr, u32 size); + int (*set_param)(struct mdw_device *mdev, enum mdw_info_type type, + u32 val); + u32 (*get_info)(struct mdw_device *mdev, enum mdw_info_type type); +}; + +void mdw_rv_set_func(struct mdw_device *mdev); + +long mdw_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); +int mdw_cmd_ioctl(struct mdw_fpriv *mpriv, void *data); + +void mdw_mem_mpriv_release(struct mdw_fpriv *mpriv); + +int mdw_mem_flush(struct mdw_mem *m); +int mdw_mem_invalidate(struct mdw_mem *m); + +#ifdef CONFIG_DEBUG_FS +int mdw_sysfs_init(struct mdw_device *mdev); +void mdw_sysfs_deinit(struct mdw_device *mdev); +#endif + +int mdw_dev_init(struct mdw_device *mdev); +void mdw_dev_deinit(struct mdw_device *mdev); +#endif From patchwork Sat Oct 23 11:14:06 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579571 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1FD9AC433FE for ; Sat, 23 Oct 2021 11:26:32 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id E165B60F6F for ; Sat, 23 Oct 2021 11:26:31 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org E165B60F6F Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=MYAZUciJlwQy3XtR/cFRUHWXWYeoLg81145+WfXqToQ=; b=2pp00WBcEUHuoa z6ADWY/XEYfBVDPJRW01cX3m02cfFoPgPRrK/f+k1WdyfduZxP8JrEvVAhkbJ23p+Gl6VvcqG2UdI DxjW6gjKBa4+VKpiIaZb8awvBHfLV1wO/icmrkQGLZngbLmbHZPCuBzgl57moNgEDcZQYDWssGkHV J5q866/ZoBEujIm+dev4eqcqRspFAkzfCnY2dk4O3yumm08E395deGntA5mvVCk51iatdV8jfPmoL uTZfZ961mp8/7iSzsZRUNBP+xi+xULknJajU1eVDn8TH/onlvFqvYd7cu2mrkaDfv0yo63k349ij2 79mPm4xXLlKGzLcRY1xA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9P-00CgQj-Hs; Sat, 23 Oct 2021 11:25:23 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9E-00CgNV-1l; Sat, 23 Oct 2021 11:25:13 +0000 X-UUID: ea558df9807b472c8c3b2f94a18251a4-20211023 X-UUID: ea558df9807b472c8c3b2f94a18251a4-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 619387162; Sat, 23 Oct 2021 04:25:03 -0700 Received: from mtkmbs10n2.mediatek.inc (172.21.101.183) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:00 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n2.mediatek.inc (172.21.101.183) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.3; Sat, 23 Oct 2021 19:14:59 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:14:59 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 10/13] arm64: dts: mt8192: Add APU-IOMMU nodes Date: Sat, 23 Oct 2021 19:14:06 +0800 Message-ID: <20211023111409.30463-11-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_042512_137018_96053055 X-CRM114-Status: UNSURE ( 9.65 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org From: Yong Wu Add APU-IOMMI nodes Signed-off-by: Yong Wu Signed-off-by: Flora Fu --- arch/arm64/boot/dts/mediatek/mt8192.dtsi | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi index 7014082637b0..d5e417a512a7 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -916,6 +917,14 @@ #clock-cells = <1>; }; + iommu_apu: m4u@19010000 { + compatible = "mediatek,mt8192-iommu-apu"; + reg = <0 0x19010000 0 0x1000>; + interrupts = ; + power-domains = <&apuspm 0>; + #iommu-cells = <1>; + }; + apu_conn: apu_conn@19020000 { compatible = "mediatek,mt8192-apu-conn", "syscon"; reg = <0 0x19020000 0 0x1000>; From patchwork Sat Oct 23 11:14:07 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579569 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C537C433EF for ; Sat, 23 Oct 2021 11:26:31 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 004D060FD8 for ; Sat, 23 Oct 2021 11:26:30 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 004D060FD8 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=sL1l1MHx8HSI8FfWq5Fv7u0dkX2XP+dO9BSWsUzHW54=; b=cF4pj5fJ0i8opi ITupFRrjaP49M034ZTENbOBDmnSKzhPJnNVp3xFFsjH1GnVG1l0CpAlaR6cm46538A1/BwomxkxnI xecnVj8jTilx2JOYxEBX2Cy8HC2yR1MwM2/mSYXn26Ft13A+b8Eria6P++cq8L5wfRf4tfbbUOjMR vJM0IYnubMxMpKemY4UdrC6j8Tchd8jnvx0WsL0xTY0+sO47oXdX2F7zS+dsRemF/H1CfedWqL6Ns I442QbAnoMVsyzaMkyd1E8XnF3zBWLEpnRDO375IdY+H5vILulYeWTMQSnnd574EfmPU9T/t8dps6 3Y4lZa7o2lCyxEIRMwXA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9C-00CgN7-Ra; Sat, 23 Oct 2021 11:25:11 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF98-00CgMT-6W; Sat, 23 Oct 2021 11:25:07 +0000 X-UUID: 9e9ff560dd1e4765a5e3f108ed10cc58-20211023 X-UUID: 9e9ff560dd1e4765a5e3f108ed10cc58-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 982351954; Sat, 23 Oct 2021 04:25:03 -0700 Received: from mtkmbs07n1.mediatek.inc (172.21.101.16) by MTKMBS62N2.mediatek.inc (172.29.193.42) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:01 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs07n1.mediatek.inc (172.21.101.16) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:15:00 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:15:00 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 11/13] arm64: dts: mt8192: Add apu power nodes Date: Sat, 23 Oct 2021 19:14:07 +0800 Message-ID: <20211023111409.30463-12-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_042506_274811_8793DCE7 X-CRM114-Status: UNSURE ( 9.09 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add apu power node. Signed-off-by: Flora Fu --- arch/arm64/boot/dts/mediatek/mt8192.dtsi | 62 ++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi index d5e417a512a7..c505c6926839 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi @@ -964,6 +964,68 @@ }; }; + apusys_power: apusys_power@190f1000 { + compatible = "mediatek,apusys-power", + "mediatek,mt8192-apu-power"; + reg = <0 0x190f1000 0 0x1000>, + <0 0x19000600 0 0x100>; + reg-names = "apu_pcu", + "apu_spare"; + power-domains = <&apuspm 0>; + clocks = <&topckgen CLK_TOP_DSP_SEL>, + <&topckgen CLK_TOP_DSP1_SEL>, + <&topckgen CLK_TOP_DSP1_NPUPLL_SEL>, + <&topckgen CLK_TOP_DSP2_SEL>, + <&topckgen CLK_TOP_DSP2_NPUPLL_SEL>, + <&topckgen CLK_TOP_DSP5_SEL>, + <&topckgen CLK_TOP_DSP5_APUPLL_SEL>, + <&topckgen CLK_TOP_IPU_IF_SEL>, + <&clk26m>, + <&topckgen CLK_TOP_MAINPLL_D4_D2>, + <&topckgen CLK_TOP_UNIVPLL_D4_D2>, + <&topckgen CLK_TOP_UNIVPLL_D6_D2>, + <&topckgen CLK_TOP_MMPLL_D6>, + <&topckgen CLK_TOP_MMPLL_D5>, + <&topckgen CLK_TOP_MMPLL_D4>, + <&topckgen CLK_TOP_UNIVPLL_D5>, + <&topckgen CLK_TOP_UNIVPLL_D4>, + <&topckgen CLK_TOP_UNIVPLL_D3>, + <&topckgen CLK_TOP_MAINPLL_D6>, + <&topckgen CLK_TOP_MAINPLL_D4>, + <&topckgen CLK_TOP_MAINPLL_D3>, + <&topckgen CLK_TOP_TVDPLL>, + <&topckgen CLK_TOP_APUPLL>, + <&topckgen CLK_TOP_NPUPLL>, + <&apmixedsys CLK_APMIXED_APUPLL>, + <&apmixedsys CLK_APMIXED_NPUPLL>; + clock-names = "clk_top_dsp_sel", + "clk_top_dsp1_sel", + "clk_top_dsp1_npupll_sel", + "clk_top_dsp2_sel", + "clk_top_dsp2_npupll_sel", + "clk_top_dsp5_sel", + "clk_top_dsp5_apupll_sel", + "clk_top_ipu_if_sel", + "clk_top_clk26m", + "clk_top_mainpll_d4_d2", + "clk_top_univpll_d4_d2", + "clk_top_univpll_d6_d2", + "clk_top_mmpll_d6", + "clk_top_mmpll_d5", + "clk_top_mmpll_d4", + "clk_top_univpll_d5", + "clk_top_univpll_d4", + "clk_top_univpll_d3", + "clk_top_mainpll_d6", + "clk_top_mainpll_d4", + "clk_top_mainpll_d3", + "clk_top_tvdpll_ck", + "clk_top_apupll_ck", + "clk_top_npupll_ck", + "clk_apmixed_apupll_rate", + "clk_apmixed_npupll_rate"; + }; + camsys: clock-controller@1a000000 { compatible = "mediatek,mt8192-camsys"; reg = <0 0x1a000000 0 0x1000>; From patchwork Sat Oct 23 11:14:08 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579565 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id CAB9BC433EF for ; Sat, 23 Oct 2021 11:18:51 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 8792460F50 for ; Sat, 23 Oct 2021 11:18:51 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org 8792460F50 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=BB1g2CdPvTaag1M7pJE3+wEszHnrnWvoTpYJVUk8FRo=; b=fcuvUZyYujVgz3 8pDgcywgBsIJb7shKJyqPM0IW6pkZlnDQqvMbXT214YAM74+gaYwOnCxjAHrnz75HK0K92gBzp+3O a+mq8cn9R8O12TW8HDD5Gl+t9IpyALf2C9yS+Bs8/+4hrBWtKYv67nGX0JViKzNybuUHznRADL8jx faY6zrq9J9NrWXZCkRCmUsm9NUXJzXautptfOUxPzhQ9siB2iL6y7jnYm7HJX4fTl70RhIHpv4/FF oPseKpyAu1YYrBKu76gp/eKK4NBAmWNynGETxiwtYbXMeenMaqfgfTvN4nmjpA5lFXJ6Rdna7bnHU T+xs3igN4RvT7ctuV8+w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF1b-00CdkG-2D; Sat, 23 Oct 2021 11:17:19 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meEzX-00CcRy-0B; Sat, 23 Oct 2021 11:15:12 +0000 X-UUID: 0bdce6a428b1496a84e8632d0d40ad8d-20211023 X-UUID: 0bdce6a428b1496a84e8632d0d40ad8d-20211023 Received: from mtkcas68.mediatek.inc [(172.29.94.19)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 1145453943; Sat, 23 Oct 2021 04:15:04 -0700 Received: from mtkmbs10n1.mediatek.inc (172.21.101.34) by MTKMBS62N1.mediatek.inc (172.29.193.41) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:02 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384) id 15.2.792.15; Sat, 23 Oct 2021 19:15:01 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:15:01 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 12/13] arm64: dts: mt8192: Add apu tinysys Date: Sat, 23 Oct 2021 19:14:08 +0800 Message-ID: <20211023111409.30463-13-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_041511_106093_D135B9CD X-CRM114-Status: UNSURE ( 9.70 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add node for APU tinysys. Signed-off-by: Flora Fu --- arch/arm64/boot/dts/mediatek/mt8192.dtsi | 36 ++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt8192.dtsi b/arch/arm64/boot/dts/mediatek/mt8192.dtsi index c505c6926839..8108084a3f6f 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192.dtsi +++ b/arch/arm64/boot/dts/mediatek/mt8192.dtsi @@ -925,6 +925,42 @@ #iommu-cells = <1>; }; + apusys_rv@19001000 { + compatible = "mediatek,mt8192-apusys-rv"; + reg = <0 0x19000000 0 0x1000>, + <0 0x19001000 0 0x1000>, + <0 0x19002000 0 0x10>; + reg-names = "apu_mbox", + "md32_sysctrl", + "apu_wdt"; + mediatek,apusys-power = <&apusys_power>; + power-domains = <&apuspm 0>; + iommus = <&iommu_apu IOMMU_PORT_APU_DATA>; + interrupts = , + ; + interrupt-names = "apu_wdt", + "mbox0_irq"; + apu_ctrl { + compatible = "mediatek,apu-ctrl-rpmsg"; + mtk,rpmsg-name = "apu-ctrl-rpmsg"; + }; + + apu_pwr_tx { + compatible = "mediatek,apupwr-tx-rpmsg"; + mtk,rpmsg-name = "apupwr-tx-rpmsg"; + }; + + apu_pwr_rx { + compatible = "mediatek,apupwr-rx-rpmsg"; + mtk,rpmsg-name = "apupwr-rx-rpmsg"; + }; + + apu_mdw_rpmsg { + compatible = "mediatek,apu-mdw-rpmsg"; + mtk,rpmsg-name = "apu-mdw-rpmsg"; + }; + }; + apu_conn: apu_conn@19020000 { compatible = "mediatek,mt8192-apu-conn", "syscon"; reg = <0 0x19020000 0 0x1000>; From patchwork Sat Oct 23 11:14:09 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Flora Fu X-Patchwork-Id: 12579575 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.99]) by smtp.lore.kernel.org (Postfix) with ESMTP id 22FFEC433F5 for ; Sat, 23 Oct 2021 11:27:11 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id D404B60231 for ; Sat, 23 Oct 2021 11:27:10 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.4.1 mail.kernel.org D404B60231 Authentication-Results: mail.kernel.org; dmarc=fail (p=none dis=none) header.from=mediatek.com Authentication-Results: mail.kernel.org; spf=none smtp.mailfrom=lists.infradead.org DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:CC:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=CBjC+l96uGWjwDW65VElVPdRywEg+NnXZ50fj49Bl9k=; b=gcXKVU6ThFGooV aOwgJMjlpnfNMrlWa0geqAL4rwyVlCmIJBS+B8AJFGKLoKILRzWU/ydY663TEX8rLXLB8UedvapJx S8gNP0o5D2NQgBpiezVHCL+LYIT4U3st+lmXrge6uMGvPpcCiUp0ngBz6bpo26BbuA40UsAAxNfw7 +TMHHcvJQJ9TYRC6ut65xctsn2f2CSIJKzSW8P8VqLlbRGOOMu0UWWt1ybaRmjttSsRv3F3t9q6kj 4dcCc/VGd4fsWLorYB1GzrDp5w58iGL+MfQqMI6x3yb07OSPCTqZzmzwlBgnZB5z4pNT8w7rCw8dJ oFMbIYw35lpQEqpLsjfQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9p-00CgYz-Tk; Sat, 23 Oct 2021 11:25:50 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.94.2 #2 (Red Hat Linux)) id 1meF9F-00CgNV-BR; Sat, 23 Oct 2021 11:25:14 +0000 X-UUID: 895770bb8e4c412796522e0f7e4706c8-20211023 X-UUID: 895770bb8e4c412796522e0f7e4706c8-20211023 Received: from mtkcas66.mediatek.inc [(172.29.193.44)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-SHA384 256/256) with ESMTP id 597983860; Sat, 23 Oct 2021 04:25:03 -0700 Received: from mtkexhb01.mediatek.inc (172.21.101.102) by MTKMBS62DR.mediatek.inc (172.29.94.18) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 04:15:03 -0700 Received: from mtkcas10.mediatek.inc (172.21.101.39) by mtkexhb01.mediatek.inc (172.21.101.102) with Microsoft SMTP Server (TLS) id 15.0.1497.2; Sat, 23 Oct 2021 19:15:02 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkcas10.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.0.1497.2 via Frontend Transport; Sat, 23 Oct 2021 19:15:02 +0800 From: Flora Fu To: Matthias Brugger , Mark Brown , Sumit Semwal CC: , , , , , , Flora Fu , Yong Wu , Pi-Cheng Chen Subject: [RFC 13/13] arm64: dts: mt8192: Add regulator for APU Date: Sat, 23 Oct 2021 19:14:09 +0800 Message-ID: <20211023111409.30463-14-flora.fu@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20211023111409.30463-1-flora.fu@mediatek.com> References: <20211023111409.30463-1-flora.fu@mediatek.com> MIME-Version: 1.0 X-MTK: N X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20211023_042513_444230_8CAAAFA1 X-CRM114-Status: UNSURE ( 9.42 ) X-CRM114-Notice: Please train this message. X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+linux-arm-kernel=archiver.kernel.org@lists.infradead.org Add regulator for mt8192 evb board. Signed-off-by: Flora Fu --- arch/arm64/boot/dts/mediatek/mt8192-evb.dts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/arch/arm64/boot/dts/mediatek/mt8192-evb.dts b/arch/arm64/boot/dts/mediatek/mt8192-evb.dts index 5d9e108e41f5..431008466d77 100644 --- a/arch/arm64/boot/dts/mediatek/mt8192-evb.dts +++ b/arch/arm64/boot/dts/mediatek/mt8192-evb.dts @@ -35,3 +35,8 @@ domain-supply = <&mt6359_vproc1_buck_reg>; }; }; + +&apusys_power { + vvpu-supply = <&mt6359_vproc1_buck_reg>; + vmdla-supply = <&mt6359_vproc2_buck_reg>; +};