From patchwork Wed Oct 9 11:15:42 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shu-hsiang Yang X-Patchwork-Id: 13828300 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 411B2CEDD90 for ; Wed, 9 Oct 2024 12:31:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=dfQNQQCo8K9+DzWkjIEJye5NdvsRl2yQMCwuZNkZaYk=; b=cdiwqAU9Uzgt/RmguqQeRjW7pL sxiQIBg2YoAhRhwRnelbbWLHkg/Ervk/RIgzo7sUNiTkggOKWVIt2nrTmhd8yYOvLd3utB15X5cYA IDzOlXhsh1tC9hNszzVj7B/ZwJbY+gaQqUmo0l4Cl4Gs+BvI6dqYRFLqe1rH41YqMDC5Fqlpf3FEy h99zkFcOYC0i9MJmfnSHAuC1Ysu9E3thpdNLrIPQ55Z0YnlzCuMmrGScZwafTKdUg1af0cyzXJ/Ly XszyoKSrdWZeoWADNQkEt6A44hxpn902LlTRASo3tG9Z32Hdcdl63ZkTTQuME/dmJHKb8qbGHaguW 8TMOmvmg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syVq5-00000009DOi-2z8W; Wed, 09 Oct 2024 12:30:49 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUfu-000000091FD-2w3R; Wed, 09 Oct 2024 11:16:16 +0000 X-UUID: e0e51c8a862f11efba0aef63c0775dbf-20241009 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=dfQNQQCo8K9+DzWkjIEJye5NdvsRl2yQMCwuZNkZaYk=; b=SPRB2oQTBNtk9itpCoovZzDifsfpW2gcXjRwtJKlWwnO6gYvYt/Df6j1+edbQAHjZFRFpCzYul4fBNe3kydNS4G6tuwDWOJMArF/Dm4tczbRUuT942Fcpy9XYeG0BhF1MlrcWa4YzPjju8WFnpe5H4tHUJ1v1Mve6LE8wO8eMAM=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:7307378d-44fc-43fd-b6bf-94d3276f789b,IP:0,U RL:25,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION :release,TS:25 X-CID-META: VersionHash:6dc6a47,CLOUDID:078a0041-8751-41b2-98dd-475503d45150,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:11|1,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES :1,SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR,TF_CID_SPAM_ULN X-UUID: e0e51c8a862f11efba0aef63c0775dbf-20241009 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1113697884; Wed, 09 Oct 2024 04:16:06 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Wed, 9 Oct 2024 04:16:03 -0700 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Wed, 9 Oct 2024 19:16:03 +0800 From: Shu-hsiang Yang To: Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Sumit Semwal , Christian Konig CC: , , , , , , , , , , , , , Shu-hsiang Yang Subject: [PATCH v1 01/10] dt-bindings: media: mediatek: add camsys device Date: Wed, 9 Oct 2024 19:15:42 +0800 Message-ID: <20241009111551.27052-2-Shu-hsiang.Yang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> References: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_041614_798601_0D3B9C99 X-CRM114-Status: GOOD ( 14.67 ) 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 1. Add camera isp7x module device document 2. Add camera interface device document Signed-off-by: Shu-hsiang Yang --- .../media/mediatek/mediatek,cam-raw.yaml | 169 ++++++++++++++++++ .../media/mediatek/mediatek,cam-yuv.yaml | 148 +++++++++++++++ .../media/mediatek/mediatek,camisp.yaml | 71 ++++++++ .../media/mediatek/mediatek,seninf-core.yaml | 106 +++++++++++ .../media/mediatek/mediatek,seninf.yaml | 88 +++++++++ 5 files changed, 582 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/mediatek/mediatek,cam-raw.yaml create mode 100644 Documentation/devicetree/bindings/media/mediatek/mediatek,cam-yuv.yaml create mode 100644 Documentation/devicetree/bindings/media/mediatek/mediatek,camisp.yaml create mode 100644 Documentation/devicetree/bindings/media/mediatek/mediatek,seninf-core.yaml create mode 100644 Documentation/devicetree/bindings/media/mediatek/mediatek,seninf.yaml diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-raw.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-raw.yaml new file mode 100644 index 000000000000..c709e4bf0a18 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-raw.yaml @@ -0,0 +1,169 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 MediaTek Inc. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-raw.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The cam-raw unit of MediaTek ISP system + +maintainers: + - Shu-hsiang Yang + - Shun-yi Wang + - Teddy Chen + +description: + MediaTek cam-raw is the camera RAW processing unit in MediaTek SoC. + +properties: + compatible: + const: mediatek,cam-raw + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + reg: + items: + minItems: 2 + maxItems: 4 + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + maxItems: 2 + + mediatek,cam-id: + description: + Describes the index of MediaTek cam-raw unit for ISP + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + mediatek,larbs: + description: + Describes MediaTek bus infrastructure unit for ISP system. + List of phandle to the local arbiters in the current SoCs. + Refer to bindings/memory-controllers/mediatek,smi-larb.yaml. + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + maxItems: 32 + + interrupts: + minItems: 1 + + dma-ranges: + description: + Describes the address information of IOMMU mapping to memory. + Defines six fields for the MediaTek IOMMU extended iova, pa, and size. + minItems: 1 + + power-domains: + minItems: 1 + + clocks: + minItems: 4 + maxItems: 16 + + clock-names: + minItems: 4 + maxItems: 16 + + assigned-clocks: + maxItems: 1 + + assigned-clock-parents: + maxItems: 1 + + iommus: + description: + Points to the respective IOMMU block with master port as argument, see + Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. + Ports are according to the HW. + minItems: 1 + maxItems: 32 + +required: + - compatible + - reg + - reg-names + - interrupts + - power-domains + - clocks + - clock-names + - iommus + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + cam_raw_a@16030000 { + compatible = "mediatek,cam-raw"; + reg = <0 0x16030000 0 0x8000>, + <0 0x16038000 0 0x8000>; + reg-names = "base", "inner_base"; + mediatek,cam-id = <0>; + mediatek,larbs = <&larb16a>; + interrupts = ; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0x2 0x0 0x0 0x40000000 0x1 0x0>; + power-domains = <&spm MT8188_POWER_DOMAIN_CAM_SUBA>; + clocks = <&camsys CLK_CAM_MAIN_CAM2MM0_GALS>, + <&camsys CLK_CAM_MAIN_CAM2MM1_GALS>, + <&camsys CLK_CAM_MAIN_CAM2SYS_GALS>, + <&camsys CLK_CAM_MAIN_CAM>, + <&camsys CLK_CAM_MAIN_CAMTG>, + <&camsys_rawa CLK_CAM_RAWA_LARBX>, + <&camsys_rawa CLK_CAM_RAWA_CAM>, + <&camsys_rawa CLK_CAM_RAWA_CAMTG>, + <&topckgen CLK_TOP_CAM>, + <&topckgen CLK_TOP_CAMTG>, + <&topckgen CLK_TOP_CAMTM>; + clock-names = "camsys_cam2mm0_cgpdn", + "camsys_cam2mm1_cgpdn", + "camsys_cam2sys_cgpdn", + "camsys_cam_cgpdn", + "camsys_camtg_cgpdn", + "camsys_rawa_larbx_cgpdn", + "camsys_rawa_cam_cgpdn", + "camsys_rawa_camtg_cgpdn", + "topckgen_top_cam", + "topckgen_top_camtg", + "topckgen_top_camtm"; + assigned-clocks = <&topckgen CLK_TOP_CAM>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5>; + iommus = <&vpp_iommu M4U_PORT_L16A_IMGO_R1>, + <&vpp_iommu M4U_PORT_L16A_CQI_R1>, + <&vpp_iommu M4U_PORT_L16A_CQI_R2>, + <&vpp_iommu M4U_PORT_L16A_BPCI_R1>, + <&vpp_iommu M4U_PORT_L16A_LSCI_R1>, + <&vpp_iommu M4U_PORT_L16A_RAWI_R2>, + <&vpp_iommu M4U_PORT_L16A_RAWI_R3>, + <&vpp_iommu M4U_PORT_L16A_UFDI_R2>, + <&vpp_iommu M4U_PORT_L16A_UFDI_R3>, + <&vpp_iommu M4U_PORT_L16A_RAWI_R4>, + <&vpp_iommu M4U_PORT_L16A_RAWI_R5>, + <&vpp_iommu M4U_PORT_L16A_AAI_R1>, + <&vpp_iommu M4U_PORT_L16A_UFDI_R5>, + <&vpp_iommu M4U_PORT_L16A_FHO_R1>, + <&vpp_iommu M4U_PORT_L16A_AAO_R1>, + <&vpp_iommu M4U_PORT_L16A_TSFSO_R1>, + <&vpp_iommu M4U_PORT_L16A_FLKO_R1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-yuv.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-yuv.yaml new file mode 100644 index 000000000000..30dfd5e5ecb1 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,cam-yuv.yaml @@ -0,0 +1,148 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 MediaTek Inc. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek/mediatek,cam-yuv.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The cam-yuv unit of MediaTek ISP system + +maintainers: + - Shu-hsiang Yang + - Shun-yi Wang + - Teddy Chen + +description: + MediaTek cam-yuv is the camera YUV processing unit in MediaTek SoC. + +properties: + compatible: + const: mediatek,cam-yuv + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + reg: + items: + minItems: 2 + maxItems: 4 + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 1 + maxItems: 2 + + mediatek,cam-id: + description: + Describes the index of MediaTek cam-yuv unit for ISP + $ref: /schemas/types.yaml#/definitions/uint32 + enum: [0, 1, 2] + + mediatek,larbs: + description: + Describes MediaTek bus infrastructure unit for ISP system. + List of phandle to the local arbiters in the current SoCs. + Refer to bindings/memory-controllers/mediatek,smi-larb.yaml. + $ref: /schemas/types.yaml#/definitions/phandle-array + minItems: 1 + maxItems: 32 + + interrupts: + minItems: 1 + + dma-ranges: + description: + Describes the address information of IOMMU mapping to memory. + Defines six fields for the MediaTek IOMMU extended iova, pa, and size. + minItems: 1 + + power-domains: + minItems: 1 + + clocks: + minItems: 4 + maxItems: 16 + + clock-names: + minItems: 4 + maxItems: 16 + + assigned-clocks: + maxItems: 1 + + assigned-clock-parents: + maxItems: 1 + + iommus: + description: + Points to the respective IOMMU block with master port as argument, see + Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details. + Ports are according to the HW. + minItems: 1 + maxItems: 32 + +required: + - compatible + - reg + - reg-names + - interrupts + - power-domains + - clocks + - clock-names + - iommus + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + cam_yuv_b@16090000 { + compatible = "mediatek,cam-yuv"; + reg = <0 0x16090000 0 0x8000>; + reg-names = "base"; + mediatek,cam-id = <1>; + mediatek,larbs = <&larb17b>; + interrupts = ; + #address-cells = <2>; + #size-cells = <2>; + dma-ranges = <0x2 0x0 0x0 0x40000000 0x1 0x0>; + power-domains = <&spm MT8188_POWER_DOMAIN_CAM_SUBB>; + clocks = <&camsys CLK_CAM_MAIN_CAM2MM0_GALS>, + <&camsys CLK_CAM_MAIN_CAM2MM1_GALS>, + <&camsys CLK_CAM_MAIN_CAM2SYS_GALS>, + <&camsys_yuvb CLK_CAM_YUVB_LARBX>, + <&camsys_yuvb CLK_CAM_YUVB_CAM>, + <&camsys_yuvb CLK_CAM_YUVB_CAMTG>; + clock-names = "camsys_cam2mm0_cgpdn", + "camsys_cam2mm1_cgpdn", + "camsys_cam2sys_cgpdn", + "camsys_yuvb_larbx_cgpdn", + "camsys_yuvb_cam_cgpdn", + "camsys_yuvb_camtg_cgpdn"; + assigned-clocks = <&topckgen CLK_TOP_CAM>; + assigned-clock-parents = <&topckgen CLK_TOP_UNIVPLL_D5>; + iommus = <&vdo_iommu M4U_PORT_L17B_YUVO_R1>, + <&vdo_iommu M4U_PORT_L17B_YUVO_R3>, + <&vdo_iommu M4U_PORT_L17B_YUVCO_R1>, + <&vdo_iommu M4U_PORT_L17B_YUVO_R2>, + <&vdo_iommu M4U_PORT_L17B_RZH1N2TO_R1>, + <&vdo_iommu M4U_PORT_L17B_DRZS4NO_R1>, + <&vdo_iommu M4U_PORT_L17B_TNCSO_R1>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,camisp.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,camisp.yaml new file mode 100644 index 000000000000..ce378ddbd5bd --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,camisp.yaml @@ -0,0 +1,71 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 MediaTek Inc. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek/mediatek,camisp.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The camisp unit of MediaTek ISP system + +maintainers: + - Shu-hsiang Yang + - Shun-yi Wang + - Teddy Chen + +description: + MediaTek camisp is the ISP auxiliary unit for camera system in MediaTek SoC. + +properties: + compatible: + const: mediatek,camisp + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + reg: + items: + minItems: 2 + maxItems: 4 + minItems: 1 + maxItems: 2 + + reg-names: + maxItems: 1 + + power-domains: + maxItems: 1 + + mediatek,scp: + description: MediaTek co-process unit for ISP system + $ref: /schemas/types.yaml#/definitions/phandle + +required: + - compatible + - reg + - reg-names + - power-domains + +additionalProperties: false + +examples: + - | + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + camisp: camisp@16000000 { + compatible = "mediatek,camisp"; + reg = <0 0x16000000 0 0x1000>; + reg-names = "base"; + mediatek,scp = <&scp_dual>; + power-domains = <&spm MT8188_POWER_DOMAIN_CAM_MAIN>; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf-core.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf-core.yaml new file mode 100644 index 000000000000..bc509976a79e --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf-core.yaml @@ -0,0 +1,106 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 MediaTek Inc. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek/mediatek,seninf-core.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The seninf-core top unit of MediaTek ISP system + +maintainers: + - Shu-hsiang Yang + - Shun-yi Wang + - Teddy Chen + +description: + MediaTek seninf-core is the ISP sensor interface unit in MediaTek SoC. + The sensor interface serves as the MIPI-CSI2 top RX controller. + +properties: + compatible: + const: mediatek,seninf-core + + "#address-cells": + const: 2 + + "#size-cells": + const: 2 + + reg: + items: + minItems: 2 + maxItems: 4 + minItems: 1 + maxItems: 2 + + reg-names: + minItems: 2 + maxItems: 2 + + mtk_csi_phy_ver: + description: + Describes MediaTek camera Rx controller version + $ref: /schemas/types.yaml#/definitions/string + maxItems: 1 + + interrupts: + minItems: 1 + maxItems: 2 + + power-domains: + minItems: 1 + maxItems: 4 + + clocks: + minItems: 3 + maxItems: 8 + + clock-names: + minItems: 3 + maxItems: 8 + +required: + - compatible + - reg + - reg-names + - interrupts + - power-domains + - clocks + - clock-names + +additionalProperties: false + +examples: + - | + #include + #include + #include + #include + + soc { + #address-cells = <2>; + #size-cells = <2>; + + seninf_top: seninf_top@16010000 { + compatible = "mediatek,seninf-core"; + reg = <0 0x16010000 0 0x8000>, + <0 0x11ed0000 0 0xc000>; + reg-names = "base", "ana-rx"; + mtk_csi_phy_ver = "mtk_csi_phy_2_0"; + interrupts = ; + power-domains = <&spm MT8188_POWER_DOMAIN_CSIRX_TOP>, + <&spm MT8188_POWER_DOMAIN_CAM_VCORE>, + <&spm MT8188_POWER_DOMAIN_CAM_MAIN>; + clocks = <&camsys CLK_CAM_MAIN_SENINF>, + <&topckgen CLK_TOP_SENINF>, + <&topckgen CLK_TOP_SENINF1>, + <&topckgen CLK_TOP_CAMTM>; + clock-names = "clk_cam_seninf", + "clk_top_seninf", + "clk_top_seninf1", + "clk_top_camtm"; + }; + }; + +... diff --git a/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf.yaml b/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf.yaml new file mode 100644 index 000000000000..37d94138c558 --- /dev/null +++ b/Documentation/devicetree/bindings/media/mediatek/mediatek,seninf.yaml @@ -0,0 +1,88 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +# Copyright (c) 2024 MediaTek Inc. + +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/mediatek/mediatek,seninf.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: The seninf unit of MediaTek ISP system + +maintainers: + - Shu-hsiang Yang + - Shun-yi Wang + - Teddy Chen + +description: + MediaTek seninf is the MIPI-CSI2 port for seninf-core in MediaTek SoC. + These ports provide the optional capability to define endpoints and set RX + controller for camera sensors. + +properties: + compatible: + const: mediatek,seninf + + csi-port: + description: MediaTek CSI Rx port name + $ref: /schemas/types.yaml#/definitions/string + + port: + description: + MediaTek sensor interface endpoints for one sensor bus. + $ref: /schemas/graph.yaml#/$defs/port-base + + properties: + "#address-cells": + const: 1 + "#size-cells": + const: 0 + + patternProperties: + "^endpoint(@[0-9]+)?$": + description: + CSI port for one sensor endpoint configuration. + Consider one sensor bus can support differet links for MIPI PHY. + $ref: /schemas/media/video-interfaces.yaml# + unevaluatedProperties: false + properties: + data-lanes: + items: + enum: [1, 2, 3, 4] + maxItems: 4 + + additionalProperties: false + +required: + - compatible + - csi-port + - port + +additionalProperties: false + +examples: + - | + seninf_top { + seninf_csi_port_0: seninf_csi_port_0 { + compatible = "mediatek,seninf"; + csi-port = "0A"; + port { + #address-cells = <1>; + #size-cells = <0>; + + seninf_csi_port_0_in_1: endpoint { + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <1440000000 624000000>; + remote-endpoint = <&sensor0_out_1>; + }; + + seninf_csi_port_0_in_2: endpoint@2 { + reg = <2>; + data-lanes = <1 2>; + link-frequencies = /bits/ 64 <336000000 207000000>; + remote-endpoint = <&sensor0_out_2>; + }; + }; + }; + }; + +... From patchwork Wed Oct 9 11:15:44 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shu-hsiang Yang X-Patchwork-Id: 13828190 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 2FBB1CF0453 for ; Wed, 9 Oct 2024 11:20:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=Q2xOGc+RtjzNrItvs3HvwzWSO0frevMjWR7p4Vj7aUk=; b=eQ59AYCO/vjXML5oeWSsZzlHoc mzZhZPdVSwBhk50hoamB4dPL31LXrdZyA+D2/xRwBod1oTU8qYGroC3lTyfTOKgfXq2eCsqzT4s99 HQtlMQGg+NGb6XEHqXefl0jDFW3kEmJa5+bs58/VxzuLMSDcMO85yRlW434+XlxHLQr7R/XUUqzyX ZdW2qLXsRuH3prRiHfrGs0o0JQcxqt/MXVuRZ1QWOHvoe2vrl1HEvKaRQNISBPiZN3LDneazK4485 sXj1haNTd1bobGci51S33RcgCvlA8pUb9DIovsACNk7pk0ltWAvd0WQebm6arGgdK+D63g2iww505 e56h1kxg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUjr-000000091yg-2tQU; Wed, 09 Oct 2024 11:20:19 +0000 Received: from mailgw01.mediatek.com ([216.200.240.184]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUft-000000091FE-1nTH; Wed, 09 Oct 2024 11:16:18 +0000 X-UUID: e2e69270862f11efb3adad29d29602c1-20241009 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=Q2xOGc+RtjzNrItvs3HvwzWSO0frevMjWR7p4Vj7aUk=; b=f6s8XeHhAhkVAwKKRwTwTSzf+hv9cnXbuxDYCfRKQKCECatBmp2RxT/1LOs+Muu/wKRGBvMSJRuVeDJLwD9IFPwhyZS78WZgmyi/9LgTlWk5SGS8xzwTwgGQ4+64NkmgrVzxunnmkyMbyMN/IRh2cB3wjppemvINvNZyivBJtlY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:89156826-6c81-4573-a4b2-20e2afa224b8,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:6dc6a47,CLOUDID:20a58926-5902-4533-af4f-d0904aa89b3c,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:1,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,OSH|NGT X-CID-BAS: 2,OSH|NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e2e69270862f11efb3adad29d29602c1-20241009 Received: from mtkmbs13n1.mediatek.inc [(172.21.101.193)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1827698121; Wed, 09 Oct 2024 04:16:10 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by MTKMBS09N2.mediatek.inc (172.21.101.94) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Wed, 9 Oct 2024 04:16:07 -0700 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Wed, 9 Oct 2024 19:16:07 +0800 From: Shu-hsiang Yang To: Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Sumit Semwal , Christian Konig CC: , , , , , , , , , , , , , Shu-hsiang Yang Subject: [PATCH v1 03/10] media: platform: mediatek: add isp_7x seninf unit Date: Wed, 9 Oct 2024 19:15:44 +0800 Message-ID: <20241009111551.27052-4-Shu-hsiang.Yang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> References: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_041613_572888_D01DF711 X-CRM114-Status: GOOD ( 21.88 ) 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 Introduces the driver of the MediaTek Sensor Interface, focusing on integration with the MediaTek ISP CAMSYS. The seninf device bridges camera sensors and the ISP system, providing management for sensor data routing and processing. Key features include V4L2 framework control, and dynamic handling of stream configurations and virtual channels. Signed-off-by: Shu-hsiang Yang --- .../isp_7x/camsys/kd_imgsensor_define_v4l2.h | 87 + .../isp/isp_7x/camsys/mtk_cam-seninf-def.h | 193 ++ .../isp/isp_7x/camsys/mtk_cam-seninf-drv.c | 1741 +++++++++++++++++ .../isp/isp_7x/camsys/mtk_cam-seninf-drv.h | 16 + .../isp/isp_7x/camsys/mtk_cam-seninf-hw.h | 120 ++ .../isp/isp_7x/camsys/mtk_cam-seninf-if.h | 28 + .../isp/isp_7x/camsys/mtk_cam-seninf-regs.h | 40 + .../isp/isp_7x/camsys/mtk_cam-seninf-route.c | 356 ++++ .../isp/isp_7x/camsys/mtk_cam-seninf-route.h | 23 + .../isp/isp_7x/camsys/mtk_cam-seninf.h | 170 ++ 10 files changed, 2774 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h new file mode 100644 index 000000000000..1684a79bbb84 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/kd_imgsensor_define_v4l2.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2019 MediaTek Inc. + */ + +#ifndef _KD_IMGSENSOR_DATA_V4L2_H +#define _KD_IMGSENSOR_DATA_V4L2_H + +enum VC_FEATURE { + VC_NONE = 0, + VC_MIN_NUM, + VC_RAW_DATA = VC_MIN_NUM, + VC_RAW_DATA_MAX, + + VC_PDAF_MIN_NUM = VC_RAW_DATA_MAX, + VC_PDAF_STATS = VC_PDAF_MIN_NUM, + VC_PDAF_STATS_NE, + VC_PDAF_STATS_ME, + VC_PDAF_STATS_SE, + VC_PDAF_STATS_PIX_1, + VC_PDAF_STATS_PIX_2, + VC_PDAF_STATS_NE_PIX_1 = VC_PDAF_STATS_PIX_1, + VC_PDAF_STATS_NE_PIX_2 = VC_PDAF_STATS_PIX_2, + VC_PDAF_STATS_ME_PIX_1, + VC_PDAF_STATS_ME_PIX_2, + VC_PDAF_STATS_SE_PIX_1, + VC_PDAF_STATS_SE_PIX_2, + VC_PDAF_MAX_NUM, + + VC_HDR_MIN_NUM = VC_PDAF_MAX_NUM, + VC_HDR_MVHDR = VC_HDR_MIN_NUM, + VC_HDR_MAX_NUM, + + VC_3HDR_MIN_NUM = VC_HDR_MAX_NUM, + VC_3HDR_EMBEDDED = VC_3HDR_MIN_NUM, + VC_3HDR_FLICKER, + VC_3HDR_Y, + VC_3HDR_AE, + VC_3HDR_MAX_NUM, + + VC_STAGGER_MIN_NUM = VC_3HDR_MAX_NUM, + VC_STAGGER_EMBEDDED = VC_STAGGER_MIN_NUM, + VC_STAGGER_NE, + VC_STAGGER_ME, + VC_STAGGER_SE, + VC_STAGGER_MAX_NUM, + + VC_YUV_MIN_NUM = VC_STAGGER_MAX_NUM, + VC_YUV_Y = VC_YUV_MIN_NUM, + VC_YUV_UV, + VC_YUV_MAX_NUM, + + VC_RAW_EXT_MIN_NUM = VC_YUV_MAX_NUM, + VC_RAW_W_DATA = VC_RAW_EXT_MIN_NUM, + VC_RAW_PROCESSED_DATA, + VC_RAW_EXT_MAX_NUM, + + VC_GENERAL_DATA_MIN_NUM = VC_RAW_EXT_MAX_NUM, + VC_GENERAL_EMBEDDED = VC_GENERAL_DATA_MIN_NUM, + VC_GENERAL_DATA_MAX_NUM, + + VC_MAX_NUM = VC_GENERAL_DATA_MAX_NUM, +}; + +enum { + PAD_SINK = 0, + PAD_SRC_RAW0, + PAD_SRC_RAW1, + PAD_SRC_RAW2, + PAD_SRC_RAW_W0, + PAD_SRC_RAW_EXT0, + PAD_SRC_PDAF0, + PAD_SRC_PDAF1, + PAD_SRC_PDAF2, + PAD_SRC_PDAF3, + PAD_SRC_PDAF4, + PAD_SRC_PDAF5, + PAD_SRC_PDAF6, + PAD_SRC_HDR0, + PAD_SRC_HDR1, + PAD_SRC_HDR2, + PAD_SRC_GENERAL0, + PAD_MAXCNT, + PAD_ERR = 0xffff, +}; + +#endif /* _KD_IMGSENSOR_DATA_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h new file mode 100644 index 000000000000..0bad8f307c10 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-def.h @@ -0,0 +1,193 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_DEF_H__ +#define __MTK_CAM_SENINF_DEF_H__ + +#define SENINF_VC_MAXCNT 8 +#define SENINF_DEF_PIXEL_MODE 2 + +#define SENINF_CLK_MARGIN_IN_PERCENT 0 +#define HW_BUF_EFFECT 10 + +#define SENINF_HS_TRAIL_EN_CONDITION 1450000000 +#define SENINF_TIMESTAMP_CLK 1000 +#define ISP_CLK_LOW 273000000 + +#define SENINF_CPHY_SETTLE_DELAY_DT 0x10 +#define SENINF_DPHY_SETTLE_DELAY_DT 0x10 +#define SENINF_SETTLE_DELAY_CK 0x11 +#define SENINF_HS_TRAIL_PARAMETER 0x34 + +#define SENSOR_CLOCK_POLARITY_HIGH 0 +#define SENSOR_CLOCK_POLARITY_LOW 1 +#define NUM_PORTS 2 +#define DEFAULT_WIDTH 1600 +#define DEFAULT_HEIGHT 1200 + +enum CSI_PORT { + CSI_PORT_0 = 0, + CSI_PORT_1, + CSI_PORT_2, + CSI_PORT_3, + CSI_PORT_4, + CSI_PORT_5, + CSI_PORT_0A, + CSI_PORT_0B, + CSI_PORT_1A, + CSI_PORT_1B, + CSI_PORT_2A, + CSI_PORT_2B, + CSI_PORT_3A, + CSI_PORT_3B, + CSI_PORT_4A, + CSI_PORT_4B, + CSI_PORT_5A, + CSI_PORT_5B, + CSI_PORT_MAX_NUM, +}; + +#define SENINF_CSI_PORT_NAMES \ + "0", \ + "1", \ + "2", \ + "3", \ + "4", \ + "5", \ + "0A", \ + "0B", \ + "1A", \ + "1B", \ + "2A", \ + "2B", \ + "3A", \ + "3B", \ + "4A", \ + "4B", \ + "5A", \ + "5B", \ + +enum SENINF_PHY_VER_ENUM { + SENINF_PHY_2_0, + SENINF_PHY_VER_NUM, +}; + +#define MTK_CSI_PHY_VERSIONS "mtk_csi_phy_2_0" + +enum SENINF_ENUM { + SENINF_1, + SENINF_2, + SENINF_3, + SENINF_4, + SENINF_5, + SENINF_6, + SENINF_7, + SENINF_8, + SENINF_9, + SENINF_10, + SENINF_11, + SENINF_12, + SENINF_NUM, +}; + +enum SENINF_MUX_ENUM { + SENINF_MUX1, + SENINF_MUX2, + SENINF_MUX3, + SENINF_MUX4, + SENINF_MUX5, + SENINF_MUX6, + SENINF_MUX7, + SENINF_MUX8, + SENINF_MUX9, + SENINF_MUX10, + SENINF_MUX11, + SENINF_MUX12, + SENINF_MUX13, + SENINF_MUX_NUM, + SENINF_MUX_ERROR = -1, +}; + +enum SENINF_CAM_MUX_ENUM { + SENINF_CAM_MUX0, + SENINF_CAM_MUX1, + SENINF_CAM_MUX2, + SENINF_CAM_MUX3, + SENINF_CAM_MUX4, + SENINF_CAM_MUX5, + SENINF_CAM_MUX6, + SENINF_CAM_MUX7, + SENINF_CAM_MUX8, + SENINF_CAM_MUX9, + SENINF_CAM_MUX10, + SENINF_CAM_MUX11, + SENINF_CAM_MUX12, + SENINF_CAM_MUX13, + SENINF_CAM_MUX14, + SENINF_CAM_MUX15, + SENINF_CAM_MUX_NUM, + SENINF_CAM_MUX_ERR = 0xff +}; + +/* 0:CSI2(2.5G), 3: parallel, 8:NCSI2(1.5G) */ +enum SENINF_SOURCE_ENUM { + CSI2 = 0x0, + TEST_MODEL = 0x1, + CCIR656 = 0x2, + PARALLEL_SENSOR = 0x3, + SERIAL_SENSOR = 0x4, + HD_TV = 0x5, + EXT_CSI2_OUT1 = 0x6, + EXT_CSI2_OUT2 = 0x7, + MIPI_SENSOR = 0x8, + VIRTUAL_CHANNEL_1 = 0x9, + VIRTUAL_CHANNEL_2 = 0xA, + VIRTUAL_CHANNEL_3 = 0xB, + VIRTUAL_CHANNEL_4 = 0xC, + VIRTUAL_CHANNEL_5 = 0xD, + VIRTUAL_CHANNEL_6 = 0xE, +}; + +enum SENINF_CSI2_ENUM { + CSI2_1_5G = 0x0, + CSI2_2_5G = 0x1, + CSI2_2_5G_CPHY = 0x2, +}; + +enum TG_FORMAT_ENUM { + FMT_RAW_8BIT = 0x0, + FMT_RAW_10BIT = 0x1, + FMT_RAW_12BIT = 0x2, + FMT_YUV422 = 0x3, + FMT_RAW_14BIT = 0x4, + FMT_RGB565_MIPI = 0x5, + FMT_RGB888_MIPI = 0x6, + FMT_JPEG = 0x7 +}; + +enum { + CLK_CAM_SENINF = 0, + CLK_TOP_SENINF, + CLK_TOP_SENINF1, + CLK_TOP_SENINF2, + CLK_TOP_SENINF3, + CLK_TOP_SENINF4, + CLK_TOP_SENINF5, + CLK_TOP_SENINF_END, + CLK_TOP_CAMTM = CLK_TOP_SENINF_END, + CLK_MAXCNT, +}; + +#define SENINF_CLK_NAMES \ + "clk_cam_seninf", \ + "clk_top_seninf", \ + "clk_top_seninf1", \ + "clk_top_seninf2", \ + "clk_top_seninf3", \ + "clk_top_seninf4", \ + "clk_top_seninf5", \ + "clk_top_camtm", \ + +#endif /* __MTK_CAM_SENINF_DEF_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c new file mode 100644 index 000000000000..a8fb48070304 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.c @@ -0,0 +1,1741 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022 MediaTek Inc. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_cam.h" +#include "mtk_cam-seninf-def.h" +#include "mtk_cam-seninf.h" +#include "mtk_cam-seninf-hw.h" +#include "mtk_cam-seninf-route.h" +#include "kd_imgsensor_define_v4l2.h" + +#define sd_to_ctx(__sd) container_of(__sd, struct seninf_ctx, subdev) +#define notifier_to_ctx(__n) container_of(__n, struct seninf_ctx, notifier) +#define ctrl_hdl_to_ctx(__h) container_of(__h, struct seninf_ctx, ctrl_handler) + +static const char * const csi_port_names[] = { + SENINF_CSI_PORT_NAMES +}; + +static const char * const clk_names[] = { + SENINF_CLK_NAMES +}; + +static const char * const set_reg_names[] = { + SET_REG_KEYS_NAMES +}; + +static ssize_t status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mtk_cam_seninf_show_status(dev, attr, buf); +} + +static DEVICE_ATTR_RO(status); + +static ssize_t err_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return mtk_cam_seninf_show_err_status(dev, attr, buf); +} + +static DEVICE_ATTR_RO(err_status); + +static ssize_t debug_ops_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int len = 0; + + len += snprintf(buf + len, PAGE_SIZE - len, "This is debug ops message\n"); + + return len; +} + +enum REG_OPS_CMD { + REG_OPS_CMD_ID, + REG_OPS_CMD_CSI, + REG_OPS_CMD_RG, + REG_OPS_CMD_VAL, + REG_OPS_CMD_MAX_NUM, +}; + +static ssize_t debug_ops_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char delim[] = " "; + char csi_names[20]; + char *token = NULL; + char *sbuf = kcalloc(count + 1, sizeof(char), GFP_KERNEL); + char *s = sbuf; + int ret; + char *arg[REG_OPS_CMD_MAX_NUM]; + struct seninf_core *core = dev_get_drvdata(dev); + struct seninf_ctx *ctx; + int csi_port = -1; + int rg_idx = -1; + u32 val, i, num_para = 0; + + if (!sbuf) + goto ERR_DEBUG_OPS_STORE; + + memcpy(sbuf, buf, count); + + token = strsep(&s, delim); + while (token && num_para < REG_OPS_CMD_MAX_NUM) { + if (strlen(token)) { + arg[num_para] = token; + num_para++; + } + + token = strsep(&s, delim); + } + + if (num_para != REG_OPS_CMD_MAX_NUM) { + dev_info(dev, "Wrong command parameter number\n"); + goto ERR_DEBUG_OPS_STORE; + } + + if (strncmp("SET_REG", arg[REG_OPS_CMD_ID], sizeof("SET_REG")) == 0) { + for (i = 0; i < REG_KEY_MAX_NUM; i++) { + if (!strcasecmp(arg[REG_OPS_CMD_RG], set_reg_names[i])) + rg_idx = i; + } + if (rg_idx < 0) + goto ERR_DEBUG_OPS_STORE; + + ret = kstrtouint(arg[REG_OPS_CMD_VAL], 0, &val); + if (ret) + goto ERR_DEBUG_OPS_STORE; + + for (i = 0; i < CSI_PORT_MAX_NUM; i++) { + memset(csi_names, 0, ARRAY_SIZE(csi_names)); + snprintf(csi_names, 10, "csi-%s", csi_port_names[i]); + if (!strcasecmp(arg[REG_OPS_CMD_CSI], csi_names)) + csi_port = i; + } + + if (csi_port < 0) + goto ERR_DEBUG_OPS_STORE; + + /* reg call */ + mutex_lock(&core->mutex); + + list_for_each_entry(ctx, &core->list, list) { + if (csi_port == ctx->port) + mtk_cam_seninf_set_reg(ctx, rg_idx, val); + } + + mutex_unlock(&core->mutex); + } + +ERR_DEBUG_OPS_STORE: + + kfree(sbuf); + + return count; +} + +static DEVICE_ATTR_RW(debug_ops); + +static int seninf_core_pm_runtime_enable(struct seninf_core *core) +{ + int i, ret; + + core->pm_domain_cnt = of_count_phandle_with_args(core->dev->of_node, + "power-domains", + "#power-domain-cells"); + if (core->pm_domain_cnt == 1) { + pm_runtime_enable(core->dev); + } else if (core->pm_domain_cnt > 1) { + core->pm_domain_devs = + devm_kcalloc(core->dev, core->pm_domain_cnt, + sizeof(*core->pm_domain_devs), GFP_KERNEL); + + if (!core->pm_domain_devs) + return -ENOMEM; + + for (i = 0; i < core->pm_domain_cnt; i++) { + core->pm_domain_devs[i] = + dev_pm_domain_attach_by_id(core->dev, i); + + if (IS_ERR(core->pm_domain_devs[i])) { + ret = PTR_ERR(core->pm_domain_devs[i]); + + dev_info(core->dev, + "%s: fail to probe pm id: %d (%d)\n", + __func__, i, ret); + + goto detach_pm; + } + } + } + + return 0; + +detach_pm: + for (--i; i >= 0; i--) + dev_pm_domain_detach(core->pm_domain_devs[i], true); + + return ret; +} + +static int seninf_core_pm_runtime_disable(struct seninf_core *core) +{ + int i; + + if (core->pm_domain_cnt == 1) { + pm_runtime_disable(core->dev); + } else { + if (!core->pm_domain_devs) + return -EINVAL; + + for (i = 0; i < core->pm_domain_cnt; i++) { + if (core->pm_domain_devs[i]) + dev_pm_domain_detach(core->pm_domain_devs[i], 1); + } + } + + return 0; +} + +static int seninf_core_pm_runtime_get_sync(struct seninf_core *core) +{ + int ret, i; + + /* for one pm_domain */ + if (core->pm_domain_cnt == 1) { + ret = pm_runtime_resume_and_get(core->dev); + if (ret < 0) { + dev_info(core->dev, "fail to resume seninf_core\n"); + return ret; + } + + return 0; + } + + if (!core->pm_domain_devs) + return -EINVAL; + + /* more than one pm_domain */ + for (i = 0; i < core->pm_domain_cnt; i++) { + if (core->pm_domain_devs[i]) { + ret = pm_runtime_resume_and_get(core->pm_domain_devs[i]); + if (ret < 0) { + dev_info(core->dev, + "fail to resume pm_domain_devs(%d)\n", i); + return ret; + } + } + } + + return 0; +} + +static int seninf_core_pm_runtime_put(struct seninf_core *core) +{ + int i; + + if (core->pm_domain_cnt == 1) { + pm_runtime_put_sync(core->dev); + } else { + if (!core->pm_domain_devs || core->pm_domain_cnt < 1) + return -EINVAL; + + for (i = core->pm_domain_cnt - 1; i >= 0; i--) { + if (core->pm_domain_devs[i]) + pm_runtime_put_sync(core->pm_domain_devs[i]); + } + } + + return 0; +} + +static irqreturn_t mtk_irq_seninf(int irq, void *data) +{ + mtk_cam_seninf_irq_handler(irq, data); + return IRQ_HANDLED; +} + +static int get_seninf_cfg(struct device *dev, struct seninf_core *core) +{ + int ret; + const char *ver; + + ret = of_property_read_string(dev->of_node, "mtk_csi_phy_ver", &ver); + if (ret) { + dev_err(dev, + "Fail to get mtk_csi_phy_ver property (err=%d)\n", ret); + + return ret; + } + + if (!strcasecmp(ver, MTK_CSI_PHY_VERSIONS)) { + dev_info(dev, "%s: mtk_csi_phy_ver = %s\n", __func__, ver); + + of_property_read_u32(dev->of_node, "seninf_num", + &g_seninf_cfg->seninf_num); + of_property_read_u32(dev->of_node, "mux_num", + &g_seninf_cfg->mux_num); + of_property_read_u32(dev->of_node, "cam_mux_num", + &g_seninf_cfg->cam_mux_num); + of_property_read_u32(dev->of_node, "pref_mux_num", + &g_seninf_cfg->pref_mux_num); + + dev_info(dev, + "%s: seninf_num = %d, mux_num = %d, cam_mux_num = %d, pref_mux_num =%d\n", + __func__, + g_seninf_cfg->seninf_num, + g_seninf_cfg->mux_num, + g_seninf_cfg->cam_mux_num, + g_seninf_cfg->pref_mux_num); + + return 0; + } + + dev_err(dev, "DTS seninf config not correct.\n"); + + return -1; +} + +static int seninf_core_probe(struct platform_device *pdev) +{ + int i, ret, irq; + struct resource *res; + struct seninf_core *core; + struct device *dev = &pdev->dev; + + core = devm_kzalloc(&pdev->dev, sizeof(*core), GFP_KERNEL); + if (!core) + return -ENOMEM; + + dev_set_drvdata(dev, core); + core->dev = dev; + mutex_init(&core->mutex); + INIT_LIST_HEAD(&core->list); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base"); + core->reg_if = devm_ioremap_resource(dev, res); + if (IS_ERR(core->reg_if)) + return PTR_ERR(core->reg_if); + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ana-rx"); + core->reg_ana = devm_ioremap_resource(dev, res); + if (IS_ERR(core->reg_ana)) + return PTR_ERR(core->reg_ana); + + ret = get_seninf_cfg(dev, core); + if (ret) { + dev_err(dev, "failed to get seninf ops\n"); + return ret; + } + mtk_cam_seninf_init_res(core); + + spin_lock_init(&core->spinlock_irq); + irq = platform_get_irq(pdev, 0); + if (!irq) { + dev_err(dev, "failed to get irq\n"); + return -ENODEV; + } + + ret = devm_request_irq(dev, irq, mtk_irq_seninf, 0, + dev_name(dev), core); + if (ret) { + dev_err(dev, "failed to request irq=%d\n", irq); + return ret; + } + dev_dbg(dev, "registered irq=%d\n", irq); + + /* default platform properties */ + core->cphy_settle_delay_dt = SENINF_CPHY_SETTLE_DELAY_DT; + core->dphy_settle_delay_dt = SENINF_DPHY_SETTLE_DELAY_DT; + core->settle_delay_ck = SENINF_SETTLE_DELAY_CK; + core->hs_trail_parameter = SENINF_HS_TRAIL_PARAMETER; + + /* read platform properties from device tree */ + of_property_read_u32(dev->of_node, "cphy_settle_delay_dt", + &core->cphy_settle_delay_dt); + of_property_read_u32(dev->of_node, "dphy_settle_delay_dt", + &core->dphy_settle_delay_dt); + of_property_read_u32(dev->of_node, "settle_delay_ck", + &core->settle_delay_ck); + of_property_read_u32(dev->of_node, "hs_trail_parameter", + &core->hs_trail_parameter); + + core->dfs.cnt = 0; + core->dfs.reg = NULL; + + ret = seninf_core_pm_runtime_enable(core); + if (ret) { + dev_info(dev, "failed to enable seninf_core_pm_runtime\n"); + return ret; + } + + for (i = 0; i < CLK_MAXCNT; i++) { + core->clk[i] = devm_clk_get(dev, clk_names[i]); + if (IS_ERR(core->clk[i])) { + dev_info(dev, "failed to get %s\n", clk_names[i]); + core->clk[i] = NULL; + /* ignore not define seninf */ + } + } + + ret = of_platform_populate(dev->of_node, NULL, NULL, dev); + if (ret) { + dev_info(dev, "%s: failed to create sub devices\n", __func__); + return ret; + } + + ret = device_create_file(dev, &dev_attr_status); + if (ret) + dev_info(dev, "failed to create sysfs status\n"); + + ret = device_create_file(dev, &dev_attr_debug_ops); + if (ret) + dev_info(dev, "failed to create sysfs debug ops\n"); + + ret = device_create_file(dev, &dev_attr_err_status); + if (ret) + dev_info(dev, "failed to create sysfs status\n"); + + dev_dbg(dev, "camsys | start %s\n", __func__); + + return 0; +} + +static void seninf_core_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct seninf_core *core = dev_get_drvdata(dev); + + device_remove_file(dev, &dev_attr_status); + device_remove_file(dev, &dev_attr_debug_ops); + device_remove_file(dev, &dev_attr_err_status); + of_platform_depopulate(dev); + seninf_core_pm_runtime_disable(core); + + dev_dbg(dev, "camsys | start %s\n", __func__); +} + +static const struct of_device_id seninf_core_of_match[] = { + { .compatible = "mediatek,seninf-core" }, + {}, +}; +MODULE_DEVICE_TABLE(of, seninf_core_of_match); + +struct platform_driver seninf_core_pdrv = { + .probe = seninf_core_probe, + .remove = seninf_core_remove, + .driver = { + .name = "seninf-core", + .of_match_table = seninf_core_of_match, + }, +}; + +static int get_csi_port(struct device *dev, int *port) +{ + int i, ret; + const char *name; + + ret = of_property_read_string(dev->of_node, "csi-port", &name); + if (ret) + return ret; + + for (i = 0; i < CSI_PORT_MAX_NUM; i++) { + if (!strcasecmp(name, csi_port_names[i])) { + *port = i; + return 0; + } + } + + return -1; +} + +static int seninf_subscribe_event(struct v4l2_subdev *sd, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_CTRL: + return v4l2_ctrl_subdev_subscribe_event(sd, fh, sub); + default: + return -EINVAL; + } +} + +static void init_fmt(struct seninf_ctx *ctx) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(ctx->fmt); i++) { + ctx->fmt[i].format.code = MEDIA_BUS_FMT_SBGGR10_1X10; + ctx->fmt[i].format.width = DEFAULT_WIDTH; + ctx->fmt[i].format.height = DEFAULT_HEIGHT; + ctx->fmt[i].format.field = V4L2_FIELD_NONE; + ctx->fmt[i].format.colorspace = V4L2_COLORSPACE_SRGB; + ctx->fmt[i].format.xfer_func = V4L2_XFER_FUNC_DEFAULT; + ctx->fmt[i].format.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + ctx->fmt[i].format.quantization = V4L2_QUANTIZATION_DEFAULT; + } + + for (i = 0; i < ARRAY_SIZE(ctx->vcinfo.vc); i++) + ctx->vcinfo.vc[i].pixel_mode = SENINF_DEF_PIXEL_MODE; +} + +static int dev_read_csi_efuse(struct seninf_ctx *ctx) +{ + struct nvmem_cell *cell; + size_t len = 0; + u32 *buf; + + ctx->m_csi_efuse = 0x00000000; + + cell = nvmem_cell_get(ctx->dev, "rg_csi"); + dev_info(ctx->dev, "ctx->port = %d\n", ctx->port); + if (IS_ERR(cell)) { + if (PTR_ERR(cell) == -EPROBE_DEFER) { + dev_info(ctx->dev, + "read csi efuse returned with error cell %d\n", + -EPROBE_DEFER - EPROBE_DEFER); + return PTR_ERR(cell); + } + dev_info(ctx->dev, + "read csi efuse returned with error cell %d\n", -1); + return -1; + } + buf = (u32 *)nvmem_cell_read(cell, &len); + nvmem_cell_put(cell); + if (IS_ERR(buf)) { + dev_info(ctx->dev, "read csi efuse returned with error buf\n"); + return PTR_ERR(buf); + } + ctx->m_csi_efuse = *buf; + kfree(buf); + dev_info(ctx->dev, "Efuse Data: 0x%08x\n", ctx->m_csi_efuse); + + return 0; +} + +static const struct v4l2_mbus_framefmt fmt_default = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + .width = DEFAULT_WIDTH, + .height = DEFAULT_HEIGHT, + .field = V4L2_FIELD_NONE, + .colorspace = V4L2_COLORSPACE_SRGB, + .xfer_func = V4L2_XFER_FUNC_DEFAULT, + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, + .quantization = V4L2_QUANTIZATION_DEFAULT, +}; + +static int mtk_cam_seninf_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_mbus_framefmt *mf; + unsigned int i; + + for (i = 0; i < sd->entity.num_pads; i++) { + mf = v4l2_subdev_state_get_format(sd_state, i); + *mf = fmt_default; + } + + return 0; +} + +static int mtk_cam_seninf_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct seninf_ctx *ctx = sd_to_ctx(sd); + struct v4l2_mbus_framefmt *format; + char sink_format_changed = 0; + + if (fmt->pad < PAD_SINK || fmt->pad >= PAD_MAXCNT) + return -EINVAL; + + format = &ctx->fmt[fmt->pad].format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + *v4l2_subdev_state_get_format(sd_state, fmt->pad) = fmt->format; + + dev_dbg(ctx->dev, + "s_fmt pad %d code/res 0x%x/%dx%d which %d=> 0x%x/%dx%d\n", + fmt->pad, + fmt->format.code, + fmt->format.width, + fmt->format.height, + fmt->which, + format->code, + format->width, + format->height); + } else { + /* Update vcinfo once the SINK format changed */ + if (fmt->pad == PAD_SINK) + sink_format_changed = 1; + + format->code = fmt->format.code; + format->width = fmt->format.width; + format->height = fmt->format.height; + + if (sink_format_changed && !ctx->is_test_model) + mtk_cam_seninf_get_vcinfo(ctx); + + dev_info(ctx->dev, + "s_fmt pad %d code/res 0x%x/%dx%d which %d=> 0x%x/%dx%d\n", + fmt->pad, + fmt->format.code, + fmt->format.width, + fmt->format.height, + fmt->which, + format->code, + format->width, + format->height); + } + + return 0; +} + +static int mtk_cam_seninf_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct seninf_ctx *ctx = sd_to_ctx(sd); + struct v4l2_mbus_framefmt *format; + + if (fmt->pad < PAD_SINK || fmt->pad >= PAD_MAXCNT) + return -EINVAL; + + format = &ctx->fmt[fmt->pad].format; + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { + fmt->format = *v4l2_subdev_state_get_format(sd_state, fmt->pad); + } else { + fmt->format.code = format->code; + fmt->format.width = format->width; + fmt->format.height = format->height; + fmt->format.field = format->field; + fmt->format.colorspace = format->colorspace; + fmt->format.xfer_func = format->xfer_func; + fmt->format.ycbcr_enc = format->ycbcr_enc; + fmt->format.quantization = format->quantization; + } + + return 0; +} + +static int set_test_model(struct seninf_ctx *ctx, char enable) +{ + struct seninf_vc *vc[] = { NULL, NULL, NULL, NULL, NULL }; + int i = 0, ret = 0, vc_used = 0; + struct seninf_mux *mux; + int pref_idx[] = { 0, 1, 2, 3, 4 }; + + if (ctx->is_test_model == 1) { + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0); + } else if (ctx->is_test_model == 2) { + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0); + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW1); + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW2); + } else if (ctx->is_test_model == 3) { + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0); + vc[vc_used++] = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_PDAF0); + } else { + dev_info(ctx->dev, "testmodel%d invalid\n", ctx->is_test_model); + return -1; + } + + for (; i < vc_used; ++i) { + if (!vc[i]) { + dev_info(ctx->dev, "vc not found\n"); + return -1; + } + } + + if (enable) { + ret = pm_runtime_resume_and_get(ctx->dev); + if (ret < 0) { + dev_info(ctx->dev, "failed at pm_runtime_resume_and_get\n"); + return ret; + } + + if (ctx->core->clk[CLK_TOP_CAMTM]) + ret = clk_prepare_enable(ctx->core->clk[CLK_TOP_CAMTM]); + if (ret) + return ret; + + for (i = 0; i < vc_used; ++i) { + mux = mtk_cam_seninf_mux_get_pref(ctx, + pref_idx, + ARRAY_SIZE(pref_idx)); + if (!mux) + return -EBUSY; + vc[i]->mux = mux->idx; + vc[i]->cam = ctx->pad2cam[vc[i]->out_pad]; + vc[i]->enable = 1; + + dev_info(ctx->dev, + "test mode mux %d, cam %d, pixel mode %d\n", + vc[i]->mux, vc[i]->cam, vc[i]->pixel_mode); + + mtk_cam_seninf_set_test_model(ctx, vc[i]->mux, + vc[i]->cam, + vc[i]->pixel_mode); + + if (vc[i]->out_pad == PAD_SRC_PDAF0) + mdelay(40); + else + usleep_range(40, 60); + } + } else { + mtk_cam_seninf_set_idle(ctx); + mtk_cam_seninf_release_mux(ctx); + + if (ctx->core->clk[CLK_TOP_CAMTM]) + clk_disable_unprepare(ctx->core->clk[CLK_TOP_CAMTM]); + + pm_runtime_put_sync(ctx->dev); + } + + ctx->streaming = enable; + + return 0; +} + +static int config_hw(struct seninf_ctx *ctx) +{ + int i, intf, skip_mux_ctrl; + int hs_pol, vs_pol, vc_sel, dt_sel, dt_en; + struct seninf_vcinfo *vcinfo; + struct seninf_vc *vc; + struct seninf_mux *mux, *mux_by_grp[SENINF_VC_MAXCNT] = { 0 }; + + intf = ctx->seninf_idx; + vcinfo = &ctx->vcinfo; + + mtk_cam_seninf_reset(ctx, intf); + + mtk_cam_seninf_set_vc(ctx, intf, vcinfo); + + mtk_cam_seninf_set_csi_mipi(ctx); + + /* should set false */ + hs_pol = 0; + vs_pol = 0; + + for (i = 0; i < vcinfo->cnt; i++) { + vc = &vcinfo->vc[i]; + + /* alloc mux by group */ + if (mux_by_grp[vc->group]) { + mux = mux_by_grp[vc->group]; + skip_mux_ctrl = 1; + } else { + int pref_idx[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21 }; + mux_by_grp[vc->group] = + mtk_cam_seninf_mux_get_pref(ctx, + pref_idx, + g_seninf_cfg->pref_mux_num); + mux = mux_by_grp[vc->group]; + skip_mux_ctrl = 0; + } + + if (!mux) { + mtk_cam_seninf_release_mux(ctx); + return -EBUSY; + } + + vc->mux = mux->idx; + vc->cam = ctx->pad2cam[vc->out_pad]; + + if (!skip_mux_ctrl) { + mtk_cam_seninf_mux(ctx, vc->mux); + mtk_cam_seninf_set_mux_ctrl(ctx, vc->mux, + hs_pol, vs_pol, + MIPI_SENSOR + vc->group, + vc->pixel_mode); + + mtk_cam_seninf_set_top_mux_ctrl(ctx, vc->mux, intf); + + /* disable mtk_cam_seninf_set_mux_crop length limit */ + } + dev_info(ctx->dev, "ctx->pad2cam[%d] %d vc->out_pad %d vc->cam %d, i %d", + vc->out_pad, ctx->pad2cam[vc->out_pad], vc->out_pad, vc->cam, i); + + if (vc->cam != 0xff) { + vc_sel = vc->vc; + dt_sel = vc->dt; + dt_en = !!dt_sel; + + /* CMD_SENINF_FINALIZE_CAM_MUX */ + mtk_cam_seninf_set_cammux_vc(ctx, vc->cam, + vc_sel, dt_sel, + dt_en, dt_en); + mtk_cam_seninf_set_cammux_src(ctx, vc->mux, vc->cam, + vc->exp_hsize, + vc->exp_vsize); + mtk_cam_seninf_set_cammux_chk_pixel_mode(ctx, + vc->cam, + vc->pixel_mode); + mtk_cam_seninf_cammux(ctx, vc->cam); + + dev_info(ctx->dev, "vc[%d] pad %d intf %d mux %d cam %d\n", + i, vc->out_pad, intf, vc->mux, vc->cam); + } else { + dev_info(ctx->dev, + "not set camtg yet, vc[%d] pad %d intf %d mux %d cam %d\n", + i, vc->out_pad, intf, vc->mux, vc->cam); + } + } + return 0; +} + +static int calc_buffered_pixel_rate(struct device *dev, + s64 width, s64 height, + s64 hblank, s64 vblank, + int fps_n, int fps_d, s64 *result) +{ + s64 orig_pixel_rate = *result; + u64 buffered_pixel_rate, pclk, k; + + if (fps_d == 0 || width == 0 || hblank == 0 || ISP_CLK_LOW == 0) { + dev_info(dev, + "Prevent divided by 0, fps_d= %d, w= %llu, h= %llu, ISP_CLK= %d\n", + fps_d, width, hblank, ISP_CLK_LOW); + return 0; + } + + /* calculate pclk */ + pclk = (width + hblank) * (height + vblank) * fps_n; + do_div(pclk, fps_d); + + /* calculate buffered pixel_rate */ + buffered_pixel_rate = orig_pixel_rate * width; + k = HW_BUF_EFFECT * orig_pixel_rate; + do_div(k, ISP_CLK_LOW); + do_div(buffered_pixel_rate, (width + hblank - k)); + *result = buffered_pixel_rate; + + dev_info(dev, + "%s: w %lld h %lld hb %lld vb %lld fps %d/%d pclk %lld->%lld orig %lld k %lld hbe %d\n", + __func__, width, height, hblank, vblank, + fps_n, fps_d, pclk, buffered_pixel_rate, orig_pixel_rate, k, HW_BUF_EFFECT); + + return 0; +} + +static int get_buffered_pixel_rate(struct seninf_ctx *ctx, + struct v4l2_subdev *sd, int sd_pad_idx, + s64 *result) +{ + int ret; + struct v4l2_ctrl *ctrl; + struct v4l2_subdev_format fmt; + struct v4l2_subdev_frame_interval fi; + s64 width, height, hblank, vblank; + + fmt.pad = sd_pad_idx; + fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE; + ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &fmt); + if (ret) { + dev_info(ctx->dev, "no get_fmt in %s\n", sd->name); + return ret; + } + + width = fmt.format.width; + height = fmt.format.height; + + memset(&fi, 0, sizeof(fi)); + fi.pad = sd_pad_idx; + ret = v4l2_subdev_call_state_active(sd, pad, get_frame_interval, &fi); + if (ret) { + dev_info(ctx->dev, "no get_frame_interval in %s\n", sd->name); + return ret; + } + + ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_HBLANK); + if (!ctrl) { + dev_info(ctx->dev, "no hblank in %s\n", sd->name); + return -EINVAL; + } + + hblank = v4l2_ctrl_g_ctrl(ctrl); + + ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_VBLANK); + if (!ctrl) { + dev_info(ctx->dev, "no vblank in %s\n", sd->name); + return -EINVAL; + } + + vblank = v4l2_ctrl_g_ctrl(ctrl); + + /* update fps */ + ctx->fps_n = fi.interval.denominator; + ctx->fps_d = fi.interval.numerator; + + return calc_buffered_pixel_rate(ctx->dev, width, height, hblank, vblank, + ctx->fps_n, ctx->fps_d, result); +} + +static int get_pixel_rate(struct seninf_ctx *ctx, struct v4l2_subdev *sd, + s64 *result) +{ + struct v4l2_ctrl *ctrl; + + ctrl = v4l2_ctrl_find(sd->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_info(ctx->dev, "no pixel rate in subdev %s\n", sd->name); + return -EINVAL; + } + + *result = v4l2_ctrl_g_ctrl_int64(ctrl); + + return 0; +} + +int update_isp_clk(struct seninf_ctx *ctx) +{ + int i, pixelmode; + struct seninf_dfs *dfs = &ctx->core->dfs; + s64 pixel_rate = -1; + u64 dfs_freq; + struct seninf_vc *vc; + int ret = 0; + + if (!dfs->cnt) { + dev_info(ctx->dev, "dfs not ready.\n"); + return ret; + } + + vc = mtk_cam_seninf_get_vc_by_pad(ctx, PAD_SRC_RAW0); + if (!vc) { + dev_info(ctx->dev, "failed to get vc\n"); + return -1; + } + dev_info(ctx->dev, + "%s dfs->cnt %d pixel mode %d customized_pixel_rate %lld, buffered_pixel_rate %lld mipi_pixel_rate %lld\n", + __func__, dfs->cnt, vc->pixel_mode, ctx->customized_pixel_rate, + ctx->buffered_pixel_rate, ctx->mipi_pixel_rate); + + /* Use SensorPixelrate */ + if (ctx->customized_pixel_rate) { + pixel_rate = ctx->customized_pixel_rate; + } else if (ctx->buffered_pixel_rate) { + pixel_rate = ctx->buffered_pixel_rate; + } else if (ctx->mipi_pixel_rate) { + pixel_rate = ctx->mipi_pixel_rate; + } else { + dev_info(ctx->dev, "failed to get pixel_rate\n"); + return -EINVAL; + } + + pixelmode = vc->pixel_mode; + for (i = 0; i < dfs->cnt; i++) { + dfs_freq = dfs->freqs[i]; + dfs_freq = dfs_freq * (100 - SENINF_CLK_MARGIN_IN_PERCENT); + do_div(dfs_freq, 100); + if ((dfs_freq << pixelmode) >= pixel_rate) + break; + } + + if (i == dfs->cnt) { + dev_info(ctx->dev, "mux is overrun. please adjust pixelmode\n"); + return -EINVAL; + } + + return 0; +} + +static int debug_err_detect_initialize(struct seninf_ctx *ctx) +{ + struct seninf_core *core; + struct seninf_ctx *ctx_; + + core = dev_get_drvdata(ctx->dev->parent); + + core->csi_irq_en_flag = 0; + + list_for_each_entry(ctx_, &core->list, list) { + ctx_->data_not_enough_flag = 0; + ctx_->err_lane_resync_flag = 0; + ctx_->crc_err_flag = 0; + ctx_->ecc_err_double_flag = 0; + ctx_->ecc_err_corrected_flag = 0; + ctx_->fifo_overrun_flag = 0; + ctx_->size_err_flag = 0; + ctx_->data_not_enough_cnt = 0; + ctx_->err_lane_resync_cnt = 0; + ctx_->crc_err_cnt = 0; + ctx_->ecc_err_double_cnt = 0; + ctx_->ecc_err_corrected_cnt = 0; + ctx_->fifo_overrun_cnt = 0; + ctx_->size_err_cnt = 0; + } + + return 0; +} + +static int seninf_s_stream(struct v4l2_subdev *sd, int enable) +{ + int ret; + struct seninf_ctx *ctx = sd_to_ctx(sd); + + if (ctx->streaming == enable) + return 0; + + if (ctx->is_test_model) + return set_test_model(ctx, enable); + + if (!ctx->sensor_sd) { + dev_info(ctx->dev, "no sensor\n"); + return -EFAULT; + } + + if (enable) { + debug_err_detect_initialize(ctx); + + get_pixel_rate(ctx, ctx->sensor_sd, &ctx->mipi_pixel_rate); + + ctx->buffered_pixel_rate = ctx->mipi_pixel_rate; + get_buffered_pixel_rate(ctx, ctx->sensor_sd, + ctx->sensor_pad_idx, + &ctx->buffered_pixel_rate); + + ret = pm_runtime_resume_and_get(ctx->dev); + if (ret < 0) { + dev_info(ctx->dev, + "%s pm_runtime_resume_and_get ret %d\n", + __func__, ret); + return ret; + } + + update_isp_clk(ctx); + + ret = config_hw(ctx); + if (ret) { + dev_info(ctx->dev, "config_seninf_hw ret %d\n", ret); + return ret; + } + + /* middleware control sensor fsync after set cam-mux */ + + ret = v4l2_subdev_call(ctx->sensor_sd, video, s_stream, 1); + if (ret) { + dev_info(ctx->dev, "sensor stream-on ret %d\n", ret); + return ret; + } + + } else { + ret = v4l2_subdev_call(ctx->sensor_sd, video, s_stream, 0); + if (ret) { + dev_info(ctx->dev, "sensor stream-off ret %d\n", ret); + return ret; + } + + mtk_cam_seninf_set_idle(ctx); + mtk_cam_seninf_release_mux(ctx); + + mtk_cam_seninf_poweroff(ctx); + pm_runtime_put_sync(ctx->dev); + } + + ctx->streaming = enable; + return 0; +} + +static const struct v4l2_subdev_pad_ops seninf_subdev_pad_ops = { + .link_validate = mtk_cam_link_validate, + .set_fmt = mtk_cam_seninf_set_fmt, + .get_fmt = mtk_cam_seninf_get_fmt, +}; + +static const struct v4l2_subdev_video_ops seninf_subdev_video_ops = { + .s_stream = seninf_s_stream, +}; + +static const struct v4l2_subdev_core_ops seninf_subdev_core_ops = { + .subscribe_event = seninf_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_internal_ops seninf_subdev_internal_ops = { + .init_state = mtk_cam_seninf_init_state, +}; + +static const struct v4l2_subdev_ops seninf_subdev_ops = { + .core = &seninf_subdev_core_ops, + .video = &seninf_subdev_video_ops, + .pad = &seninf_subdev_pad_ops, +}; + +static int seninf_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd; + struct seninf_ctx *ctx; + + sd = media_entity_to_v4l2_subdev(entity); + if (!sd) + return -EINVAL; + ctx = v4l2_get_subdevdata(sd); + if (!ctx) + return -EINVAL; + + if (local->flags & MEDIA_PAD_FL_SOURCE) { + if (flags & MEDIA_LNK_FL_ENABLED) { + if (!mtk_cam_seninf_get_vc_by_pad(ctx, local->index)) { + dev_info(ctx->dev, + "%s enable link w/o vc_info pad idex %d\n", + __func__, local->index); + } + } + } else { + /* Update vcinfo once the link becomes enabled */ + if (flags & MEDIA_LNK_FL_ENABLED) { + ctx->sensor_sd = + media_entity_to_v4l2_subdev(remote->entity); + ctx->sensor_pad_idx = remote->index; + mtk_cam_seninf_get_vcinfo(ctx); + } + } + + return 0; +} + +static const struct media_entity_operations seninf_media_ops = { + .link_setup = seninf_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +struct sensor_async_subdev { + struct v4l2_async_connection asc; + u32 port; + u32 bus_type; + u32 lanes; +}; + +static int seninf_notifier_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_connection *asc) +{ + struct seninf_ctx *ctx = notifier_to_ctx(notifier); + struct sensor_async_subdev *s_asd = + container_of(asc, struct sensor_async_subdev, asc); + int ret; + + dev_info(ctx->dev, "[%s] %s bounded, bus_type:%d, lanes:%d\n", + __func__, sd->entity.name, s_asd->bus_type, s_asd->lanes); + + ctx->is_cphy = (s_asd->bus_type == V4L2_MBUS_CSI2_CPHY); + ctx->num_data_lanes = s_asd->lanes; + + ret = media_create_pad_link(&sd->entity, 0, &ctx->subdev.entity, 0, 0); + if (ret) { + dev_info(ctx->dev, "failed to create link for %s\n", + sd->entity.name); + return ret; + } + + ret = v4l2_device_register_subdev_nodes(ctx->subdev.v4l2_dev); + if (ret) { + dev_info(ctx->dev, "failed to create subdev nodes\n"); + return ret; + } + + return 0; +} + +static void seninf_notifier_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *sd, + struct v4l2_async_connection *asc) +{ + struct seninf_ctx *ctx = notifier_to_ctx(notifier); + + dev_info(ctx->dev, "%s is unbounded\n", sd->entity.name); +} + +static const struct v4l2_async_notifier_operations seninf_async_ops = { + .bound = seninf_notifier_bound, + .unbind = seninf_notifier_unbind, +}; + +/* Update vcinfo once test_model switches */ +static int seninf_test_pattern(struct seninf_ctx *ctx, u32 pattern) +{ + switch (pattern) { + case 0: + if (ctx->streaming) + return -EBUSY; + ctx->is_test_model = 0; + mtk_cam_seninf_get_vcinfo(ctx); + dev_info(ctx->dev, "test pattern off\n"); + break; + case 1: /* 1 RAW only */ + case 2: /* 3 Stagger expo */ + case 3: /* 1 RAW and 1 PD */ + if (ctx->streaming) + return -EBUSY; + ctx->is_test_model = pattern; + mtk_cam_seninf_get_vcinfo_test(ctx); + dev_info(ctx->dev, "test pattern on\n"); + break; + default: + break; + } + + return 0; +} + +static int mtk_cam_seninf_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct seninf_ctx *ctx = ctrl_hdl_to_ctx(ctrl->handler); + int ret = -EINVAL; + + switch (ctrl->id) { + case V4L2_CID_TEST_PATTERN: + ret = seninf_test_pattern(ctx, ctrl->val); + break; + default: + ret = 0; + dev_info(ctx->dev, "%s Unhandled id:0x%x, val:0x%x\n", + __func__, ctrl->id, ctrl->val); + break; + } + + return ret; +} + +static const struct v4l2_ctrl_ops seninf_ctrl_ops = { + .s_ctrl = mtk_cam_seninf_set_ctrl, +}; + +static int seninf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct seninf_ctx *ctx = sd_to_ctx(sd); + + mutex_lock(&ctx->mutex); + ctx->open_refcnt++; + + if (ctx->open_refcnt == 1) + dev_info(ctx->dev, "%s open_refcnt %d\n", + __func__, ctx->open_refcnt); + + mutex_unlock(&ctx->mutex); + + return 0; +} + +static int seninf_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) +{ + struct seninf_ctx *ctx = sd_to_ctx(sd); + + mutex_lock(&ctx->mutex); + ctx->open_refcnt--; + + if (!ctx->open_refcnt) { + dev_info(ctx->dev, "%s open_refcnt %d\n", + __func__, ctx->open_refcnt); + if (ctx->streaming) + seninf_s_stream(&ctx->subdev, 0); + } + + mutex_unlock(&ctx->mutex); + + return 0; +} + +static const struct v4l2_subdev_internal_ops seninf_internal_ops = { + .open = seninf_open, + .close = seninf_close, +}; + +static const char *const seninf_test_pattern_menu[] = { + "Disabled", + "generate_test_pattern", + "generate_test_pattern_stagger", + "generate_test_pattern_pd", +}; + +static int seninf_initialize_controls(struct seninf_ctx *ctx) +{ + struct v4l2_ctrl_handler *handler; + int ret; + + handler = &ctx->ctrl_handler; + ret = v4l2_ctrl_handler_init(handler, 2); + if (ret) + return ret; + v4l2_ctrl_new_std_menu_items(handler, &seninf_ctrl_ops, + V4L2_CID_TEST_PATTERN, + ARRAY_SIZE(seninf_test_pattern_menu) - 1, + 0, 0, seninf_test_pattern_menu); + + if (handler->error) { + ret = handler->error; + dev_info(ctx->dev, "Failed to init controls(%d)\n", ret); + goto err_free_handler; + } + + ctx->subdev.ctrl_handler = handler; + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(handler); + + return ret; +} + +static int seninf_parse_endpoint(struct device *dev, + struct v4l2_fwnode_endpoint *vep, + struct sensor_async_subdev *s_asd) +{ + struct fwnode_handle *remote_hnd; + + s_asd->port = vep->base.port; + s_asd->bus_type = vep->bus_type; + s_asd->lanes = vep->bus.mipi_csi2.num_data_lanes; + + dev_dbg(dev, "Got local node port:%d type:%d lanes:%d\n", + vep->base.port, vep->bus_type, + vep->bus.mipi_csi2.num_data_lanes); + + /* check if sensor endpoint assign mipi lane nums */ + remote_hnd = fwnode_graph_get_remote_endpoint(vep->base.local_fwnode); + if (remote_hnd) { + u32 remote_bus = 0, remote_lanes = 0; + + fwnode_property_read_u32(remote_hnd, "bus-type", &remote_bus); + if (remote_bus == V4L2_FWNODE_BUS_TYPE_CSI2_DPHY) + s_asd->bus_type = V4L2_MBUS_CSI2_DPHY; + else if (remote_bus == V4L2_FWNODE_BUS_TYPE_CSI2_CPHY) + s_asd->bus_type = V4L2_MBUS_CSI2_CPHY; + + remote_lanes = + fwnode_property_count_u32(remote_hnd, "data-lanes"); + if (remote_lanes > 0 && + remote_lanes <= vep->bus.mipi_csi2.num_data_lanes) + s_asd->lanes = remote_lanes; + + fwnode_handle_put(remote_hnd); + dev_dbg(dev, "Got remote node lanes:%d\n", remote_lanes); + } + + return 0; +} + +static int seninf_parse_fwnode(struct device *dev, + struct v4l2_async_notifier *notifier) +{ + struct fwnode_handle *fwnode = NULL; + struct v4l2_fwnode_endpoint vep = { + .bus_type = V4L2_MBUS_CSI2_DPHY, /* CDPHY only */ + }; + int ret = 0; + + fwnode_graph_for_each_endpoint(dev_fwnode(dev), fwnode) { + struct sensor_async_subdev *s_asd; + + ret = v4l2_fwnode_endpoint_parse(fwnode, &vep); + if (ret) { + dev_err(dev, "failed to parse v4l2 fwnode endpoint\n"); + break; + } + + if (vep.bus_type != V4L2_MBUS_CSI2_DPHY && + vep.bus_type != V4L2_MBUS_CSI2_CPHY) { + dev_err(dev, "Got unsupported endpoint:%d, bus:%d\n", + vep.base.port, vep.bus_type); + continue; + } + + s_asd = v4l2_async_nf_add_fwnode_remote(notifier, fwnode, + struct sensor_async_subdev); + if (IS_ERR(s_asd)) { + ret = PTR_ERR(s_asd); + break; + } + + ret = seninf_parse_endpoint(dev, &vep, s_asd); + if (ret < 0) + break; + } + + if (fwnode) + fwnode_handle_put(fwnode); + + return ret; +} + +static int register_subdev(struct seninf_ctx *ctx) +{ + int i, ret; + struct v4l2_subdev *sd = &ctx->subdev; + struct device *dev = ctx->dev; + struct media_pad *pads = ctx->pads; + struct v4l2_async_notifier *notifier = &ctx->notifier; + + v4l2_subdev_init(sd, &seninf_subdev_ops); + sd->internal_ops = &seninf_subdev_internal_ops; + sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; + sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS; + sd->dev = dev; + + if (strlen(dev->of_node->name) > 16) + snprintf(sd->name, sizeof(sd->name), "%s-%s", + dev_driver_string(dev), &dev->of_node->name[16]); + else + snprintf(sd->name, sizeof(sd->name), "%s-%s", + dev_driver_string(dev), csi_port_names[ctx->port]); + + v4l2_set_subdevdata(sd, ctx); + + sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; + sd->entity.ops = &seninf_media_ops; + sd->internal_ops = &seninf_internal_ops; + + pads[PAD_SINK].flags = MEDIA_PAD_FL_SINK; + for (i = PAD_SRC_RAW0; i < PAD_MAXCNT; i++) + pads[i].flags = MEDIA_PAD_FL_SOURCE; + + for (i = 0; i < PAD_MAXCNT; i++) + ctx->pad2cam[i] = 0xff; + + ret = media_entity_pads_init(&sd->entity, PAD_MAXCNT, pads); + if (ret < 0) { + dev_info(dev, "failed to init pads\n"); + return ret; + } + + /* register seninf as mtk_cam async child */ + ret = v4l2_async_register_subdev(sd); + if (ret < 0) { + dev_info(dev, "failed to register subdev\n"); + return ret; + } + + /* register seninf as sensor async parent */ + v4l2_async_subdev_nf_init(notifier, sd); + ret = seninf_parse_fwnode(dev, notifier); + if (ret < 0) + dev_info(dev, "no endpoint\n"); + + notifier->ops = &seninf_async_ops; + ret = v4l2_async_nf_register(notifier); + if (ret < 0) { + dev_info(dev, "failed to register notifier\n"); + goto err_unregister_subdev; + } + + return 0; + +err_unregister_subdev: + v4l2_device_unregister_subdev(sd); + v4l2_async_nf_cleanup(notifier); + + return ret; +} + +static void unregister_subdev(struct seninf_ctx *ctx) +{ + struct v4l2_subdev *sd = &ctx->subdev; + + v4l2_async_nf_unregister(&ctx->notifier); + v4l2_async_nf_cleanup(&ctx->notifier); + v4l2_async_unregister_subdev(sd); + media_entity_cleanup(&sd->entity); +} + +static int seninf_probe(struct platform_device *pdev) +{ + int ret, port; + struct seninf_ctx *ctx; + struct device *dev = &pdev->dev; + struct seninf_core *core; + + if (!dev->parent) + return -EPROBE_DEFER; + + /* get mtk seninf_core */ + core = dev_get_drvdata(dev->parent); + if (!core) + return -EPROBE_DEFER; + + /* init seninf_csi ctx */ + ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL); + if (!ctx) + return -ENOMEM; + + dev_set_drvdata(dev, ctx); + ctx->dev = dev; + ctx->core = core; + list_add(&ctx->list, &core->list); + INIT_LIST_HEAD(&ctx->list_mux); + INIT_LIST_HEAD(&ctx->list_cam_mux); + + ctx->open_refcnt = 0; + mutex_init(&ctx->mutex); + + ret = get_csi_port(dev, &port); + if (ret) { + dev_info(dev, "get_csi_port ret %d\n", ret); + return ret; + } + + mtk_cam_seninf_init_iomem(ctx, core->reg_if, core->reg_ana); + mtk_cam_seninf_init_port(ctx, port); + init_fmt(ctx); + + /* platform properties */ + ctx->cphy_settle_delay_dt = ctx->core->cphy_settle_delay_dt; + ctx->dphy_settle_delay_dt = ctx->core->dphy_settle_delay_dt; + ctx->settle_delay_ck = ctx->core->settle_delay_ck; + ctx->hs_trail_parameter = ctx->core->hs_trail_parameter; + + of_property_read_u32(dev->of_node, "cphy_settle_delay_dt", + &ctx->cphy_settle_delay_dt); + of_property_read_u32(dev->of_node, "dphy_settle_delay_dt", + &ctx->dphy_settle_delay_dt); + of_property_read_u32(dev->of_node, "settle_delay_ck", + &ctx->settle_delay_ck); + of_property_read_u32(dev->of_node, "hs_trail_parameter", + &ctx->hs_trail_parameter); + + dev_info(dev, + "seninf d_settlte/d_settle_ck/d_trail/c_settle= 0x%x/0x%x/0x%x/0x%x\n", + ctx->dphy_settle_delay_dt, + ctx->settle_delay_ck, + ctx->hs_trail_parameter, + ctx->cphy_settle_delay_dt); + + ret = dev_read_csi_efuse(ctx); + if (ret < 0) + dev_info(dev, "Failed to read efuse data\n"); + + ret = seninf_initialize_controls(ctx); + if (ret) { + dev_info(dev, "Failed to initialize controls\n"); + return ret; + } + + /* bind seninf_csi to mtkcam */ + ret = register_subdev(ctx); + if (ret < 0) { + dev_err(dev, "register_subdev failed\n"); + goto err_free_handler; + } + + pm_runtime_enable(dev); + + dev_info(dev, "%s: port=%d\n", __func__, ctx->port); + + dev_info(dev, "camsys | [%s] success\n", __func__); + + return 0; + +err_free_handler: + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + + return ret; +} + +static int runtime_suspend(struct device *dev) +{ + int i; + struct seninf_ctx *ctx = dev_get_drvdata(dev); + struct seninf_core *core = ctx->core; + + mutex_lock(&core->mutex); + + core->refcnt--; + if (core->refcnt == 0) { + i = CLK_TOP_SENINF_END; + do { + i--; + if (ctx->core->clk[i]) + clk_disable_unprepare(ctx->core->clk[i]); + } while (i); + seninf_core_pm_runtime_put(core); + } + + mutex_unlock(&core->mutex); + + return 0; +} + +static int runtime_resume(struct device *dev) +{ + u32 i; + int ret; + + struct seninf_ctx *ctx = dev_get_drvdata(dev); + struct seninf_core *core = ctx->core; + + mutex_lock(&core->mutex); + + core->refcnt++; + + if (core->refcnt == 1) { + ret = seninf_core_pm_runtime_get_sync(core); + if (ret < 0) { + dev_info(dev, "seninf_core_pm_runtime_get_sync failed\n"); + return ret; + } + + for (i = 0; i < CLK_TOP_SENINF_END; i++) { + if (core->clk[i]) + ret = clk_prepare_enable(core->clk[i]); + if (ret) + dev_dbg(dev, "%s: clk seninf%d is empty\n", + __func__, i); + } + mtk_cam_seninf_disable_all_mux(ctx); + mtk_cam_seninf_disable_all_cammux(ctx); + } + + mutex_unlock(&core->mutex); + + return 0; +} + +static const struct dev_pm_ops pm_ops = { + SET_RUNTIME_PM_OPS(runtime_suspend, runtime_resume, NULL) +}; + +static void seninf_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct seninf_ctx *ctx = dev_get_drvdata(dev); + + if (ctx->streaming) { + mtk_cam_seninf_set_idle(ctx); + mtk_cam_seninf_release_mux(ctx); + } + + pm_runtime_disable(ctx->dev); + + unregister_subdev(ctx); + + v4l2_ctrl_handler_free(&ctx->ctrl_handler); + + mutex_destroy(&ctx->mutex); + + dev_dbg(dev, "camsys | start %s\n", __func__); +} + +static const struct of_device_id seninf_of_match[] = { + { .compatible = "mediatek,seninf" }, + {}, +}; +MODULE_DEVICE_TABLE(of, seninf_of_match); + +static int seninf_suspend(struct platform_device *pdev, pm_message_t mesg) +{ + return 0; +} + +static int seninf_resume(struct platform_device *pdev) +{ + return 0; +} + +struct platform_driver seninf_pdrv = { + .probe = seninf_probe, + .remove = seninf_remove, + .suspend = seninf_suspend, + .resume = seninf_resume, + .driver = { + .name = "seninf", + .of_match_table = seninf_of_match, + .pm = &pm_ops, + }, +}; + +int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height, + s64 hblank, s64 vblank, + int fps_n, int fps_d, + s64 sensor_pixel_rate) +{ + int ret; + s64 p_pixel_rate = sensor_pixel_rate; + + ret = calc_buffered_pixel_rate(dev, width, height, hblank, vblank, + fps_n, fps_d, &p_pixel_rate); + if (ret) + return sensor_pixel_rate; + + return p_pixel_rate; +} + +int mtk_cam_seninf_get_pixelrate(struct v4l2_subdev *sd, s64 *p_pixel_rate) +{ + int ret; + s64 pixel_rate = -1; + struct seninf_ctx *ctx = sd_to_ctx(sd); + + if (!ctx->sensor_sd) { + dev_info(ctx->dev, "no sensor\n"); + return -EFAULT; + } + + ret = get_buffered_pixel_rate(ctx, + ctx->sensor_sd, ctx->sensor_pad_idx, + &pixel_rate); + if (ret) + get_pixel_rate(ctx, ctx->sensor_sd, &pixel_rate); + + if (pixel_rate <= 0) { + dev_info(ctx->dev, "failed to get pixel_rate\n"); + return -EINVAL; + } + + *p_pixel_rate = pixel_rate; + + return 0; +} + +int mtk_cam_seninf_dump(struct v4l2_subdev *sd) +{ + int ret = 0; + struct seninf_ctx *ctx = sd_to_ctx(sd); + + ret = pm_runtime_resume_and_get(ctx->dev); + if (ret < 0) { + dev_info(ctx->dev, "%s pm_runtime_resume_and_get ret %d\n", + __func__, ret); + return ret; + } + + if (ctx->streaming) { + ret = mtk_cam_seninf_debug(sd_to_ctx(sd)); + /* user may call sensor ESD_RESET_SUPPORT */ + } else { + dev_info(ctx->dev, "%s should not dump during stream off\n", + __func__); + } + + pm_runtime_put_sync(ctx->dev); + return ret; +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h new file mode 100644 index 000000000000..117ae208cf4b --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-drv.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_DRV_H +#define __MTK_CAM_SENINF_DRV_H + +#include "mtk_cam-seninf.h" + +extern struct platform_driver seninf_core_pdrv; +extern struct platform_driver seninf_pdrv; + +int update_isp_clk(struct seninf_ctx *ctx); + +#endif /*__MTK_CAM_SENINF_DRV_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h new file mode 100644 index 000000000000..535112f318b7 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-hw.h @@ -0,0 +1,120 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_HW_H__ +#define __MTK_CAM_SENINF_HW_H__ + +enum SET_REG_KEYS { + REG_KEY_MIN = 0, + REG_KEY_SETTLE_CK = REG_KEY_MIN, + REG_KEY_SETTLE_DT, + REG_KEY_HS_TRAIL_EN, + REG_KEY_HS_TRAIL_PARAM, + REG_KEY_CSI_IRQ_STAT, + REG_KEY_CSI_RESYNC_CYCLE, + REG_KEY_MUX_IRQ_STAT, + REG_KEY_CAMMUX_IRQ_STAT, + REG_KEY_CAMMUX_VSYNC_IRQ_EN, + REG_KEY_CSI_IRQ_EN, + REG_KEY_MAX_NUM +}; + +#define SET_REG_KEYS_NAMES \ + "RG_SETTLE_CK", \ + "RG_SETTLE_DT", \ + "RG_HS_TRAIL_EN", \ + "RG_HS_TRAIL_PARAM", \ + "RG_CSI_IRQ_STAT", \ + "RG_CSI_RESYNC_CYCLE", \ + "RG_MUX_IRQ_STAT", \ + "RG_CAMMUX_IRQ_STAT", \ + "REG_VSYNC_IRQ_EN", \ + "RG_CSI_IRQ_EN", \ + +struct mtk_cam_seninf_mux_meter { + u32 width; + u32 height; + u32 h_valid; + u32 h_blank; + u32 v_valid; + u32 v_blank; + s64 mipi_pixel_rate; + s64 vb_in_us; + s64 hb_in_us; + s64 line_time_in_us; +}; + +struct mtk_cam_seninf_cfg { + unsigned int seninf_num; + unsigned int mux_num; + unsigned int cam_mux_num; + unsigned int pref_mux_num; +}; + +extern struct mtk_cam_seninf_cfg *g_seninf_cfg; + +int mtk_cam_seninf_init_iomem(struct seninf_ctx *ctx, void __iomem *if_base, + void __iomem *ana_base); +int mtk_cam_seninf_init_port(struct seninf_ctx *ctx, int port); +int mtk_cam_seninf_is_cammux_used(struct seninf_ctx *ctx, int cam_mux); +int mtk_cam_seninf_cammux(struct seninf_ctx *ctx, int cam_mux); +int mtk_cam_seninf_disable_cammux(struct seninf_ctx *ctx, int cam_mux); +int mtk_cam_seninf_disable_all_cammux(struct seninf_ctx *ctx); +int mtk_cam_seninf_set_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx, + int seninf_src); +int mtk_cam_seninf_get_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx); +int mtk_cam_seninf_get_cammux_ctrl(struct seninf_ctx *ctx, int cam_mux); +u32 mtk_cam_seninf_get_cammux_res(struct seninf_ctx *ctx, int cam_mux); +int mtk_cam_seninf_set_cammux_vc(struct seninf_ctx *ctx, int cam_mux, + int vc_sel, int dt_sel, int vc_en, + int dt_en); +int mtk_cam_seninf_set_cammux_src(struct seninf_ctx *ctx, int src, + int target, int exp_hsize, int exp_vsize); +int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx, + struct seninf_vcinfo *vcinfo); +int mtk_cam_seninf_set_mux_ctrl(struct seninf_ctx *ctx, u32 mux, int hs_pol, + int vs_pol, int src_sel, int pixel_mode); +int mtk_cam_seninf_set_mux_crop(struct seninf_ctx *ctx, u32 mux, int start_x, + int end_x, int enable); +int mtk_cam_seninf_is_mux_used(struct seninf_ctx *ctx, u32 mux); +int mtk_cam_seninf_mux(struct seninf_ctx *ctx, u32 mux); +int mtk_cam_seninf_disable_mux(struct seninf_ctx *ctx, u32 mux); +int mtk_cam_seninf_disable_all_mux(struct seninf_ctx *ctx); +int mtk_cam_seninf_set_cammux_chk_pixel_mode(struct seninf_ctx *ctx, + int cam_mux, int pixel_mode); +int mtk_cam_seninf_set_test_model(struct seninf_ctx *ctx, int mux, int cam_mux, + int pixel_mode); +int mtk_cam_seninf_set_csi_mipi(struct seninf_ctx *ctx); +int mtk_cam_seninf_poweroff(struct seninf_ctx *ctx); +int mtk_cam_seninf_reset(struct seninf_ctx *ctx, u32 seninf_idx); +int mtk_cam_seninf_set_idle(struct seninf_ctx *ctx); +int mtk_cam_seninf_get_mux_meter(struct seninf_ctx *ctx, u32 mux, + struct mtk_cam_seninf_mux_meter *meter); +ssize_t mtk_cam_seninf_show_status(struct device *dev, + struct device_attribute *attr, char *buf); +int mtk_cam_seninf_switch_to_cammux_inner_page(struct seninf_ctx *ctx, + bool inner); +int mtk_cam_seninf_set_cammux_next_ctrl(struct seninf_ctx *ctx, int src, + int target); +int mtk_cam_seninf_update_mux_pixel_mode(struct seninf_ctx *ctx, u32 mux, + int pixel_mode); +int mtk_cam_seninf_irq_handler(int irq, void *data); +int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable, + int index); +int mtk_cam_seninf_set_cam_mux_dyn_en(struct seninf_ctx *ctx, bool enable, + int cam_mux, int index); +int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index); +int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable, + int index); +int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable, + int cam_mux); +int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx); +int mtk_cam_seninf_debug(struct seninf_ctx *ctx); +int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val); +ssize_t mtk_cam_seninf_show_err_status(struct device *dev, + struct device_attribute *attr, + char *buf); + +#endif /* __MTK_CAM_SENINF_HW_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h new file mode 100644 index 000000000000..2960ea0afd8d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-if.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_IF_H__ +#define __MTK_CAM_SENINF_IF_H__ + +int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd, int pad_id, + int *pixelmode); + +int mtk_cam_seninf_set_pixelmode(struct v4l2_subdev *sd, int pad_id, + int pixelmode); + +int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg); + +int mtk_cam_seninf_get_pixelrate(struct v4l2_subdev *sd, s64 *pixelrate); + +int mtk_cam_seninf_calc_pixelrate(struct device *dev, s64 width, s64 height, + s64 hblank, s64 vblank, int fps_n, int fps_d, + s64 sensor_pixel_rate); + +int mtk_cam_seninf_dump(struct v4l2_subdev *sd); + +unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd, + unsigned int pad); + +#endif /* __MTK_CAM_SENINF_IF_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h new file mode 100644 index 000000000000..65f3ec058fba --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-regs.h @@ -0,0 +1,40 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_REGS_H__ +#define __MTK_CAM_SENINF_REGS_H__ + +#define SENINF_BITS(base, reg, field, val) \ + do { \ + u32 __iomem *__p = (base) + (reg); \ + u32 __v = readl(__p); \ + __v &= ~field##_MASK; \ + __v |= (((val) << field##_SHIFT) & field##_MASK); \ + writel(__v, __p); \ + } while (0) + +#define SENINF_READ_BITS(base, reg, field) \ + ({ \ + u32 __iomem *__p = (base) + (reg); \ + u32 __v = readl(__p); \ + __v &= field##_MASK; \ + __v >>= field##_SHIFT; \ + __v; \ + }) + +#define SENINF_READ_REG(base, reg) \ + ({ \ + u32 __iomem *__p = (base) + (reg); \ + u32 __v = readl(__p); \ + __v; \ + }) + +#define SENINF_WRITE_REG(base, reg, val) \ + do { \ + u32 __iomem *__p = (base) + (reg); \ + writel(val, __p); \ + } while (0) + +#endif /* __MTK_CAM_SENINF_REGS_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c new file mode 100644 index 000000000000..cda62fb7fb84 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.c @@ -0,0 +1,356 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022 MediaTek Inc. + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_cam-seninf.h" +#include "mtk_cam-seninf-route.h" +#include "mtk_cam-seninf-if.h" +#include "mtk_cam-seninf-hw.h" +#include "mtk_cam-seninf-drv.h" +#include "kd_imgsensor_define_v4l2.h" + +#define to_std_fmt_code(code) \ + ((code) & 0xFFFF) + +void mtk_cam_seninf_init_res(struct seninf_core *core) +{ + int i; + + INIT_LIST_HEAD(&core->list_mux); + for (i = 0; i < g_seninf_cfg->mux_num; i++) { + core->mux[i].idx = i; + list_add_tail(&core->mux[i].list, &core->list_mux); + } +} + +struct seninf_mux *mtk_cam_seninf_mux_get(struct seninf_ctx *ctx) +{ + struct seninf_core *core = ctx->core; + struct seninf_mux *ent = NULL; + + mutex_lock(&core->mutex); + + if (!list_empty(&core->list_mux)) { + ent = list_first_entry(&core->list_mux, + struct seninf_mux, list); + list_move_tail(&ent->list, &ctx->list_mux); + } + + mutex_unlock(&core->mutex); + + return ent; +} + +struct seninf_mux *mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx, + int *pref_idx, int pref_cnt) +{ + int i; + struct seninf_core *core = ctx->core; + struct seninf_mux *ent = NULL; + + mutex_lock(&core->mutex); + + list_for_each_entry(ent, &core->list_mux, list) { + for (i = 0; i < pref_cnt; i++) { + if (ent->idx == pref_idx[i]) { + list_move_tail(&ent->list, &ctx->list_mux); + mutex_unlock(&core->mutex); + return ent; + } + } + } + + mutex_unlock(&core->mutex); + + return mtk_cam_seninf_mux_get(ctx); +} + +void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux) +{ + struct seninf_core *core = ctx->core; + + mutex_lock(&core->mutex); + list_move_tail(&mux->list, &core->list_mux); + mutex_unlock(&core->mutex); +} + +void mtk_cam_seninf_get_vcinfo_test(struct seninf_ctx *ctx) +{ + struct seninf_vcinfo *vcinfo = &ctx->vcinfo; + struct seninf_vc *vc; + + vcinfo->cnt = 0; + + if (ctx->is_test_model == 1) { + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_RAW_DATA; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + } else if (ctx->is_test_model == 2) { + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_STAGGER_NE; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_STAGGER_ME; + vc->out_pad = PAD_SRC_RAW1; + vc->group = 0; + + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_STAGGER_SE; + vc->out_pad = PAD_SRC_RAW2; + vc->group = 0; + } else if (ctx->is_test_model == 3) { + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_RAW_DATA; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x30; + vc->feature = VC_PDAF_STATS; + vc->out_pad = PAD_SRC_PDAF0; + vc->group = 0; + } +} + +struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx) +{ + int i; + struct seninf_vcinfo *vcinfo = &ctx->vcinfo; + + for (i = 0; i < vcinfo->cnt; i++) { + if (vcinfo->vc[i].out_pad == idx) + return &vcinfo->vc[i]; + } + + return NULL; +} + +unsigned int mtk_cam_seninf_get_vc_feature(struct v4l2_subdev *sd, + unsigned int pad) +{ + struct seninf_vc *pvc = NULL; + struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev); + + pvc = mtk_cam_seninf_get_vc_by_pad(ctx, pad); + if (pvc) + return pvc->feature; + + return VC_NONE; +} + +int mtk_cam_seninf_get_vcinfo(struct seninf_ctx *ctx) +{ + struct seninf_vcinfo *vcinfo = &ctx->vcinfo; + struct seninf_vc *vc; + + if (!ctx->sensor_sd) + return -EINVAL; + + vcinfo->cnt = 0; + + switch (to_std_fmt_code(ctx->fmt[PAD_SINK].format.code)) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2a; + vc->feature = VC_RAW_DATA; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + break; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2b; + vc->feature = VC_RAW_DATA; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + break; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + vc = &vcinfo->vc[vcinfo->cnt++]; + vc->vc = 0; + vc->dt = 0x2c; + vc->feature = VC_RAW_DATA; + vc->out_pad = PAD_SRC_RAW0; + vc->group = 0; + break; + default: + return -1; + } + + return 0; +} + +void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx) +{ + struct seninf_mux *ent, *tmp; + + list_for_each_entry_safe(ent, tmp, &ctx->list_mux, list) { + mtk_cam_seninf_mux_put(ctx, ent); + } +} + +int mtk_cam_seninf_is_di_enabled(struct seninf_ctx *ctx, u8 ch, u8 dt) +{ + int i; + struct seninf_vc *vc; + + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + if (vc->vc == ch && vc->dt == dt) { + if (media_pad_remote_pad_first(&ctx->pads[vc->out_pad])) + return 1; + + return 0; + } + } + + return 0; +} + +int mtk_cam_seninf_get_pixelmode(struct v4l2_subdev *sd, + int pad_id, int *pixel_mode) +{ + struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev); + struct seninf_vc *vc; + + vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id); + if (!vc) { + pr_info("%s: invalid pad=%d\n", __func__, pad_id); + return -1; + } + + *pixel_mode = vc->pixel_mode; + + return 0; +} + +int mtk_cam_seninf_set_pixelmode(struct v4l2_subdev *sd, + int pad_id, int pixel_mode) +{ + struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev); + struct seninf_vc *vc; + + vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id); + if (!vc) { + pr_info("%s: invalid pad=%d\n", __func__, pad_id); + return -1; + } + + vc->pixel_mode = pixel_mode; + if (ctx->streaming) { + update_isp_clk(ctx); + mtk_cam_seninf_update_mux_pixel_mode(ctx, vc->mux, pixel_mode); + } + + return 0; +} + +static int _mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, + int pad_id, int camtg, bool disable_last) +{ + int old_camtg; + struct seninf_ctx *ctx = container_of(sd, struct seninf_ctx, subdev); + struct seninf_vc *vc; + + if (pad_id < PAD_SRC_RAW0 || pad_id >= PAD_MAXCNT) + return -EINVAL; + + vc = mtk_cam_seninf_get_vc_by_pad(ctx, pad_id); + if (!vc) + return -EINVAL; + + ctx->pad2cam[pad_id] = camtg; + + /* change cam-mux while streaming */ + if (ctx->streaming && vc->cam != camtg) { + if (camtg == 0xff) { + old_camtg = vc->cam; + vc->cam = 0xff; + mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true); + mtk_cam_seninf_set_cammux_next_ctrl(ctx, 0x1f, old_camtg); + mtk_cam_seninf_disable_cammux(ctx, old_camtg); + } else { + /* disable old */ + old_camtg = vc->cam; + /* enable new */ + vc->cam = camtg; + mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true); + mtk_cam_seninf_set_cammux_next_ctrl(ctx, 0x1f, vc->cam); + + mtk_cam_seninf_switch_to_cammux_inner_page(ctx, false); + + mtk_cam_seninf_set_cammux_vc(ctx, vc->cam, + vc->vc, vc->dt, + !!vc->dt, !!vc->dt); + mtk_cam_seninf_set_cammux_src(ctx, vc->mux, vc->cam, + vc->exp_hsize, + vc->exp_vsize); + mtk_cam_seninf_set_cammux_chk_pixel_mode(ctx, + vc->cam, + vc->pixel_mode); + if (old_camtg != 0xff && disable_last) { + /* disable old in next sof */ + mtk_cam_seninf_disable_cammux(ctx, old_camtg); + } + mtk_cam_seninf_cammux(ctx, vc->cam); /* enable in next sof */ + mtk_cam_seninf_switch_to_cammux_inner_page(ctx, true); + mtk_cam_seninf_set_cammux_next_ctrl(ctx, vc->mux, vc->cam); + if (old_camtg != 0xff && disable_last) + mtk_cam_seninf_set_cammux_next_ctrl(ctx, + vc->mux, + old_camtg); + + /* user control sensor fsync after change cam-mux */ + } + + dev_info(ctx->dev, "%s: pad %d mux %d cam %d -> %d\n", + __func__, vc->out_pad, vc->mux, old_camtg, vc->cam); + } else { + dev_info(ctx->dev, "%s: pad_id %d, camtg %d, ctx->streaming %d, vc->cam %d\n", + __func__, pad_id, camtg, ctx->streaming, vc->cam); + } + + return 0; +} + +int mtk_cam_seninf_set_camtg(struct v4l2_subdev *sd, int pad_id, int camtg) +{ + return _mtk_cam_seninf_set_camtg(sd, pad_id, camtg, true); +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h new file mode 100644 index 000000000000..99f6c6e7818d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf-route.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_ROUTE_H__ +#define __MTK_CAM_SENINF_ROUTE_H__ + +#define MAX_MUX_CHANNEL 4 + +void mtk_cam_seninf_init_res(struct seninf_core *core); + +struct seninf_mux *mtk_cam_seninf_mux_get(struct seninf_ctx *ctx); +struct seninf_mux *mtk_cam_seninf_mux_get_pref(struct seninf_ctx *ctx, + int *pref_idx, int pref_cnt); +void mtk_cam_seninf_mux_put(struct seninf_ctx *ctx, struct seninf_mux *mux); +void mtk_cam_seninf_release_mux(struct seninf_ctx *ctx); +void mtk_cam_seninf_get_vcinfo_test(struct seninf_ctx *ctx); +struct seninf_vc *mtk_cam_seninf_get_vc_by_pad(struct seninf_ctx *ctx, int idx); +int mtk_cam_seninf_get_vcinfo(struct seninf_ctx *ctx); +int mtk_cam_seninf_is_di_enabled(struct seninf_ctx *ctx, u8 ch, u8 dt); + +#endif /* __MTK_CAM_SENINF_ROUTE_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h new file mode 100644 index 000000000000..6984e6d1b3ff --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-seninf.h @@ -0,0 +1,170 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_SENINF_H__ +#define __MTK_CAM_SENINF_H__ + +#include +#include +#include + +#include "mtk_cam-seninf-def.h" +#include "kd_imgsensor_define_v4l2.h" +#include "mtk_cam-seninf-regs.h" + +struct seninf_mux { + struct list_head list; + int idx; +}; + +struct seninf_cam_mux { + struct list_head list; + int idx; +}; + +struct seninf_vc { + u8 vc; + u8 dt; + u8 feature; + u8 out_pad; + u8 pixel_mode; + u8 group; + u8 mux; /* allocated per group */ + u8 cam; /* assigned by cam driver */ + u8 enable; + u16 exp_hsize; + u16 exp_vsize; +}; + +struct seninf_vcinfo { + struct seninf_vc vc[SENINF_VC_MAXCNT]; + int cnt; +}; + +struct seninf_dfs { + struct device *dev; + struct regulator *reg; + unsigned long *freqs; + unsigned long *volts; + int cnt; +}; + +struct seninf_core { + struct device *dev; + int pm_domain_cnt; + struct device **pm_domain_devs; + struct clk *clk[CLK_MAXCNT]; + struct seninf_dfs dfs; + struct list_head list; + struct list_head list_mux; /* available mux */ + struct seninf_mux mux[SENINF_MUX_NUM]; + struct mutex mutex; /* protect seninf core operations */ + void __iomem *reg_if; + void __iomem *reg_ana; + int refcnt; + + /* platform properties */ + int cphy_settle_delay_dt; + int dphy_settle_delay_dt; + int settle_delay_ck; + int hs_trail_parameter; + + /* protect variables in irq handler */ + spinlock_t spinlock_irq; + + /* mipi error detection count */ + unsigned int detection_cnt; + /* enable csi irq flag */ + unsigned int csi_irq_en_flag; +}; + +struct seninf_ctx { + struct v4l2_subdev subdev; + struct v4l2_async_notifier notifier; + struct device *dev; + struct v4l2_ctrl_handler ctrl_handler; + struct media_pad pads[PAD_MAXCNT]; + struct v4l2_subdev_format fmt[PAD_MAXCNT]; + struct seninf_core *core; + struct list_head list; + + u32 port; + u32 port_a; + u32 port_b; + u32 port_num; + u32 num_data_lanes; + s64 mipi_pixel_rate; + s64 buffered_pixel_rate; + s64 customized_pixel_rate; + unsigned int m_csi_efuse; + + unsigned int is_4d1c:1; + unsigned int is_cphy:1; + unsigned int is_test_model:4; + unsigned int is_secure:1; + unsigned int sec_info_addr; + u32 seninf_idx; + int pad2cam[PAD_MAXCNT]; + + /* remote sensor */ + struct v4l2_subdev *sensor_sd; + u32 sensor_pad_idx; + + /* provided by sensor */ + struct seninf_vcinfo vcinfo; + int fps_n; + int fps_d; + + /* dfs */ + int isp_freq; + + void __iomem *reg_ana_csi_rx[CSI_PORT_MAX_NUM]; + void __iomem *reg_ana_dphy_top[CSI_PORT_MAX_NUM]; + void __iomem *reg_ana_cphy_top[CSI_PORT_MAX_NUM]; + void __iomem *reg_if_top; + void __iomem *reg_if_ctrl[SENINF_NUM]; + void __iomem *reg_if_cam_mux; + void __iomem *reg_if_cam_mux_gcsr; + void __iomem *reg_if_cam_mux_pcsr[SENINF_CAM_MUX_NUM]; + void __iomem *reg_if_tg[SENINF_NUM]; + void __iomem *reg_if_csi2[SENINF_NUM]; + void __iomem *reg_if_mux[SENINF_MUX_NUM]; + + /* resources */ + struct list_head list_mux; /* work mux */ + struct list_head list_cam_mux; + + /* flags */ + unsigned int streaming:1; + + int cphy_settle_delay_dt; + int dphy_settle_delay_dt; + int settle_delay_ck; + int hs_trail_parameter; + + int open_refcnt; + struct mutex mutex; /* protect seninf context */ + + /* csi irq */ + unsigned int data_not_enough_cnt; + unsigned int err_lane_resync_cnt; + unsigned int crc_err_cnt; + unsigned int ecc_err_double_cnt; + unsigned int ecc_err_corrected_cnt; + /* seninf_mux fifo overrun irq */ + unsigned int fifo_overrun_cnt; + /* cam_mux h/v size irq */ + unsigned int size_err_cnt; + /* error flag */ + unsigned int data_not_enough_flag; + unsigned int err_lane_resync_flag; + unsigned int crc_err_flag; + unsigned int ecc_err_double_flag; + unsigned int ecc_err_corrected_flag; + unsigned int fifo_overrun_flag; + unsigned int size_err_flag; +}; + +#endif /* __MTK_CAM_SENINF_H__ */ From patchwork Wed Oct 9 11:15:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shu-hsiang Yang X-Patchwork-Id: 13828244 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id E5989CEDD87 for ; Wed, 9 Oct 2024 11:58:28 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=feYTh5N/CZvxiWWNxiO80BwiDZSBYicbkLOe9DUTMm0=; b=1nSxC/wOlbyftQb2/5d0py/zkm 50jCDQqzdpA5+hCINPzL1YrZb2zfQhc/RbzsN2CbHqb++Zzvn2lnuObjKjbc/l5wxfcX8SHe/ZOIk LjsxlKzwbnKJIe9QzF/jLPlmnoTz4fGLkZZBqh6BTyY5opE2kdPAs6oBpCxPlXVXn7QtT6e5tLyS4 hyywVwA2zExkYz1opfbO8b8MH8wuvNYoXrDJZcAdf9vvjEhJLc7eCZlEXodKugyzzpC3+2cj+h6OX vnQyOT8KiMdSR5o0Q3GbaXnX6UtK/5bf7j+uX4H8iBUhowW6Dm4Ec0xtCEqz+abU2SVNUK9gSPHKk GuJrbVKQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syVKK-000000097cq-0u6k; Wed, 09 Oct 2024 11:58:00 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUv3-000000094SG-2nEN for linux-arm-kernel@bombadil.infradead.org; Wed, 09 Oct 2024 11:31:54 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:CC:To:From:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=feYTh5N/CZvxiWWNxiO80BwiDZSBYicbkLOe9DUTMm0=; b=Muix+j+1683XZ75bKFMfp0sZSd 0vqRuQw5jca6ev93RzpxprDGgFQJ2y7eGEAJE42Z7wTMj9ePMybjP5CQErIqLP/LSCpeeepJBuXil rHzog7IQ/GvoFMjFMQ32Ek546kJasExv6dx9Xrfmz/AkVLFGjGrgeQC0rzMcMxu0KViIDXC+X/RrO URT1wd8RK3mzKRJ5COC6YLLgPQ12c8RWyijxbfdaY1W9lyH3XsVU8pJI9VouinDvoFXIl1PTslcS2 2GiLGcCX9s83bBTL7L93c8Qi3vCmamfi53dOvYWKWOJycPL3avPTheIxdbv5RMeeTlzsUxIa7kU4r stHRlGuQ==; Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUuy-00000004vgA-1r7m for linux-arm-kernel@lists.infradead.org; Wed, 09 Oct 2024 11:31:52 +0000 X-UUID: e3e710f0862f11efb3adad29d29602c1-20241009 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=feYTh5N/CZvxiWWNxiO80BwiDZSBYicbkLOe9DUTMm0=; b=fv3JwfBVxMzwhKteXTy529J1/Wlj9HYj3TYiXhG61xfIhhPJRjKvsLrPVn8jDmLpvStPjDKtaDZ8ZWM/cQIRj6JBFzxVEDTjVEFGU9gm5+ZpuDgW6JBESFMu3jDtIzYifu6xwcUBSj56CFdUQmlIFuBPxxYBt4CTEXbFEQeJIYA=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:42c15355-6cbc-4428-ba3c-83d9898fb78d,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:6dc6a47,CLOUDID:4d8a0041-8751-41b2-98dd-475503d45150,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:1,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 2,OSH X-CID-BAS: 2,OSH,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e3e710f0862f11efb3adad29d29602c1-20241009 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 903174948; Wed, 09 Oct 2024 04:16:11 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by mtkmbs13n2.mediatek.inc (172.21.101.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Wed, 9 Oct 2024 19:16:08 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Wed, 9 Oct 2024 19:16:08 +0800 From: Shu-hsiang Yang To: Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Sumit Semwal , Christian Konig CC: , , , , , , , , , , , , , Shu-hsiang Yang Subject: [PATCH v1 07/10] media: platform: mediatek: add isp_7x video ops Date: Wed, 9 Oct 2024 19:15:48 +0800 Message-ID: <20241009111551.27052-8-Shu-hsiang.Yang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> References: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_123149_591089_6BFE5500 X-CRM114-Status: GOOD ( 28.31 ) 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 Introduces the V4L2 video interface and feature management for the MediaTek ISP7x CAMSYS. These interfaces include various functionalities, such as video operation initialization and registration. They also manage MediaTek-specific formats and handle buffers for MediaTek camera video devices. This integrates CAMSYS functionalities to be compatible with the V4L2 framework. Signed-off-by: Shu-hsiang Yang --- .../isp/isp_7x/camsys/mtk_cam-feature.c | 40 + .../isp/isp_7x/camsys/mtk_cam-feature.h | 26 + .../isp/isp_7x/camsys/mtk_cam-video.c | 1817 +++++++++++++++++ .../isp/isp_7x/camsys/mtk_cam-video.h | 224 ++ 4 files changed, 2107 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c new file mode 100644 index 000000000000..639c1e1671fc --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.c @@ -0,0 +1,40 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2022 MediaTek Inc. + +#include "mtk_cam-feature.h" + +struct mtk_cam_ctx; + +/* + * mtk_cam_is_[feature] is used for raw_feature, + * which must not change during streaming. + */ + +static bool mtk_cam_is_no_seninf(struct mtk_cam_ctx *ctx) +{ + return !media_pad_remote_pad_first(&ctx->pipe->pads[MTK_RAW_SINK]); +} + +bool mtk_cam_is_pure_m2m(struct mtk_cam_ctx *ctx) +{ + if (!ctx->used_raw_num) + return false; + + if (ctx->pipe->feature_pending & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK || + mtk_cam_is_no_seninf(ctx)) + return true; + else + return false; +} + +bool mtk_cam_is_m2m(struct mtk_cam_ctx *ctx) +{ + if (!ctx->used_raw_num) + return false; + + if (mtk_cam_is_no_seninf(ctx)) + return true; + else + return mtk_cam_feature_is_m2m(ctx->pipe->feature_pending); +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h new file mode 100644 index 000000000000..dd5acc754765 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-feature.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_FEATURE_H +#define __MTK_CAM_FEATURE_H + +#include "mtk_cam.h" +#include "mtk_cam-raw.h" + +static inline bool mtk_cam_feature_is_m2m(int feature) +{ + return !!(feature & MTK_CAM_FEATURE_OFFLINE_M2M_MASK) || + !!(feature & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK); +} + +static inline bool mtk_cam_feature_is_pure_m2m(int feature) +{ + return !!(feature & MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK); +} + +bool mtk_cam_is_m2m(struct mtk_cam_ctx *ctx); +bool mtk_cam_is_pure_m2m(struct mtk_cam_ctx *ctx); + +#endif /*__MTK_CAM_FEATURE_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c new file mode 100644 index 000000000000..95cdf1a2fb4c --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.c @@ -0,0 +1,1817 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2022 MediaTek Inc. + +#include +#include +#include +#include +#include + +#include "mtk_cam.h" +#include "mtk_cam-feature.h" +#include "mtk_cam-video.h" +#include "mtk_camera-v4l2-controls.h" +#include "mtk_cam-ufbc-def.h" + +/* + * differt dma (fmt) would have different bus_size + * align xsize(bytes per line) with [bus_size * pixel_mode] + */ +static inline int mtk_cam_is_fullg(unsigned int ipi_fmt) +{ + return (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER8) || + (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER10) || + (ipi_fmt == MTKCAM_IPI_IMG_FMT_FG_BAYER12); +} + +static inline +unsigned int mtk_cam_dma_bus_size(int bpp, int pixel_mode_shift, int is_fg) +{ + unsigned int bus_size = ALIGN(bpp, 16) << pixel_mode_shift; + + if (is_fg) + bus_size <<= 1; + return bus_size / 8; /* in bytes */ +} + +static inline +unsigned int mtk_cam_yuv_dma_bus_size(int bpp, int pixel_mode_shift) +{ + unsigned int bus_size = ALIGN(bpp, 32) << pixel_mode_shift; + + return bus_size / 8; /* in bytes */ +} + +static inline +unsigned int mtk_cam_dmao_xsize(int w, unsigned int ipi_fmt, int pixel_mode_shift) +{ + const unsigned int is_fg = mtk_cam_is_fullg(ipi_fmt); + const unsigned int bpp = mtk_cam_get_pixel_bits(ipi_fmt); + const unsigned int bytes = is_fg ? + DIV_ROUND_UP(w * bpp * 3 / 2, 8) : DIV_ROUND_UP(w * bpp, 8); + const unsigned int bus_size = + mtk_cam_dma_bus_size(bpp, pixel_mode_shift, is_fg); + + return ALIGN(bytes, bus_size); +} + +static void mtk_cam_release_all_buffer(struct mtk_cam_device *cam) +{ + struct mtk_cam_buffer *buf, *tmp; + + spin_lock(&cam->dma_pending_lock); + list_for_each_entry_safe(buf, tmp, &cam->dma_pending, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock(&cam->dma_pending_lock); + + spin_lock(&cam->dma_processing_lock); + list_for_each_entry_safe(buf, tmp, &cam->dma_processing, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock(&cam->dma_processing_lock); +} + +static int mtk_cam_vb2_queue_setup(struct vb2_queue *vq, + unsigned int *num_buffers, + unsigned int *num_planes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct mtk_cam_device *cam = vb2_get_drv_priv(vq); + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq); + struct mtk_raw_pipeline *raw_pipeline; + unsigned int max_buffer_count = node->desc.max_buf_count; + const struct v4l2_format *fmt = &node->active_fmt; + unsigned int size; + int i; + + /* Check the limitation of buffer size */ + if (max_buffer_count) + *num_buffers = clamp_val(*num_buffers, 1, max_buffer_count); + + if (node->desc.smem_alloc) + vq->dma_attrs |= DMA_ATTR_NO_KERNEL_MAPPING; + + if (vq->type == V4L2_BUF_TYPE_META_OUTPUT || + vq->type == V4L2_BUF_TYPE_META_CAPTURE) + size = fmt->fmt.meta.buffersize; + else + size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + /* Add for q.create_bufs with fmt.g_sizeimage(p) / 2 test */ + if (*num_planes) { + if (sizes[0] < size || *num_planes != 1) + return -EINVAL; + } else { + /* Set default as one plane */ + *num_planes = 1; + sizes[0] = size; + + if (is_raw_subdev(node->uid.pipe_id)) { + raw_pipeline = + mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id); + + if (raw_pipeline && + raw_pipeline->user_res.raw_res.feature && + fmt->fmt.pix_mp.num_planes > 1) { + *num_planes = fmt->fmt.pix_mp.num_planes; + for (i = 0; i < *num_planes; i++) + sizes[i] = size; + } + } + } + + return 0; +} + +static int mtk_cam_vb2_buf_init(struct vb2_buffer *vb) +{ + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + struct mtk_cam_buffer *buf; + struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = cam->raw.devs[0]; + dma_addr_t addr; + + buf = mtk_cam_vb2_buf_to_dev_buf(vb); + buf->daddr = vb2_dma_contig_plane_dma_addr(vb, 0); + buf->scp_addr = 0; + + /* SCP address is only valid for meta input buffer */ + if (!node->desc.smem_alloc) + return 0; + + /* Use coherent address to get iova address */ + addr = dma_map_resource(dev, buf->daddr, vb->planes[0].length, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(dev, addr)) { + dev_err(dev, "failed to map addr:%pad\n", &buf->daddr); + return -EFAULT; + } + buf->scp_addr = buf->daddr; + buf->daddr = addr; + + return 0; +} + +static int mtk_cam_vb2_buf_prepare(struct vb2_buffer *vb) +{ + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); + const struct v4l2_format *fmt = &node->active_fmt; + unsigned int size; + + dev_dbg(vb->vb2_queue->dev, "%s: %s\n", __func__, node->desc.name); + + if (vb->vb2_queue->type == V4L2_BUF_TYPE_META_OUTPUT || + vb->vb2_queue->type == V4L2_BUF_TYPE_META_CAPTURE) + size = fmt->fmt.meta.buffersize; + else + size = fmt->fmt.pix_mp.plane_fmt[0].sizeimage; + + if (vb2_plane_size(vb, 0) < size) { + dev_info(vb->vb2_queue->dev, + "plane size is too small:%lu<%u\n", + vb2_plane_size(vb, 0), size); + } + + if (V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) { + if ((vb2_get_plane_payload(vb, 0) != size) && + vb->vb2_queue->streaming) { + dev_dbg(vb->vb2_queue->dev, + "plane payload is mismatch:%lu:%u\n", + vb2_get_plane_payload(vb, 0), size); + } + return 0; + } + + v4l2_buf->field = V4L2_FIELD_NONE; + vb2_set_plane_payload(vb, 0, size); + + return 0; +} + +static int mtk_cam_vb2_start_streaming(struct vb2_queue *vq, + unsigned int count) +{ + struct mtk_cam_device *cam = vb2_get_drv_priv(vq); + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq); + struct media_entity *entity = &node->vdev.entity; + struct mtk_cam_ctx *ctx = NULL; + struct device *dev = cam->dev; + int ret; + + /* check entity is linked */ + if (!node->enabled) { + dev_info(cam->dev, + "%s: stream on failed, node is not enabled\n", + node->desc.name); + ret = -ENOLINK; + goto fail_return_buffer; + } + + if (!media_entity_is_streaming(entity)) { + ctx = mtk_cam_start_ctx(cam, node); + if (!ctx) { + ret = -ENOLINK; + goto fail_return_buffer; + } + } else { + ctx = mtk_cam_find_ctx(cam, entity); + if (WARN_ON(!ctx)) { + ret = -ENOLINK; + goto fail_return_buffer; + } + } + + cam->streaming_pipe |= (1 << node->uid.pipe_id); + ctx->streaming_pipe |= (1 << node->uid.pipe_id); + ctx->streaming_node_cnt++; + + if (ctx->streaming_node_cnt == 1) + if (is_raw_subdev(node->uid.pipe_id)) { + if (!isp_composer_create_session(ctx)) { + ctx->session_created = 1; + } else { + complete(&ctx->session_complete); + ret = -EBUSY; + goto fail_stop_ctx; + } + } + + dev_dbg(dev, "%s:%s:ctx(%d): node:%d count info:%d\n", __func__, + node->desc.name, ctx->stream_id, node->desc.id, + ctx->streaming_node_cnt); + + ret = mtk_cam_ctx_stream_on(ctx, node); + if (ret) + goto fail_destroy_session; + + mtk_cam_buf_try_queue(ctx); + + return 0; + +fail_destroy_session: + if (ctx->session_created) + isp_composer_destroy_session(ctx); +fail_stop_ctx: + ctx->streaming_node_cnt--; + ctx->streaming_pipe &= ~(1 << node->uid.pipe_id); + cam->streaming_pipe &= ~(1 << node->uid.pipe_id); + mtk_cam_dev_req_cleanup(ctx, node->uid.pipe_id, VB2_BUF_STATE_QUEUED); + mtk_cam_stop_ctx(ctx, node); +fail_return_buffer: + mtk_cam_release_all_buffer(cam); + /* relese bufs by request */ + return ret; +} + +static void mtk_cam_vb2_stop_streaming(struct vb2_queue *vq) +{ + struct mtk_cam_device *cam = vb2_get_drv_priv(vq); + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vq); + struct device *dev = cam->dev; + struct mtk_cam_ctx *ctx; + + ctx = mtk_cam_find_ctx(cam, &node->vdev.entity); + if (WARN_ON(!ctx)) { + /* the ctx is stop, media_pipeline_stop is called */ + mtk_cam_dev_req_clean_pending(cam, node->uid.pipe_id, + VB2_BUF_STATE_ERROR); + return; + } + + dev_dbg(dev, "%s:%s:ctx(%d): node:%d count info:%d\n", __func__, + node->desc.name, ctx->stream_id, node->desc.id, + ctx->streaming_node_cnt); + + mtk_cam_ctx_stream_off(ctx, node); + + if (cam->streaming_pipe & (1 << node->uid.pipe_id)) { + /* NOTE: take multi-pipelines case into consideration */ + /* Moreover, must clean bit mask before req cleanup */ + /* Otherwise, would cause req not removed in pending list */ + cam->streaming_pipe &= ~(1 << node->uid.pipe_id); + mtk_cam_dev_req_cleanup(ctx, node->uid.pipe_id, VB2_BUF_STATE_ERROR); + } + + /* all bufs of node should be return by per requests */ + mtk_cam_release_all_buffer(ctx->cam); + + /* NOTE: take multi-pipelines case into consideration */ + cam->streaming_pipe &= ~(1 << node->uid.pipe_id); + ctx->streaming_node_cnt--; + if (ctx->streaming_node_cnt) + return; + + mtk_cam_stop_ctx(ctx, node); +} + +int is_mtk_format(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_YUYV10: + case V4L2_PIX_FMT_YVYU10: + case V4L2_PIX_FMT_UYVY10: + case V4L2_PIX_FMT_VYUY10: + case V4L2_PIX_FMT_YUYV12: + case V4L2_PIX_FMT_YVYU12: + case V4L2_PIX_FMT_UYVY12: + case V4L2_PIX_FMT_VYUY12: + case V4L2_PIX_FMT_MTISP_YUYV10P: + case V4L2_PIX_FMT_MTISP_YVYU10P: + case V4L2_PIX_FMT_MTISP_UYVY10P: + case V4L2_PIX_FMT_MTISP_VYUY10P: + case V4L2_PIX_FMT_MTISP_YUYV12P: + case V4L2_PIX_FMT_MTISP_YVYU12P: + case V4L2_PIX_FMT_MTISP_UYVY12P: + case V4L2_PIX_FMT_MTISP_VYUY12P: + case V4L2_PIX_FMT_NV12_10: + case V4L2_PIX_FMT_NV21_10: + case V4L2_PIX_FMT_NV16_10: + case V4L2_PIX_FMT_NV61_10: + case V4L2_PIX_FMT_NV12_12: + case V4L2_PIX_FMT_NV21_12: + case V4L2_PIX_FMT_NV16_12: + case V4L2_PIX_FMT_NV61_12: + case V4L2_PIX_FMT_MTISP_NV12_10P: + case V4L2_PIX_FMT_MTISP_NV21_10P: + case V4L2_PIX_FMT_MTISP_NV16_10P: + case V4L2_PIX_FMT_MTISP_NV61_10P: + case V4L2_PIX_FMT_MTISP_NV12_12P: + case V4L2_PIX_FMT_MTISP_NV21_12P: + case V4L2_PIX_FMT_MTISP_NV16_12P: + case V4L2_PIX_FMT_MTISP_NV61_12P: + case V4L2_PIX_FMT_MTISP_NV12_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_UFBC: + case V4L2_PIX_FMT_MTISP_NV12_10_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_10_UFBC: + case V4L2_PIX_FMT_MTISP_NV12_12_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_12_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER8_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER10_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER12_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER14_UFBC: + case V4L2_PIX_FMT_MTISP_SGRB8F: + case V4L2_PIX_FMT_MTISP_SGRB10F: + case V4L2_PIX_FMT_MTISP_SGRB12F: + return 1; + default: + return 0; + } +} + +int is_yuv_ufo(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_MTISP_NV12_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_UFBC: + case V4L2_PIX_FMT_MTISP_NV12_10_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_10_UFBC: + case V4L2_PIX_FMT_MTISP_NV12_12_UFBC: + case V4L2_PIX_FMT_MTISP_NV21_12_UFBC: + return 1; + default: + return 0; + } +} + +int is_raw_ufo(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_MTISP_BAYER8_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER10_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER12_UFBC: + case V4L2_PIX_FMT_MTISP_BAYER14_UFBC: + return 1; + default: + return 0; + } +} + +int is_fullg_rb(u32 pixelformat) +{ + switch (pixelformat) { + case V4L2_PIX_FMT_MTISP_SGRB8F: + case V4L2_PIX_FMT_MTISP_SGRB10F: + case V4L2_PIX_FMT_MTISP_SGRB12F: + return 1; + default: + return 0; + } +} + +const struct mtk_format_info *mtk_format_info(u32 format) +{ + static const struct mtk_format_info formats[] = { + /* YUV planar formats */ + { .format = V4L2_PIX_FMT_NV12_10, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV21_10, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV16_10, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV61_10, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_YUYV10, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_YVYU10, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_UYVY10, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_VYUY10, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV12_12, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV21_12, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV16_12, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_NV61_12, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_YUYV12, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_YVYU12, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_UYVY12, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_VYUY12, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 2, .bit_r_den = 1 }, + /* YUV packed formats */ + { .format = V4L2_PIX_FMT_MTISP_YUYV10P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_YVYU10P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_UYVY10P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_VYUY10P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV12_10P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV21_10P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV16_10P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV61_10P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_YUYV12P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_YVYU12P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_UYVY12P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_VYUY12P, + .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_NV12_12P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_NV21_12P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_NV16_12P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_NV61_12P, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + /* YUV UFBC formats */ + { .format = V4L2_PIX_FMT_MTISP_NV12_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_MTISP_NV21_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 2, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_MTISP_NV12_10_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV21_10_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_NV12_12_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_NV21_12_UFBC, + .mem_planes = 1, .comp_planes = 2, .bpp = { 1, 2, 0, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_BAYER8_UFBC, + .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, + .hdiv = 1, .vdiv = 1, .bit_r_num = 1, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_MTISP_BAYER10_UFBC, + .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, + .hdiv = 1, .vdiv = 1, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_BAYER12_UFBC, + .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, + .hdiv = 1, .vdiv = 1, .bit_r_num = 3, .bit_r_den = 2 }, + { .format = V4L2_PIX_FMT_MTISP_BAYER14_UFBC, + .mem_planes = 1, .comp_planes = 1, .bpp = { 1, 0, 0, 0 }, + .hdiv = 1, .vdiv = 1, .bit_r_num = 7, .bit_r_den = 4 }, + /* Full-G RGB formats */ + { .format = V4L2_PIX_FMT_MTISP_SGRB8F, + .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 1, .bit_r_den = 1 }, + { .format = V4L2_PIX_FMT_MTISP_SGRB10F, + .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 5, .bit_r_den = 4 }, + { .format = V4L2_PIX_FMT_MTISP_SGRB12F, + .mem_planes = 1, .comp_planes = 3, .bpp = { 1, 1, 1, 0 }, + .hdiv = 2, .vdiv = 2, .bit_r_num = 3, .bit_r_den = 2 }, + }; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(formats); ++i) + if (formats[i].format == format) + return &formats[i]; + return NULL; +} + +static void mtk_cam_vb2_buf_queue(struct vb2_buffer *vb) +{ + struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue); + struct mtk_cam_buffer *buf = mtk_cam_vb2_buf_to_dev_buf(vb); + struct mtk_cam_request *req = to_mtk_cam_req(vb->request); + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + struct mtk_raw_pde_config *pde_cfg; + struct device *dev = cam->dev; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_meta_input *meta_in; + struct mtkcam_ipi_meta_output *meta_out; + struct mtk_cam_ctx *ctx; + unsigned int pipe_id; + unsigned int desc_id; + unsigned int dma_port = node->desc.dma_port; + + if (!vb->vb2_queue->uses_requests) { + spin_lock(&cam->dma_pending_lock); + list_add_tail(&buf->list, &cam->dma_pending); + spin_unlock(&cam->dma_pending_lock); + buf->state.estate = E_BUF_STATE_QUEUED; + if (media_entity_is_streaming(&node->vdev.entity)) { + ctx = mtk_cam_find_ctx(cam, &node->vdev.entity); + mtk_cam_buf_try_queue(ctx); + } + return; + } + + dma_port = node->desc.dma_port; + pipe_id = node->uid.pipe_id; + req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0); + frame_param = &req_stream_data->frame_params; + mtk_cam_s_data_set_vbuf(req_stream_data, buf, node->desc.id); + + /* update buffer internal address */ + switch (dma_port) { + case MTKCAM_IPI_RAW_META_STATS_CFG: + desc_id = node->desc.id - MTK_RAW_SINK_NUM; + meta_in = &frame_param->meta_inputs[desc_id]; + meta_in->buf.size = node->active_fmt.fmt.meta.buffersize; + meta_in->buf.iova = buf->daddr; + meta_in->buf.scp_addr = buf->scp_addr; + meta_in->uid.id = dma_port; + break; + case MTKCAM_IPI_RAW_META_STATS_0: + case MTKCAM_IPI_RAW_META_STATS_1: + case MTKCAM_IPI_RAW_META_STATS_2: + pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config; + desc_id = node->desc.id - MTK_RAW_META_OUT_BEGIN; + meta_out = &frame_param->meta_outputs[desc_id]; + meta_out->buf.size = node->active_fmt.fmt.meta.buffersize; + meta_out->buf.iova = buf->daddr; + meta_out->buf.scp_addr = buf->scp_addr; + meta_out->uid.id = dma_port; + camsys_set_meta_stats_info(dma_port, vb, pde_cfg); + break; + default: + dev_dbg(dev, "%s:pipe(%d):buffer with invalid port(%d)\n", + __func__, pipe_id, dma_port); + break; + } +} + +static void mtk_cam_vb2_buf_cleanup(struct vb2_buffer *vb) +{ + struct mtk_cam_video_device *node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + struct mtk_cam_buffer *buf; + struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue); + struct device *dev = cam->raw.devs[0]; + + /* SCP address is only valid for meta input buffer */ + if (!node->desc.smem_alloc) + return; + + buf = mtk_cam_vb2_buf_to_dev_buf(vb); + dma_unmap_page_attrs(dev, buf->daddr, vb->planes[0].length, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); +} + +static void mtk_cam_vb2_request_complete(struct vb2_buffer *vb) +{ + struct mtk_cam_device *cam = vb2_get_drv_priv(vb->vb2_queue); + + dev_dbg(vb->vb2_queue->dev, "camsys | request %s\n", __func__); + + v4l2_ctrl_request_complete(vb->req_obj.req, cam->v4l2_dev.ctrl_handler); +} + +static int mtk_cam_vb2_buf_out_validate(struct vb2_buffer *vb) +{ + struct vb2_v4l2_buffer *v4l2_buf = to_vb2_v4l2_buffer(vb); + + if (vb->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { + if (v4l2_buf->field == V4L2_FIELD_ANY) + v4l2_buf->field = V4L2_FIELD_NONE; + + if (v4l2_buf->field != V4L2_FIELD_NONE) + return -EINVAL; + } + return 0; +} + +static const struct vb2_ops mtk_cam_vb2_ops = { + .queue_setup = mtk_cam_vb2_queue_setup, + + .wait_prepare = vb2_ops_wait_prepare, + .wait_finish = vb2_ops_wait_finish, + + .buf_out_validate = mtk_cam_vb2_buf_out_validate, + .buf_init = mtk_cam_vb2_buf_init, + .buf_prepare = mtk_cam_vb2_buf_prepare, + + .start_streaming = mtk_cam_vb2_start_streaming, + .stop_streaming = mtk_cam_vb2_stop_streaming, + + .buf_queue = mtk_cam_vb2_buf_queue, + .buf_cleanup = mtk_cam_vb2_buf_cleanup, + .buf_request_complete = mtk_cam_vb2_request_complete, +}; + +static const struct v4l2_file_operations mtk_cam_v4l2_fops = { + .owner = THIS_MODULE, + .unlocked_ioctl = video_ioctl2, + .open = v4l2_fh_open, + .release = vb2_fop_release, + .poll = vb2_fop_poll, + .mmap = vb2_fop_mmap, +#ifdef CONFIG_COMPAT + .compat_ioctl32 = v4l2_compat_ioctl32, +#endif +}; + +unsigned int mtk_cam_get_sensor_pixel_id(unsigned int fmt) +{ + switch (fmt & SENSOR_FMT_MASK) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SBGGR14_1X14: + return MTKCAM_IPI_BAYER_PXL_ID_B; + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGBRG14_1X14: + return MTKCAM_IPI_BAYER_PXL_ID_GB; + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SGRBG14_1X14: + return MTKCAM_IPI_BAYER_PXL_ID_GR; + case MEDIA_BUS_FMT_SRGGB8_1X8: + case MEDIA_BUS_FMT_SRGGB10_1X10: + case MEDIA_BUS_FMT_SRGGB12_1X12: + case MEDIA_BUS_FMT_SRGGB14_1X14: + return MTKCAM_IPI_BAYER_PXL_ID_R; + default: + return MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN; + } +} + +unsigned int mtk_cam_get_sensor_fmt(unsigned int fmt) +{ + switch (fmt & SENSOR_FMT_MASK) { + case MEDIA_BUS_FMT_SBGGR8_1X8: + case MEDIA_BUS_FMT_SGBRG8_1X8: + case MEDIA_BUS_FMT_SGRBG8_1X8: + case MEDIA_BUS_FMT_SRGGB8_1X8: + return MTKCAM_IPI_IMG_FMT_BAYER8; + case MEDIA_BUS_FMT_SBGGR10_1X10: + case MEDIA_BUS_FMT_SGBRG10_1X10: + case MEDIA_BUS_FMT_SGRBG10_1X10: + case MEDIA_BUS_FMT_SRGGB10_1X10: + return MTKCAM_IPI_IMG_FMT_BAYER10; + case MEDIA_BUS_FMT_SBGGR12_1X12: + case MEDIA_BUS_FMT_SGBRG12_1X12: + case MEDIA_BUS_FMT_SGRBG12_1X12: + case MEDIA_BUS_FMT_SRGGB12_1X12: + return MTKCAM_IPI_IMG_FMT_BAYER12; + case MEDIA_BUS_FMT_SBGGR14_1X14: + case MEDIA_BUS_FMT_SGBRG14_1X14: + case MEDIA_BUS_FMT_SGRBG14_1X14: + case MEDIA_BUS_FMT_SRGGB14_1X14: + return MTKCAM_IPI_IMG_FMT_BAYER14; + default: + return MTKCAM_IPI_IMG_FMT_UNKNOWN; + } +} + +unsigned int mtk_cam_get_pixel_bits(unsigned int ipi_fmt) +{ + switch (ipi_fmt) { + case MTKCAM_IPI_IMG_FMT_BAYER8: + case MTKCAM_IPI_IMG_FMT_FG_BAYER8: + return 8; + case MTKCAM_IPI_IMG_FMT_BAYER10: + case MTKCAM_IPI_IMG_FMT_FG_BAYER10: + case MTKCAM_IPI_IMG_FMT_BAYER10_MIPI: + return 10; + case MTKCAM_IPI_IMG_FMT_BAYER12: + case MTKCAM_IPI_IMG_FMT_FG_BAYER12: + return 12; + case MTKCAM_IPI_IMG_FMT_BAYER14: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER14: + return 14; + case MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED: + case MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED: + case MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED: + case MTKCAM_IPI_IMG_FMT_BAYER16: + case MTKCAM_IPI_IMG_FMT_YUYV: + case MTKCAM_IPI_IMG_FMT_YVYU: + case MTKCAM_IPI_IMG_FMT_UYVY: + case MTKCAM_IPI_IMG_FMT_VYUY: + return 16; + case MTKCAM_IPI_IMG_FMT_Y8: + case MTKCAM_IPI_IMG_FMT_YUV_422_2P: + case MTKCAM_IPI_IMG_FMT_YVU_422_2P: + case MTKCAM_IPI_IMG_FMT_YUV_422_3P: + case MTKCAM_IPI_IMG_FMT_YVU_422_3P: + case MTKCAM_IPI_IMG_FMT_YUV_420_2P: + case MTKCAM_IPI_IMG_FMT_YVU_420_2P: + case MTKCAM_IPI_IMG_FMT_YUV_420_3P: + case MTKCAM_IPI_IMG_FMT_YVU_420_3P: + return 8; + case MTKCAM_IPI_IMG_FMT_YUYV_Y210: + case MTKCAM_IPI_IMG_FMT_YVYU_Y210: + case MTKCAM_IPI_IMG_FMT_UYVY_Y210: + case MTKCAM_IPI_IMG_FMT_VYUY_Y210: + return 32; + case MTKCAM_IPI_IMG_FMT_YUV_P210: + case MTKCAM_IPI_IMG_FMT_YVU_P210: + case MTKCAM_IPI_IMG_FMT_YUV_P010: + case MTKCAM_IPI_IMG_FMT_YVU_P010: + case MTKCAM_IPI_IMG_FMT_YUV_P212: + case MTKCAM_IPI_IMG_FMT_YVU_P212: + case MTKCAM_IPI_IMG_FMT_YUV_P012: + case MTKCAM_IPI_IMG_FMT_YVU_P012: + return 16; + case MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED: + return 20; + case MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED: + return 10; + case MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED: + return 12; + case MTKCAM_IPI_IMG_FMT_RGB_8B_3P: + case MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P: + case MTKCAM_IPI_IMG_FMT_UFBC_NV12: + case MTKCAM_IPI_IMG_FMT_UFBC_NV21: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER8: + return 8; + case MTKCAM_IPI_IMG_FMT_RGB_10B_3P_PACKED: + case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED: + case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010: + case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER10: + return 10; + case MTKCAM_IPI_IMG_FMT_RGB_12B_3P_PACKED: + case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED: + case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012: + case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER12: + return 12; + case MTKCAM_IPI_IMG_FMT_RGB_10B_3P: + case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P: + case MTKCAM_IPI_IMG_FMT_RGB_12B_3P: + case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P: + return 16; + default: + break; + } + pr_debug("not supported ipi-fmt 0x%08x", ipi_fmt); + + return -1; +} + +unsigned int mtk_cam_get_img_fmt(unsigned int fourcc) +{ + switch (fourcc) { + case V4L2_PIX_FMT_GREY: + return MTKCAM_IPI_IMG_FMT_Y8; + case V4L2_PIX_FMT_YUYV: + return MTKCAM_IPI_IMG_FMT_YUYV; + case V4L2_PIX_FMT_YVYU: + return MTKCAM_IPI_IMG_FMT_YVYU; + case V4L2_PIX_FMT_NV16: + return MTKCAM_IPI_IMG_FMT_YUV_422_2P; + case V4L2_PIX_FMT_NV61: + return MTKCAM_IPI_IMG_FMT_YVU_422_2P; + case V4L2_PIX_FMT_NV12: + return MTKCAM_IPI_IMG_FMT_YUV_420_2P; + case V4L2_PIX_FMT_NV21: + return MTKCAM_IPI_IMG_FMT_YVU_420_2P; + case V4L2_PIX_FMT_YUV422P: + return MTKCAM_IPI_IMG_FMT_YUV_422_3P; + case V4L2_PIX_FMT_YUV420: + return MTKCAM_IPI_IMG_FMT_YUV_420_3P; + case V4L2_PIX_FMT_YVU420: + return MTKCAM_IPI_IMG_FMT_YVU_420_3P; + case V4L2_PIX_FMT_NV12_10: + return MTKCAM_IPI_IMG_FMT_YUV_P010; + case V4L2_PIX_FMT_NV21_10: + return MTKCAM_IPI_IMG_FMT_YVU_P010; + case V4L2_PIX_FMT_NV16_10: + return MTKCAM_IPI_IMG_FMT_YUV_P210; + case V4L2_PIX_FMT_NV61_10: + return MTKCAM_IPI_IMG_FMT_YVU_P210; + case V4L2_PIX_FMT_MTISP_NV12_10P: + return MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED; + case V4L2_PIX_FMT_MTISP_NV21_10P: + return MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED; + case V4L2_PIX_FMT_MTISP_NV16_10P: + return MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED; + case V4L2_PIX_FMT_MTISP_NV61_10P: + return MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED; + case V4L2_PIX_FMT_YUYV10: + return MTKCAM_IPI_IMG_FMT_YUYV_Y210; + case V4L2_PIX_FMT_YVYU10: + return MTKCAM_IPI_IMG_FMT_YVYU_Y210; + case V4L2_PIX_FMT_UYVY10: + return MTKCAM_IPI_IMG_FMT_UYVY_Y210; + case V4L2_PIX_FMT_VYUY10: + return MTKCAM_IPI_IMG_FMT_VYUY_Y210; + case V4L2_PIX_FMT_MTISP_YUYV10P: + return MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED; + case V4L2_PIX_FMT_MTISP_YVYU10P: + return MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED; + case V4L2_PIX_FMT_MTISP_UYVY10P: + return MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED; + case V4L2_PIX_FMT_MTISP_VYUY10P: + return MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED; + case V4L2_PIX_FMT_NV12_12: + return MTKCAM_IPI_IMG_FMT_YUV_P012; + case V4L2_PIX_FMT_NV21_12: + return MTKCAM_IPI_IMG_FMT_YVU_P012; + case V4L2_PIX_FMT_NV16_12: + return MTKCAM_IPI_IMG_FMT_YUV_P212; + case V4L2_PIX_FMT_NV61_12: + return MTKCAM_IPI_IMG_FMT_YVU_P212; + case V4L2_PIX_FMT_MTISP_NV12_12P: + return MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED; + case V4L2_PIX_FMT_MTISP_NV21_12P: + return MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED; + case V4L2_PIX_FMT_MTISP_NV16_12P: + return MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED; + case V4L2_PIX_FMT_MTISP_NV61_12P: + return MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED; + case V4L2_PIX_FMT_SBGGR8: + case V4L2_PIX_FMT_SGBRG8: + case V4L2_PIX_FMT_SGRBG8: + case V4L2_PIX_FMT_SRGGB8: + return MTKCAM_IPI_IMG_FMT_BAYER8; + case V4L2_PIX_FMT_MTISP_SBGGR8F: + case V4L2_PIX_FMT_MTISP_SGBRG8F: + case V4L2_PIX_FMT_MTISP_SGRBG8F: + case V4L2_PIX_FMT_MTISP_SRGGB8F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER8; + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + return MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED; + case V4L2_PIX_FMT_SBGGR10P: + case V4L2_PIX_FMT_SGBRG10P: + case V4L2_PIX_FMT_SGRBG10P: + case V4L2_PIX_FMT_SRGGB10P: + return MTKCAM_IPI_IMG_FMT_BAYER10_MIPI; + case V4L2_PIX_FMT_MTISP_SBGGR10: + case V4L2_PIX_FMT_MTISP_SGBRG10: + case V4L2_PIX_FMT_MTISP_SGRBG10: + case V4L2_PIX_FMT_MTISP_SRGGB10: + return MTKCAM_IPI_IMG_FMT_BAYER10; + case V4L2_PIX_FMT_MTISP_SBGGR10F: + case V4L2_PIX_FMT_MTISP_SGBRG10F: + case V4L2_PIX_FMT_MTISP_SGRBG10F: + case V4L2_PIX_FMT_MTISP_SRGGB10F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER10; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + return MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED; + case V4L2_PIX_FMT_MTISP_SBGGR12: + case V4L2_PIX_FMT_MTISP_SGBRG12: + case V4L2_PIX_FMT_MTISP_SGRBG12: + case V4L2_PIX_FMT_MTISP_SRGGB12: + return MTKCAM_IPI_IMG_FMT_BAYER12; + case V4L2_PIX_FMT_MTISP_SBGGR12F: + case V4L2_PIX_FMT_MTISP_SGBRG12F: + case V4L2_PIX_FMT_MTISP_SGRBG12F: + case V4L2_PIX_FMT_MTISP_SRGGB12F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER12; + case V4L2_PIX_FMT_SBGGR14: + case V4L2_PIX_FMT_SGBRG14: + case V4L2_PIX_FMT_SGRBG14: + case V4L2_PIX_FMT_SRGGB14: + return MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED; + case V4L2_PIX_FMT_MTISP_SBGGR14: + case V4L2_PIX_FMT_MTISP_SGBRG14: + case V4L2_PIX_FMT_MTISP_SGRBG14: + case V4L2_PIX_FMT_MTISP_SRGGB14: + return MTKCAM_IPI_IMG_FMT_BAYER14; + case V4L2_PIX_FMT_MTISP_SBGGR14F: + case V4L2_PIX_FMT_MTISP_SGBRG14F: + case V4L2_PIX_FMT_MTISP_SGRBG14F: + case V4L2_PIX_FMT_MTISP_SRGGB14F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER14; + case V4L2_PIX_FMT_SBGGR16: + case V4L2_PIX_FMT_SGBRG16: + case V4L2_PIX_FMT_SGRBG16: + case V4L2_PIX_FMT_SRGGB16: + return MTKCAM_IPI_IMG_FMT_BAYER16; + case V4L2_PIX_FMT_MTISP_NV12_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_NV12; + case V4L2_PIX_FMT_MTISP_NV21_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_NV21; + case V4L2_PIX_FMT_MTISP_NV12_10_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010; + case V4L2_PIX_FMT_MTISP_NV21_10_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010; + case V4L2_PIX_FMT_MTISP_NV12_12_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012; + case V4L2_PIX_FMT_MTISP_NV21_12_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012; + case V4L2_PIX_FMT_MTISP_BAYER8_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_BAYER8; + case V4L2_PIX_FMT_MTISP_BAYER10_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_BAYER10; + case V4L2_PIX_FMT_MTISP_BAYER12_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_BAYER12; + case V4L2_PIX_FMT_MTISP_BAYER14_UFBC: + return MTKCAM_IPI_IMG_FMT_UFBC_BAYER14; + case V4L2_PIX_FMT_MTISP_SGRB8F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P; + case V4L2_PIX_FMT_MTISP_SGRB10F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED; + case V4L2_PIX_FMT_MTISP_SGRB12F: + return MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED; + default: + return MTKCAM_IPI_IMG_FMT_UNKNOWN; + } +} + +static void mtk_cam_fill_pixfmt_mp(struct v4l2_pix_format_mplane *pixfmt, + u32 pixelformat, u32 width, u32 height) +{ + struct v4l2_plane_pix_format *plane; + unsigned int ipi_fmt = mtk_cam_get_img_fmt(pixelformat); + u8 pixel_bits = mtk_cam_get_pixel_bits(ipi_fmt); + u32 stride; + u32 aligned_width; + u8 bus_size; + u8 i; + + pixfmt->width = width; + pixfmt->height = height; + pixfmt->pixelformat = pixelformat; + plane = &pixfmt->plane_fmt[0]; + bus_size = mtk_cam_yuv_dma_bus_size(pixel_bits, 0); + plane->sizeimage = 0; + + if (is_mtk_format(pixelformat)) { + const struct mtk_format_info *info; + + info = mtk_format_info(pixelformat); + if (!info) + return; + + pixfmt->num_planes = info->mem_planes; + if (info->mem_planes == 1) { + if (is_yuv_ufo(pixelformat)) { + /* UFO format width should align 64 pixel */ + aligned_width = ALIGN(width, 64); + stride = aligned_width * info->bit_r_num / info->bit_r_den; + + if (stride > plane->bytesperline) + plane->bytesperline = stride; + plane->sizeimage = stride * height; + plane->sizeimage += stride * height / 2; + plane->sizeimage += ALIGN((aligned_width / 64), 8) * height; + plane->sizeimage += ALIGN((aligned_width / 64), 8) * height / 2; + plane->sizeimage += sizeof(struct ufbc_buffer_header); + } else if (is_raw_ufo(pixelformat)) { + /* UFO format width should align 64 pixel */ + aligned_width = ALIGN(width, 64); + stride = aligned_width * info->bit_r_num / info->bit_r_den; + + if (stride > plane->bytesperline) + plane->bytesperline = stride; + plane->sizeimage = stride * height; + plane->sizeimage += ALIGN((aligned_width / 64), 8) * height; + plane->sizeimage += sizeof(struct ufbc_buffer_header); + } else { + /* width should be bus_size align */ + aligned_width = ALIGN(DIV_ROUND_UP(width + * info->bit_r_num, info->bit_r_den), bus_size); + stride = aligned_width * info->bpp[0]; + + if (stride > plane->bytesperline) + plane->bytesperline = stride; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + + if (plane->bytesperline > stride && + is_fullg_rb(pixelformat)) { + plane->sizeimage += + DIV_ROUND_UP(plane->bytesperline, hdiv) + * DIV_ROUND_UP(height, vdiv); + } else if (plane->bytesperline > stride && + !is_fullg_rb(pixelformat)) { + plane->sizeimage += + plane->bytesperline + * DIV_ROUND_UP(height, vdiv); + } else { + plane->sizeimage += info->bpp[i] + * DIV_ROUND_UP(aligned_width, hdiv) + * DIV_ROUND_UP(height, vdiv); + } + } + } + pr_debug("%s stride %d sizeimage %d\n", __func__, + plane->bytesperline, plane->sizeimage); + } else { + pr_debug("do not support non contiguous mplane\n"); + } + } else { + const struct v4l2_format_info *info; + + pr_debug("pixelformat:0x%x sizeimage:%d\n", + pixelformat, plane->sizeimage); + info = v4l2_format_info(pixelformat); + if (!info) + return; + + pixfmt->num_planes = info->mem_planes; + if (info->mem_planes == 1) { + aligned_width = ALIGN(width, bus_size); + stride = aligned_width * info->bpp[0]; + if (stride > plane->bytesperline) + plane->bytesperline = stride; + + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + + plane->sizeimage += info->bpp[i] + * DIV_ROUND_UP(aligned_width, hdiv) + * DIV_ROUND_UP(height, vdiv); + } + pr_debug("%s stride %d sizeimage %d\n", __func__, + plane->bytesperline, plane->sizeimage); + } else { + pr_warn("do not support non contiguous mplane\n"); + } + } +} + +static void mtk_cam_fill_ext_fmtdesc(struct v4l2_fmtdesc *fmt) +{ + const char *descr = NULL; + const unsigned int sz = sizeof(fmt->description); + + switch (fmt->pixelformat) { + case V4L2_PIX_FMT_MTISP_SBGGR8: + descr = "8-bit Bayer BGGR MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG8: + descr = "8-bit Bayer GBRG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG8: + descr = "8-bit Bayer GRBG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB8: + descr = "8-bit Bayer RGGB MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR10: + descr = "10-bit Bayer BGGR MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG10: + descr = "10-bit Bayer GBRG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG10: + descr = "10-bit Bayer GRBG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB10: + descr = "10-bit Bayer RGGB MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR12: + descr = "12-bit Bayer BGGR MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG12: + descr = "12-bit Bayer GBRG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG12: + descr = "12-bit Bayer GRBG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB12: + descr = "12-bit Bayer RGGB MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR14: + descr = "14-bit Bayer BGGR MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG14: + descr = "14-bit Bayer GBRG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG14: + descr = "14-bit Bayer GRBG MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB14: + descr = "14-bit Bayer RGGB MTISP Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR8F: + descr = "8-bit Full-G Bayer BGGR Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG8F: + descr = "8-bit Full-G Bayer GBRG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG8F: + descr = "8-bit Full-G Bayer GRBG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB8F: + descr = "8-bit Full-G Bayer RGGB Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR10F: + descr = "10-bit Full-G Bayer BGGR Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG10F: + descr = "10-bit Full-G Bayer GBRG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG10F: + descr = "10-bit Full-G Bayer GRBG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB10F: + descr = "10-bit Full-G Bayer RGGB Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR12F: + descr = "12-bit Full-G Bayer BGGR Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG12F: + descr = "12-bit Full-G Bayer GBRG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG12F: + descr = "12-bit Full-G Bayer GRBG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB12F: + descr = "12-bit Full-G Bayer RGGB Packed"; + break; + case V4L2_PIX_FMT_MTISP_SBGGR14F: + descr = "14-bit Full-G Bayer BGGR Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGBRG14F: + descr = "14-bit Full-G Bayer GBRG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRBG14F: + descr = "14-bit Full-G Bayer GRBG Packed"; + break; + case V4L2_PIX_FMT_MTISP_SRGGB14F: + descr = "14-bit Full-G Bayer RGGB Packed"; + break; + case V4L2_PIX_FMT_MTISP_NV12_10P: + descr = "Y/CbCr 4:2:0 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV21_10P: + descr = "Y/CrCb 4:2:0 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV16_10P: + descr = "Y/CbCr 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV61_10P: + descr = "Y/CrCb 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_YUYV10P: + descr = "YUYV 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_YVYU10P: + descr = "YVYU 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_UYVY10P: + descr = "UYVY 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_VYUY10P: + descr = "VYUY 4:2:2 10 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV12_12P: + descr = "Y/CbCr 4:2:0 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV21_12P: + descr = "Y/CrCb 4:2:0 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV16_12P: + descr = "Y/CbCr 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV61_12P: + descr = "Y/CrCb 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_YUYV12P: + descr = "YUYV 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_YVYU12P: + descr = "YVYU 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_UYVY12P: + descr = "UYVY 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_VYUY12P: + descr = "VYUY 4:2:2 12 bits packed"; + break; + case V4L2_PIX_FMT_MTISP_NV12_UFBC: + descr = "YCbCr 420 8 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_NV21_UFBC: + descr = "YCrCb 420 8 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_NV12_10_UFBC: + descr = "YCbCr 420 10 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_NV21_10_UFBC: + descr = "YCrCb 420 10 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_NV12_12_UFBC: + descr = "YCbCr 420 12 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_NV21_12_UFBC: + descr = "YCrCb 420 12 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_BAYER8_UFBC: + descr = "RAW 8 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_BAYER10_UFBC: + descr = "RAW 10 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_BAYER12_UFBC: + descr = "RAW 12 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_BAYER14_UFBC: + descr = "RAW 14 bits compress"; + break; + case V4L2_PIX_FMT_MTISP_SGRB8F: + descr = "8-bit 3 plane GRB Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRB10F: + descr = "10-bit 3 plane GRB Packed"; + break; + case V4L2_PIX_FMT_MTISP_SGRB12F: + descr = "12-bit 3 plane GRB Packed"; + break; + case V4L2_META_FMT_MTISP_PARAMS: + descr = "MTK ISP Tuning Metadata"; + break; + case V4L2_META_FMT_MTISP_3A: + descr = "MTK 3A Statistics"; + break; + case V4L2_META_FMT_MTISP_AF: + descr = "MTK AF Statistics"; + break; + case V4L2_META_FMT_MTISP_LCS: + descr = "MTK LCS Statistics"; + break; + case V4L2_META_FMT_MTISP_LMV: + descr = "MTK LMV Statistics"; + break; + default: + descr = NULL; + break; + } + + if (descr) + WARN_ON(strscpy(fmt->description, descr, sz) < 0); +} + +static void cal_image_pix_mp(unsigned int node_id, + struct v4l2_pix_format_mplane *mp, + unsigned int pixel_mode) +{ + unsigned int ipi_fmt = mtk_cam_get_img_fmt(mp->pixelformat); + unsigned int width = mp->width; + unsigned int height = mp->height; + unsigned int stride, i; + + pr_debug("fmt:0x%x ipi_fmt:%d\n", mp->pixelformat, ipi_fmt); + switch (ipi_fmt) { + case MTKCAM_IPI_IMG_FMT_BAYER8: + case MTKCAM_IPI_IMG_FMT_BAYER10: + case MTKCAM_IPI_IMG_FMT_BAYER12: + case MTKCAM_IPI_IMG_FMT_BAYER14: + case MTKCAM_IPI_IMG_FMT_BAYER16: + case MTKCAM_IPI_IMG_FMT_BAYER10_MIPI: + case MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED: + case MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED: + case MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED: + case MTKCAM_IPI_IMG_FMT_FG_BAYER8: + case MTKCAM_IPI_IMG_FMT_FG_BAYER10: + case MTKCAM_IPI_IMG_FMT_FG_BAYER12: + case MTKCAM_IPI_IMG_FMT_FG_BAYER14: + stride = mtk_cam_dmao_xsize(width, ipi_fmt, pixel_mode); + for (i = 0; i < mp->num_planes; i++) { + if (stride > mp->plane_fmt[i].bytesperline) + mp->plane_fmt[i].bytesperline = stride; + mp->plane_fmt[i].sizeimage = + mp->plane_fmt[i].bytesperline * height; + } + break; + case MTKCAM_IPI_IMG_FMT_YUYV: + case MTKCAM_IPI_IMG_FMT_YVYU: + case MTKCAM_IPI_IMG_FMT_UYVY: + case MTKCAM_IPI_IMG_FMT_VYUY: + case MTKCAM_IPI_IMG_FMT_YUV_422_2P: + case MTKCAM_IPI_IMG_FMT_YVU_422_2P: + case MTKCAM_IPI_IMG_FMT_YUV_422_3P: + case MTKCAM_IPI_IMG_FMT_YVU_422_3P: + case MTKCAM_IPI_IMG_FMT_YUV_420_2P: + case MTKCAM_IPI_IMG_FMT_YVU_420_2P: + case MTKCAM_IPI_IMG_FMT_YUV_420_3P: + case MTKCAM_IPI_IMG_FMT_YVU_420_3P: + case MTKCAM_IPI_IMG_FMT_Y8: + case MTKCAM_IPI_IMG_FMT_YUYV_Y210: + case MTKCAM_IPI_IMG_FMT_YVYU_Y210: + case MTKCAM_IPI_IMG_FMT_UYVY_Y210: + case MTKCAM_IPI_IMG_FMT_VYUY_Y210: + case MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P210: + case MTKCAM_IPI_IMG_FMT_YVU_P210: + case MTKCAM_IPI_IMG_FMT_YUV_P010: + case MTKCAM_IPI_IMG_FMT_YVU_P010: + case MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P212: + case MTKCAM_IPI_IMG_FMT_YVU_P212: + case MTKCAM_IPI_IMG_FMT_YUV_P012: + case MTKCAM_IPI_IMG_FMT_YVU_P012: + case MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED: + case MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED: + case MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED: + case MTKCAM_IPI_IMG_FMT_UFBC_NV12: + case MTKCAM_IPI_IMG_FMT_UFBC_NV21: + case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010: + case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010: + case MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012: + case MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER8: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER10: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER12: + case MTKCAM_IPI_IMG_FMT_UFBC_BAYER14: + case MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P: + case MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED: + case MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED: + mtk_cam_fill_pixfmt_mp(mp, mp->pixelformat, width, height); + break; + default: + break; + } +} + +static int mtk_video_init_format(struct mtk_cam_video_device *video) +{ + struct mtk_cam_dev_node_desc *desc = &video->desc; + struct v4l2_format *active = &video->active_fmt; + const struct v4l2_format *default_fmt = + &desc->fmts[desc->default_fmt_idx].vfmt; + + active->type = desc->buf_type; + + if (!desc->image) { + active->fmt.meta.dataformat = default_fmt->fmt.meta.dataformat; + active->fmt.meta.buffersize = default_fmt->fmt.meta.buffersize; + return 0; + } + + active->fmt.pix_mp.pixelformat = default_fmt->fmt.pix_mp.pixelformat; + active->fmt.pix_mp.width = default_fmt->fmt.pix_mp.width; + active->fmt.pix_mp.height = default_fmt->fmt.pix_mp.height; + active->fmt.pix_mp.num_planes = default_fmt->fmt.pix_mp.num_planes; + + cal_image_pix_mp(desc->id, &active->fmt.pix_mp, 0); + + /* set init one-plane */ + active->fmt.pix_mp.num_planes = 1; + active->fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB; + active->fmt.pix_mp.field = V4L2_FIELD_NONE; + active->fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + active->fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + active->fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB; + + return 0; +} + +int mtk_cam_video_register(struct mtk_cam_video_device *video, + struct v4l2_device *v4l2_dev) +{ + struct mtk_cam_device *cam = + container_of(v4l2_dev, struct mtk_cam_device, v4l2_dev); + struct media_pad *pad = &video->pad; + struct video_device *vdev = &video->vdev; + struct vb2_queue *q = &video->vb2_q; + unsigned int output = V4L2_TYPE_IS_OUTPUT(video->desc.buf_type); + int ret; + + if (video->desc.link_flags & MEDIA_LNK_FL_ENABLED) + video->enabled = true; + else + video->enabled = false; + + mutex_init(&video->q_lock); + + /* initialize vb2_queue */ + q->type = video->desc.buf_type; + q->io_modes = VB2_MMAP | VB2_DMABUF; + + if (q->type == V4L2_BUF_TYPE_META_OUTPUT) + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + else + q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_BOOTIME; + + if (video->desc.smem_alloc) { + q->bidirectional = 1; + /* reserved memory */ + q->dev = cam->smem_dev; + } else if (is_yuv_node(video->desc.id)) { + q->dev = cam->raw.yuvs[0]; + } else { + q->dev = cam->raw.devs[0]; + } + + q->supports_requests = true; + q->lock = &video->q_lock; + q->ops = &mtk_cam_vb2_ops; + q->mem_ops = &vb2_dma_contig_memops; + q->drv_priv = cam; + q->buf_struct_size = sizeof(struct mtk_cam_buffer); + + if (output) + q->timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_EOF; + else + q->timestamp_flags |= V4L2_BUF_FLAG_TSTAMP_SRC_SOE; + + /* No minimum buffers limitation */ + q->min_queued_buffers = 0; + + ret = vb2_queue_init(q); + if (ret < 0) { + dev_info(v4l2_dev->dev, "Failed to init vb2 queue: %d\n", ret); + goto error_vb2_init; + } + + pad->flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK; + ret = media_entity_pads_init(&vdev->entity, 1, pad); + if (ret < 0) { + dev_info(v4l2_dev->dev, "Failed to init video entity: %d\n", ret); + goto error_media_init; + } + + ret = mtk_video_init_format(video); + if (ret < 0) { + dev_info(v4l2_dev->dev, "Failed to init format: %d\n", ret); + goto error_video_register; + } + + vdev->entity.function = MEDIA_ENT_F_IO_V4L; + vdev->entity.ops = NULL; + vdev->fops = &mtk_cam_v4l2_fops; + vdev->device_caps = video->desc.cap | V4L2_CAP_STREAMING; + vdev->v4l2_dev = v4l2_dev; + + vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX; + vdev->queue = &video->vb2_q; + vdev->ioctl_ops = video->desc.ioctl_ops; + vdev->release = video_device_release_empty; + /* share q_lock */ + vdev->lock = &video->q_lock; + strscpy(vdev->name, video->desc.name, sizeof(vdev->name)); + + ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret < 0) { + dev_info(v4l2_dev->dev, "Failed to register video device: %d\n", + ret); + goto error_video_register; + } + video_set_drvdata(vdev, cam); + + dev_dbg(v4l2_dev->dev, "registered vdev:%d:%s\n", + video->desc.id, vdev->name); + + return 0; + +error_video_register: + media_entity_cleanup(&vdev->entity); +error_media_init: + vb2_queue_release(&video->vb2_q); +error_vb2_init: + mutex_destroy(&video->q_lock); + + return ret; +} + +void mtk_cam_video_unregister(struct mtk_cam_video_device *video) +{ + video_unregister_device(&video->vdev); + vb2_queue_release(&video->vb2_q); + media_entity_cleanup(&video->vdev.entity); + mutex_destroy(&video->q_lock); +} + +const struct v4l2_format * +mtk_cam_dev_find_fmt(struct mtk_cam_dev_node_desc *desc, u32 format) +{ + unsigned int i; + const struct v4l2_format *fmt; + + for (i = 0; i < desc->num_fmts; i++) { + fmt = &desc->fmts[i].vfmt; + if (fmt->fmt.pix_mp.pixelformat == format) + return fmt; + } + + return NULL; +} + +int mtk_cam_vidioc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap) +{ + struct mtk_cam_device *cam = video_drvdata(file); + + strscpy(cap->driver, dev_driver_string(cam->dev), sizeof(cap->driver)); + strscpy(cap->card, dev_driver_string(cam->dev), sizeof(cap->card)); + snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", + dev_name(cam->dev)); + + return 0; +} + +int mtk_cam_vidioc_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes) +{ + struct mtk_cam_video_device *node = file_to_mtk_cam_node(filp); + const struct v4l2_format *dev_fmt; + + dev_fmt = mtk_cam_dev_find_fmt(&node->desc, sizes->pixel_format); + if (!dev_fmt || sizes->index) + return -EINVAL; + + sizes->type = node->desc.frmsizes->type; + memcpy(&sizes->stepwise, &node->desc.frmsizes->stepwise, + sizeof(sizes->stepwise)); + return 0; +} + +int mtk_cam_vidioc_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + + if (f->index >= node->desc.num_fmts) + return -EINVAL; + + f->pixelformat = node->desc.fmts[f->index].vfmt.fmt.pix_mp.pixelformat; + f->flags = 0; + /* extended fmt description is filled here */ + /* common fmt description is filled in v4l_fill_fmtdesc */ + mtk_cam_fill_ext_fmtdesc(f); + + return 0; +} + +int mtk_cam_vidioc_g_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + + f->fmt = node->active_fmt.fmt; + + return 0; +} + +int mtk_cam_vidioc_s_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_cam_device *cam = video_drvdata(file); + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + struct mtk_raw_pipeline *raw_pipeline; + int raw_feature = 0; + + raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id); + + if (!vb2_is_busy(node->vdev.queue)) { + /* Get the valid format */ + if (raw_pipeline) + raw_feature = raw_pipeline->user_res.raw_res.feature; + + mtk_cam_video_set_fmt(node, f, raw_feature); + + /* Configure to video device */ + node->active_fmt = *f; + return 0; + } + + dev_info(cam->dev, + "%s:pipe(%d):%s:Cannot change format while streaming\n", + __func__, node->uid.pipe_id, node->desc.name); + + return -EBUSY; +} + +int mtk_cam_video_set_fmt(struct mtk_cam_video_device *node, + struct v4l2_format *f, int raw_feature) +{ + struct mtk_cam_device *cam = video_get_drvdata(&node->vdev); + const struct v4l2_format *dev_fmt; + struct v4l2_format try_fmt; + s32 i; + + dev_dbg(cam->dev, + "%s:pipe(%d):%s:feature(0x%x)\n", + __func__, node->uid.pipe_id, node->desc.name, raw_feature); + + memset(&try_fmt, 0, sizeof(try_fmt)); + try_fmt.type = f->type; + + /* Validate pixelformat */ + dev_fmt = mtk_cam_dev_find_fmt(&node->desc, f->fmt.pix_mp.pixelformat); + if (!dev_fmt) { + dev_dbg(cam->dev, "unknown fmt:%d\n", + f->fmt.pix_mp.pixelformat); + dev_fmt = &node->desc.fmts[node->desc.default_fmt_idx].vfmt; + } + try_fmt.fmt.pix_mp.pixelformat = dev_fmt->fmt.pix_mp.pixelformat; + + /* Validate image width & height range */ + try_fmt.fmt.pix_mp.width = clamp_val(f->fmt.pix_mp.width, + IMG_MIN_WIDTH, IMG_MAX_WIDTH); + try_fmt.fmt.pix_mp.height = clamp_val(f->fmt.pix_mp.height, + IMG_MIN_HEIGHT, IMG_MAX_HEIGHT); + /* 4 bytes alignment for width */ + /* width and stride should align bus_size */ + try_fmt.fmt.pix_mp.width = ALIGN(try_fmt.fmt.pix_mp.width, IMG_PIX_ALIGN); + try_fmt.fmt.pix_mp.num_planes = 1; + + for (i = 0 ; i < try_fmt.fmt.pix_mp.num_planes ; i++) + try_fmt.fmt.pix_mp.plane_fmt[i].bytesperline = + f->fmt.pix_mp.plane_fmt[i].bytesperline; + + /* bytesperline & sizeimage calculation */ + cal_image_pix_mp(node->desc.id, &try_fmt.fmt.pix_mp, 0); + + /* Constant format fields */ + try_fmt.fmt.pix_mp.colorspace = V4L2_COLORSPACE_SRGB; + try_fmt.fmt.pix_mp.field = V4L2_FIELD_NONE; + try_fmt.fmt.pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; + try_fmt.fmt.pix_mp.quantization = V4L2_QUANTIZATION_DEFAULT; + try_fmt.fmt.pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB; + + *f = try_fmt; + + return 0; +} + +int mtk_cam_vidioc_try_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + + mtk_cam_video_set_fmt(node, f, 0); + + return 0; +} + +int mtk_cam_vidioc_meta_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f) +{ + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + + if (f->index) + return -EINVAL; + + f->pixelformat = node->active_fmt.fmt.meta.dataformat; + f->flags = 0; + /* extended fmt description is filled here */ + /* common fmt description is filled in v4l_fill_fmtdesc */ + mtk_cam_fill_ext_fmtdesc(f); + + return 0; +} + +int mtk_cam_vidioc_g_meta_fmt(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct mtk_cam_device *cam = video_drvdata(file); + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + struct mtk_cam_dev_node_desc *desc = &node->desc; + const struct v4l2_format *default_fmt = + &desc->fmts[desc->default_fmt_idx].vfmt; + struct mtk_raw_pde_config *pde_cfg; + struct mtk_cam_pde_info *pde_info; + + if (node->desc.dma_port == MTKCAM_IPI_RAW_META_STATS_CFG) { + pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config; + pde_info = &pde_cfg->pde_info; + if (pde_info->pd_table_offset) { + node->active_fmt.fmt.meta.buffersize = + default_fmt->fmt.meta.buffersize + + pde_info->pdi_max_size; + + dev_dbg(cam->dev, "PDE: node(%d), enlarge meta size(%u)", + node->desc.dma_port, + node->active_fmt.fmt.meta.buffersize); + } + } + if (node->desc.dma_port == MTKCAM_IPI_RAW_META_STATS_0) { + pde_cfg = &cam->raw.pipelines[node->uid.pipe_id].pde_config; + pde_info = &pde_cfg->pde_info; + if (pde_info->pd_table_offset) { + node->active_fmt.fmt.meta.buffersize = + default_fmt->fmt.meta.buffersize + + pde_info->pdo_max_size; + + dev_dbg(cam->dev, "PDE: node(%d), enlarge meta size(%u)", + node->desc.dma_port, + node->active_fmt.fmt.meta.buffersize); + } + } + f->fmt.meta.dataformat = node->active_fmt.fmt.meta.dataformat; + f->fmt.meta.buffersize = node->active_fmt.fmt.meta.buffersize; + + return 0; +} + +int mtk_cam_vidioc_s_selection(struct file *file, void *fh, + struct v4l2_selection *s) +{ + struct mtk_cam_device *cam = video_drvdata(file); + struct mtk_cam_video_device *node = file_to_mtk_cam_node(file); + struct mtk_raw_pipeline *raw_pipeline; + + raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id); + if (raw_pipeline) { + node->active_crop = *s; + + dev_dbg(raw_pipeline->subdev.v4l2_dev->dev, + "%s:%s:%s:Set selection (%d,%d,%d,%d)\n", + __func__, raw_pipeline->subdev.name, node->desc.name, + s->r.left, s->r.top, s->r.width, s->r.height); + } + + return 0; +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h new file mode 100644 index 000000000000..6c79987670f8 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-video.h @@ -0,0 +1,224 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_VIDEO_H +#define __MTK_CAM_VIDEO_H + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_cam-ipi.h" + +#define MAX_PLANE_NUM 3 + +struct mtk_cam_resource; +struct mtk_raw_pde_config; + +typedef int (*set_pad_fmt_func_t)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_mbus_framefmt *sink_fmt, + struct mtk_cam_resource *res, + int pad, int which); + +typedef int (*set_pad_selection_func_t)(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_mbus_framefmt *sink_fmt, + struct mtk_cam_resource *res, + int pad, int which); + +/*For state analysis and controlling for request*/ +enum MTK_BUF_STATE { + E_BUF_STATE_QUEUED = 0x0, + E_BUF_STATE_COMPOSED, + E_BUF_STATE_CQ, + E_BUF_STATE_OUTER, +}; + +struct mtk_buf_state { + enum MTK_BUF_STATE estate; + struct list_head list; +}; + +/** + * struct mtk_cam_buffer - MTK camera device buffer. + * + * @vbb: Embedded struct vb2_v4l2_buffer. + * @list: List entry for the buffer queue + * @daddr: The DMA address of this buffer. + * @scp_addr: The SCP address of this buffer which + * is only supported for meta input node. + * @state: The camera buffer status. + */ +struct mtk_cam_buffer { + struct vb2_v4l2_buffer vbb; + struct list_head list; + + dma_addr_t daddr; + dma_addr_t scp_addr; + struct mtk_buf_state state; +}; + +struct mtk_cam_format_desc { + struct v4l2_format vfmt; + struct v4l2_mbus_framefmt pfmt; +}; + +struct mtk_cam_pad_ops { + set_pad_fmt_func_t set_pad_fmt; + set_pad_selection_func_t set_pad_selection; +}; + +/** + * struct mtk_cam_dev_node_desc - MTK camera device node descriptor + * + * @id: id of the node + * @name: name of the node + * @cap: supported V4L2 capabilities + * @buf_type: supported V4L2 buffer type + * @dma_port: the dma ports associated to the node + * @link_flags: default media link flags + * @smem_alloc: using the smem_dev as alloc device or not + * @need_cache_sync_on_prepare: do cache sync at buf_prepare (userspace sync) + * @need_cache_sync_on_finish: do cache sync at buf_finish (userspace sync) + * @image: true for image node, false for meta node + * @num_fmts: the number of supported node formats + * @default_fmt_idx: default format of this node + * @max_buf_count: maximum VB2 buffer count + * @ioctl_ops: mapped to v4l2_ioctl_ops + * @fmts: supported format + * @frmsizes: supported V4L2 frame size number + * @pad_ops: set and select pad configurations and formats + */ +struct mtk_cam_dev_node_desc { + u8 id; + const char *name; + u32 cap; + u32 buf_type; + u32 dma_port; + u32 link_flags; + u8 smem_alloc:1; + u8 image:1; + u8 num_fmts; + u8 default_fmt_idx; + u8 max_buf_count; + const struct v4l2_ioctl_ops *ioctl_ops; + const struct mtk_cam_format_desc *fmts; + const struct v4l2_frmsizeenum *frmsizes; + struct mtk_cam_pad_ops *pad_ops; +}; + +/** + * struct mtk_cam_video_device - MediaTek video device structure. + */ +struct mtk_cam_video_device { + struct mtkcam_ipi_uid uid; + struct mtk_cam_dev_node_desc desc; + unsigned int enabled; + + struct vb2_queue vb2_q; + struct video_device vdev; + struct media_pad pad; + struct v4l2_format active_fmt; + /* use first 4 elements of reserved field of v4l2_pix_format_mplane as request fd */ + struct v4l2_format pending_fmt; + /* use first elements of reserved field of v4l2_selection as request fd*/ + struct v4l2_selection active_crop; + /* Serializes vb2 queue and video device operations */ + struct mutex q_lock; + int streaming_id; + + /* cached ctx info */ + struct mtk_cam_ctx *ctx; +}; + +struct mtk_format_info { + u32 format; + u8 mem_planes; + u8 comp_planes; + u8 bpp[4]; + u8 hdiv; + u8 vdiv; + u8 bit_r_num; /* numerator of bit ratio */ + u8 bit_r_den; /* denominator of bit ratio */ +}; + +int mtk_cam_video_register(struct mtk_cam_video_device *video, + struct v4l2_device *v4l2_dev); + +void mtk_cam_video_unregister(struct mtk_cam_video_device *video); + +static inline struct mtk_cam_video_device * +file_to_mtk_cam_node(struct file *__file) +{ + return container_of(video_devdata(__file), struct mtk_cam_video_device, vdev); +} + +static inline struct mtk_cam_buffer * +mtk_cam_vb2_buf_to_dev_buf(struct vb2_buffer *__vb) +{ + return container_of(__vb, struct mtk_cam_buffer, vbb.vb2_buf); +} + +static inline struct mtk_cam_video_device * +mtk_cam_vbq_to_vdev(struct vb2_queue *__vq) +{ + return container_of(__vq, struct mtk_cam_video_device, vb2_q); +} + +const struct v4l2_format * +mtk_cam_dev_find_fmt(struct mtk_cam_dev_node_desc *desc, u32 format); + +int mtk_cam_vidioc_querycap(struct file *file, void *fh, + struct v4l2_capability *cap); + +int mtk_cam_vidioc_enum_framesizes(struct file *filp, void *priv, + struct v4l2_frmsizeenum *sizes); + +int mtk_cam_vidioc_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f); + +int mtk_cam_vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f); + +int mtk_cam_vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f); + +int mtk_cam_vidioc_try_fmt(struct file *file, void *fh, struct v4l2_format *f); + +int mtk_cam_vidioc_meta_enum_fmt(struct file *file, void *fh, + struct v4l2_fmtdesc *f); + +int mtk_cam_vidioc_s_selection(struct file *file, void *fh, + struct v4l2_selection *s); + +int mtk_cam_vidioc_g_meta_fmt(struct file *file, void *fh, + struct v4l2_format *f); + +/* Utility functions to convert format enum */ +unsigned int mtk_cam_get_sensor_pixel_id(unsigned int fmt); + +unsigned int mtk_cam_get_sensor_fmt(unsigned int fmt); + +unsigned int mtk_cam_get_pixel_bits(unsigned int pix_fmt); + +unsigned int mtk_cam_get_img_fmt(unsigned int fourcc); + +int mtk_cam_video_set_fmt(struct mtk_cam_video_device *node, + struct v4l2_format *f, int feature); + +int is_mtk_format(u32 pixelformat); + +int is_yuv_ufo(u32 pixelformat); + +int is_raw_ufo(u32 pixelformat); + +int is_fullg_rb(u32 pixelformat); + +const struct mtk_format_info *mtk_format_info(u32 format); + +#endif /*__MTK_CAM_VIDEO_H */ From patchwork Wed Oct 9 11:15:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shu-hsiang Yang X-Patchwork-Id: 13828191 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id 17C45CF0454 for ; Wed, 9 Oct 2024 11:21:57 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=8ju0ytowx65X0CpsP0yuEO1L3woEj5GB17r1ruwY8aE=; b=MDqbi4d8h/04pk3PNfvokrk/NZ XEK/SEvJ3nVYhAaSUN3CIQZBiqXkvHgXGXvFZyJc7pncedxTUtqco8+zs3rchLrG1pX7/P+rOLn5X GDba4ewPcy110Ka9MvrvBAD8Akp0LXgUIXrhzjOQCljSxYJCejE1L37qw5icKuHVYQzPwO6LS9JHD 7iZ35gSrRc0W5PdgFdVrcp2U16vdVsIuIuGfRvZ5M71IIhPWTJyy3SFxwukCvVOp5HxTpx0IcAwep w/2JqV04B/FTCjjJxhzkxTW9cAE/bK1n9xtk5xrpPDzXkNAH+rdLvNAMgiF2vZwqILeIx0b0KEyKO 7WUI89wg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUlB-000000092Lt-1zPB; Wed, 09 Oct 2024 11:21:41 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUfz-000000091HL-2hou; Wed, 09 Oct 2024 11:16:20 +0000 X-UUID: e4666b52862f11efba0aef63c0775dbf-20241009 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=8ju0ytowx65X0CpsP0yuEO1L3woEj5GB17r1ruwY8aE=; b=cB80hJnyH/3/d2Ic6xP5SwCzK6gqskrQon3R6NHJmXSpi1KZhoDYPHZvEQ81klifCv/EbrL3mBxqBmHsGrne5WqBahm58XPzyjoxc1RE8C8k4ZTxOm+9SPUp1x6iZq41PMvcIt7CL7lvqjqRUTSfPmqMpJGSfgKKicsqSwk/qm4=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:5f2f4e3a-9b89-4d61-aeda-ff41589d620c,IP:0,U RL:0,TC:0,Content:-25,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTIO N:release,TS:-25 X-CID-META: VersionHash:6dc6a47,CLOUDID:528a0041-8751-41b2-98dd-475503d45150,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e4666b52862f11efba0aef63c0775dbf-20241009 Received: from mtkmbs09n1.mediatek.inc [(172.21.101.35)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 2100934849; Wed, 09 Oct 2024 04:16:12 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by mtkmbs10n1.mediatek.inc (172.21.101.34) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Wed, 9 Oct 2024 19:16:09 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Wed, 9 Oct 2024 19:16:09 +0800 From: Shu-hsiang Yang To: Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Sumit Semwal , Christian Konig CC: , , , , , , , , , , , , , Shu-hsiang Yang Subject: [PATCH v1 09/10] media: platform: mediatek: add isp_7x build config Date: Wed, 9 Oct 2024 19:15:50 +0800 Message-ID: <20241009111551.27052-10-Shu-hsiang.Yang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> References: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> MIME-Version: 1.0 X-TM-AS-Product-Ver: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-AS-Result: No-10--6.784100-8.000000 X-TMASE-MatchedRID: WbOLpgv9C7Y9S3IiQd+eNRlckvO1m+Jc1KoSW5Ji1XuX0aNVfPpyq/fK AG02e9BelTJXKqh1ne1M8qdoCvOVvktzS/aGUmtztw+xHnsmQjPDHSNFHFxB801KG1YrOQW//Ge vfoH427p8p1FS+daYYMUIXPffOsz4CwsXh7HbbhOzI1v7J4hECj2Yc4MPQbFxNv1MHbxRuSJj1H gUqCPEf+LzNWBegCW2oq1o0yfqNxkLbigRnpKlKTpcQTtiHDgW3eKwXwnXwQy00lJYFDyuPUEq6 sF8PLIVy7NoYne/RapUsrIL3LuS9Q== X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--6.784100-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: E3C4734528D52573EBB41A1F6E3A9DC439736167DECD402658AFD8FCFE79CCAB2000:8 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_041619_759261_6074738A X-CRM114-Status: GOOD ( 16.61 ) 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 Kconfig and Makefile to include MTK ISP CAMSYS, integrating the driver into the kernel build and configuration process. Signed-off-by: Shu-hsiang Yang --- drivers/media/platform/mediatek/Kconfig | 1 + drivers/media/platform/mediatek/Makefile | 2 ++ drivers/media/platform/mediatek/isp/Kconfig | 21 +++++++++++++++++++ .../platform/mediatek/isp/isp_7x/Makefile | 7 +++++++ .../mediatek/isp/isp_7x/camsys/Makefile | 16 ++++++++++++++ 5 files changed, 47 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/Kconfig create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/Makefile create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile diff --git a/drivers/media/platform/mediatek/Kconfig b/drivers/media/platform/mediatek/Kconfig index 84104e2cd024..a405d5701329 100644 --- a/drivers/media/platform/mediatek/Kconfig +++ b/drivers/media/platform/mediatek/Kconfig @@ -2,6 +2,7 @@ comment "Mediatek media platform drivers" +source "drivers/media/platform/mediatek/isp/Kconfig" source "drivers/media/platform/mediatek/jpeg/Kconfig" source "drivers/media/platform/mediatek/mdp/Kconfig" source "drivers/media/platform/mediatek/vcodec/Kconfig" diff --git a/drivers/media/platform/mediatek/Makefile b/drivers/media/platform/mediatek/Makefile index 38e6ba917fe5..74164df8c68d 100644 --- a/drivers/media/platform/mediatek/Makefile +++ b/drivers/media/platform/mediatek/Makefile @@ -1,6 +1,8 @@ # SPDX-License-Identifier: GPL-2.0-only + obj-y += jpeg/ obj-y += mdp/ obj-y += vcodec/ obj-y += vpu/ obj-y += mdp3/ +obj-y += isp/isp_7x/ diff --git a/drivers/media/platform/mediatek/isp/Kconfig b/drivers/media/platform/mediatek/isp/Kconfig new file mode 100644 index 000000000000..8633e893a37d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/Kconfig @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-only + +config VIDEO_MTK_ISP_71_CAMSYS + tristate "MediaTek ISP 7.1 camsys driver" + depends on ARCH_MEDIATEK + select V4L2_FWNODE + select VIDEO_V4L2_SUBDEV_API + select VIDEOBUF2_DMA_CONTIG + select RPMSG_MTK_CCD + select MTKCCD_REMOTEPROC + select MTK_SCP + + default n + help + Camsys driver controls 3A (auto-focus, exposure, + and white balance) with tuning feature and outputs + the captured image buffers in MediaTek's ISP7 system. + + Choose y if you want to use MediaTek SoCs to create image + captured application such as video recording and still image + capturing. diff --git a/drivers/media/platform/mediatek/isp/isp_7x/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/Makefile new file mode 100644 index 000000000000..c927999cd854 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 + +subdir-ccflags-y += -Werror + +subdir-ccflags-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += -DISP7_1 + +obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += camsys/ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile new file mode 100644 index 000000000000..8e758cf6877f --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/Makefile @@ -0,0 +1,16 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2022 MediaTek Inc. + +mtk-cam-isp-objs := mtk_cam.o mtk_cam-raw.o mtk_cam-pool.o \ + mtk_cam-video.o mtk_cam-ctrl.o \ + mtk_cam-seninf-route.o mtk_cam-seninf-drv.o \ + mtk_cam-debug.o \ + mtk_cam-raw_debug.o \ + mtk_cam-feature.o mtk_cam-timesync.o + +mtk-cam-plat-util-objs := mtk_cam-plat-util.o + +include $(src)/mtk_csi_phy_2_0/Makefile + +obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += mtk-cam-plat-util.o +obj-$(CONFIG_VIDEO_MTK_ISP_71_CAMSYS) += mtk-cam-isp.o From patchwork Wed Oct 9 11:15:51 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Shu-hsiang Yang X-Patchwork-Id: 13828192 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 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 smtp.lore.kernel.org (Postfix) with ESMTPS id A2AE7CF0454 for ; Wed, 9 Oct 2024 11:23:17 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender:List-Subscribe:List-Help :List-Post:List-Archive:List-Unsubscribe:List-Id:Content-Type:MIME-Version: References:In-Reply-To:Message-ID:Date:Subject:CC:To:From:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=4XpWAyEynjzZc1Gg5Q2UscCHSaUGQb/UYCjpqT1xx6Q=; b=swlGswNApOeIV+4pOCXPiqYLlD nxhawRG74n2eeSujKSeHSGqr4r66lA34vHeKZchthuCmS7Up1Y9iplj8oK+zV9WxTCcNKnrqRQfaU 38yTwsd0tdAnstIpjeolX9YKCBSUk3y/1wXRELZkuhv2VUeYHPxLf3+o2QIN6K66DJgj0dvitfLOy fEO2FuyiZYBaudM3cci8oOl41tWxN4Ca8u2mDhBYXpKjQ0ieko1cQctwCO465QTyRz4hLQeFqqU2V fZM4Ldp+IZ7qhP2qWWJkAf0Ed4j2Jvf/gTqRVORjYQ+YWcFTdwKTCyazBNbO0VjIYTUSQC35L2aHb fEIiE0Gw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUmX-000000092ms-02hp; Wed, 09 Oct 2024 11:23:05 +0000 Received: from desiato.infradead.org ([2001:8b0:10b:1:d65d:64ff:fe57:4e05]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgN-000000091OY-3GHs; Wed, 09 Oct 2024 11:16:44 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=desiato.20200630; h=Content-Type:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:CC:To:From:Sender:Reply-To: Content-Transfer-Encoding:Content-ID:Content-Description; bh=4XpWAyEynjzZc1Gg5Q2UscCHSaUGQb/UYCjpqT1xx6Q=; b=L3DA6JWkeJ8Q2bqmrc3tucfbRZ a6uoGS1WHxclf5CXaljO5ytWMvUbMt6TsXfeQIYQwVfljMOnazLPKqe4otUprPBEPTP2pTw7CIMQZ VjVA78ukFocmB0oHwX00MfYuDRAsNBTWPScl+Ig2zMB7luDSt5qYrdpeEef/Iwn4uQLZK2ZtvTUSW xsI2n9Fz2hfSNAtk4IZKkCSXwTsRM4x/ZVix3YsMX5ZwarbSqtcr23w7GOEFX3aST0y8wTkBljrZX HlAyc9tadE+6OO5ApZOAZu6yWMxOXDCHwDEkpjyhJYpuzPXWIZKdhCZ6Sg0jWYKx3QnH+mG15ORdq OxfesTzQ==; Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgI-00000004v7m-2wo1; Wed, 09 Oct 2024 11:16:41 +0000 X-UUID: e484cd36862f11efb3adad29d29602c1-20241009 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=mediatek.com; s=dk; h=Content-Type:MIME-Version:References:In-Reply-To:Message-ID:Date:Subject:CC:To:From; bh=4XpWAyEynjzZc1Gg5Q2UscCHSaUGQb/UYCjpqT1xx6Q=; b=bujwaarj1Xec+lJ6l9kCqiJIw+dRyYyLT+DxMVoXWZumGxaMa0Be8cYr//HXojMZE00/6gL7DBUrQ1jTW+0C6PEfmouJB1t92WgM+EmVllofk/lZVhB1sHig8V6y02B1z9sQVGrIO4f7X0Xquzp/WtQCYY/OOQOKKlXqEb3fle8=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:ef009d52-8d1c-46d9-b84f-8f9d916903b0,IP:0,U RL:0,TC:0,Content:0,EDM:0,RT:0,SF:0,FILE:0,BULK:0,RULE:Release_Ham,ACTION: release,TS:0 X-CID-META: VersionHash:6dc6a47,CLOUDID:1354fe64-444a-4b47-a99a-591ade3b04b2,B ulkID:nil,BulkQuantity:0,Recheck:0,SF:102,TC:nil,Content:0,EDM:-3,IP:nil,U RL:0,File:nil,RT:nil,Bulk:nil,QS:nil,BEC:nil,COL:0,OSI:0,OSA:0,AV:0,LES:1, SPR:NO,DKR:0,DKP:0,BRR:0,BRE:0,ARC:0 X-CID-BVR: 0,NGT X-CID-BAS: 0,NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e484cd36862f11efb3adad29d29602c1-20241009 Received: from mtkmbs14n2.mediatek.inc [(172.21.101.76)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 247672504; Wed, 09 Oct 2024 04:16:12 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by mtkmbs13n2.mediatek.inc (172.21.101.108) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.2.1118.26; Wed, 9 Oct 2024 19:16:09 +0800 Received: from mtksdccf07.mediatek.inc (172.21.84.99) by mtkmbs13n2.mediatek.inc (172.21.101.73) with Microsoft SMTP Server id 15.2.1118.26 via Frontend Transport; Wed, 9 Oct 2024 19:16:09 +0800 From: Shu-hsiang Yang To: Mauro Carvalho Chehab , Rob Herring , Krzysztof Kozlowski , Conor Dooley , Matthias Brugger , AngeloGioacchino Del Regno , Sumit Semwal , Christian Konig CC: , , , , , , , , , , , , , Shu-hsiang Yang Subject: [PATCH v1 10/10] uapi: linux: add mediatek isp_7x camsys user api Date: Wed, 9 Oct 2024 19:15:51 +0800 Message-ID: <20241009111551.27052-11-Shu-hsiang.Yang@mediatek.com> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> References: <20241009111551.27052-1-Shu-hsiang.Yang@mediatek.com> MIME-Version: 1.0 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20241009_121640_298205_C67E8368 X-CRM114-Status: GOOD ( 18.37 ) 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 UAPI for MediaTek ISP platform, providing user-space interfaces for the new camsys driver. Signed-off-by: Shu-hsiang Yang --- include/uapi/linux/mtkisp_camsys.h | 227 +++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 include/uapi/linux/mtkisp_camsys.h diff --git a/include/uapi/linux/mtkisp_camsys.h b/include/uapi/linux/mtkisp_camsys.h new file mode 100644 index 000000000000..9c43f0799dbf --- /dev/null +++ b/include/uapi/linux/mtkisp_camsys.h @@ -0,0 +1,227 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +/* + * MediaTek ISP camsys User space API + * + * Copyright (c) 2024 MediaTek Inc. + */ + +#ifndef _MTKISP_CAMSYS_USER_H +#define _MTKISP_CAMSYS_USER_H + +#include +#include + +#define V4L2_BUF_FLAG_TIMESTAMP_COPY 0x00004000 +#define V4L2_BUF_FLAG_TIMESTAMP_BOOTIME 0x00008000 + +/* MTK ISP camsys events */ +#define V4L2_EVENT_REQUEST_DRAINED (V4L2_EVENT_PRIVATE_START + 1) +#define V4L2_EVENT_REQUEST_DUMPED (V4L2_EVENT_PRIVATE_START + 2) + +/* The base for the mediatek camsys driver controls */ +/* We reserve 48 controls for this driver. */ +#define V4L2_CID_USER_MTK_CAM_BASE (V4L2_CID_USER_BASE + 0x10d0) + +/* MTK ISP camsys controls */ +#define V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT (V4L2_CID_USER_MTK_CAM_BASE + 1) +#define V4L2_CID_MTK_CAM_BIN_LIMIT (V4L2_CID_USER_MTK_CAM_BASE + 2) +#define V4L2_CID_MTK_CAM_FRZ_LIMIT (V4L2_CID_USER_MTK_CAM_BASE + 3) +#define V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY (V4L2_CID_USER_MTK_CAM_BASE + 4) +#define V4L2_CID_MTK_CAM_USED_ENGINE (V4L2_CID_USER_MTK_CAM_BASE + 5) +#define V4L2_CID_MTK_CAM_BIN (V4L2_CID_USER_MTK_CAM_BASE + 6) +#define V4L2_CID_MTK_CAM_FRZ (V4L2_CID_USER_MTK_CAM_BASE + 7) +#define V4L2_CID_MTK_CAM_USED_ENGINE_TRY (V4L2_CID_USER_MTK_CAM_BASE + 8) +#define V4L2_CID_MTK_CAM_BIN_TRY (V4L2_CID_USER_MTK_CAM_BASE + 9) +#define V4L2_CID_MTK_CAM_FRZ_TRY (V4L2_CID_USER_MTK_CAM_BASE + 10) +#define V4L2_CID_MTK_CAM_PIXEL_RATE (V4L2_CID_USER_MTK_CAM_BASE + 11) +#define V4L2_CID_MTK_CAM_FEATURE (V4L2_CID_USER_MTK_CAM_BASE + 12) +#define V4L2_CID_MTK_CAM_SYNC_ID (V4L2_CID_USER_MTK_CAM_BASE + 13) +#define V4L2_CID_MTK_CAM_RAW_PATH_SELECT (V4L2_CID_USER_MTK_CAM_BASE + 14) +#define V4L2_CID_MTK_CAM_HSF_EN (V4L2_CID_USER_MTK_CAM_BASE + 15) +#define V4L2_CID_MTK_CAM_PDE_INFO (V4L2_CID_USER_MTK_CAM_BASE + 16) +#define V4L2_CID_MTK_CAM_MSTREAM_EXPOSURE (V4L2_CID_USER_MTK_CAM_BASE + 17) +#define V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC (V4L2_CID_USER_MTK_CAM_BASE + 18) +#define V4L2_CID_MTK_CAM_TG_FLASH_CFG (V4L2_CID_USER_MTK_CAM_BASE + 19) +#define V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE (V4L2_CID_USER_MTK_CAM_BASE + 20) +#define V4L2_CID_MTK_CAM_CAMSYS_HW_MODE (V4L2_CID_USER_MTK_CAM_BASE + 21) + +/* Luminance+Chrominance formats */ +#define V4L2_PIX_FMT_YUYV10 v4l2_fourcc('Y', 'U', 'Y', 'A') /* 16 YUV 4:2:2 10-bit */ +#define V4L2_PIX_FMT_YVYU10 v4l2_fourcc('Y', 'V', 'Y', 'A') /* 16 YUV 4:2:2 10-bit */ +#define V4L2_PIX_FMT_UYVY10 v4l2_fourcc('U', 'Y', 'V', 'A') /* 16 YUV 4:2:2 10-bit */ +#define V4L2_PIX_FMT_VYUY10 v4l2_fourcc('V', 'Y', 'U', 'A') /* 16 YUV 4:2:2 10-bit */ +#define V4L2_PIX_FMT_YUYV12 v4l2_fourcc('Y', 'U', 'Y', 'C') /* 16 YUV 4:2:2 12-bit */ +#define V4L2_PIX_FMT_YVYU12 v4l2_fourcc('Y', 'V', 'Y', 'C') /* 16 YUV 4:2:2 12-bit */ +#define V4L2_PIX_FMT_UYVY12 v4l2_fourcc('U', 'Y', 'V', 'C') /* 16 YUV 4:2:2 12-bit */ +#define V4L2_PIX_FMT_VYUY12 v4l2_fourcc('V', 'Y', 'U', 'C') /* 16 YUV 4:2:2 12-bit */ + +/* two planes -- one Y, one Cr + Cb interleaved */ +#define V4L2_PIX_FMT_NV12_10 v4l2_fourcc('1', '2', 'A', 'U') /* 12 Y/CbCr 4:2:0 10 bits un-packed */ +#define V4L2_PIX_FMT_NV21_10 v4l2_fourcc('2', '1', 'A', 'U') /* 12 Y/CrCb 4:2:0 10 bits un-packed */ +#define V4L2_PIX_FMT_NV16_10 v4l2_fourcc('1', '6', 'A', 'U') /* 16 Y/CbCr 4:2:2 10 bits un-packed */ +#define V4L2_PIX_FMT_NV61_10 v4l2_fourcc('6', '1', 'A', 'U') /* 16 Y/CrCb 4:2:2 10 bits un-packed */ +#define V4L2_PIX_FMT_NV12_12 v4l2_fourcc('1', '2', 'C', 'U') /* 12 Y/CbCr 4:2:0 12 bits un-packed */ +#define V4L2_PIX_FMT_NV21_12 v4l2_fourcc('2', '1', 'C', 'U') /* 12 Y/CrCb 4:2:0 12 bits un-packed */ +#define V4L2_PIX_FMT_NV16_12 v4l2_fourcc('1', '6', 'C', 'U') /* 16 Y/CbCr 4:2:2 12 bits un-packed */ +#define V4L2_PIX_FMT_NV61_12 v4l2_fourcc('6', '1', 'C', 'U') /* 16 Y/CrCb 4:2:2 12 bits un-packed */ + +/* Vendor specific - MediaTek ISP bayer formats */ +#define V4L2_PIX_FMT_MTISP_SBGGR8 v4l2_fourcc('M', 'B', 'B', '8') /* Packed 8-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG8 v4l2_fourcc('M', 'B', 'G', '8') /* Packed 8-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG8 v4l2_fourcc('M', 'B', 'g', '8') /* Packed 8-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB8 v4l2_fourcc('M', 'B', 'R', '8') /* Packed 8-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR10 v4l2_fourcc('M', 'B', 'B', 'A') /* Packed 10-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG10 v4l2_fourcc('M', 'B', 'G', 'A') /* Packed 10-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG10 v4l2_fourcc('M', 'B', 'g', 'A') /* Packed 10-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB10 v4l2_fourcc('M', 'B', 'R', 'A') /* Packed 10-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR12 v4l2_fourcc('M', 'B', 'B', 'C') /* Packed 12-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG12 v4l2_fourcc('M', 'B', 'G', 'C') /* Packed 12-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG12 v4l2_fourcc('M', 'B', 'g', 'C') /* Packed 12-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB12 v4l2_fourcc('M', 'B', 'R', 'C') /* Packed 12-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR14 v4l2_fourcc('M', 'B', 'B', 'E') /* Packed 14-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG14 v4l2_fourcc('M', 'B', 'G', 'E') /* Packed 14-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG14 v4l2_fourcc('M', 'B', 'g', 'E') /* Packed 14-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB14 v4l2_fourcc('M', 'B', 'R', 'E') /* Packed 14-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR8F v4l2_fourcc('M', 'F', 'B', '8') /* Full-G 8-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG8F v4l2_fourcc('M', 'F', 'G', '8') /* Full-G 8-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG8F v4l2_fourcc('M', 'F', 'g', '8') /* Full-G 8-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB8F v4l2_fourcc('M', 'F', 'R', '8') /* Full-G 8-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR10F v4l2_fourcc('M', 'F', 'B', 'A') /* Full-G 10-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG10F v4l2_fourcc('M', 'F', 'G', 'A') /* Full-G 10-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG10F v4l2_fourcc('M', 'F', 'g', 'A') /* Full-G 10-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB10F v4l2_fourcc('M', 'F', 'R', 'A') /* Full-G 10-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR12F v4l2_fourcc('M', 'F', 'B', 'C') /* Full-G 12-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG12F v4l2_fourcc('M', 'F', 'G', 'C') /* Full-G 12-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG12F v4l2_fourcc('M', 'F', 'g', 'C') /* Full-G 12-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB12F v4l2_fourcc('M', 'F', 'R', 'C') /* Full-G 12-bit */ +#define V4L2_PIX_FMT_MTISP_SBGGR14F v4l2_fourcc('M', 'F', 'B', 'E') /* Full-G 14-bit */ +#define V4L2_PIX_FMT_MTISP_SGBRG14F v4l2_fourcc('M', 'F', 'G', 'E') /* Full-G 14-bit */ +#define V4L2_PIX_FMT_MTISP_SGRBG14F v4l2_fourcc('M', 'F', 'g', 'E') /* Full-G 14-bit */ +#define V4L2_PIX_FMT_MTISP_SRGGB14F v4l2_fourcc('M', 'F', 'R', 'E') /* Full-G 14-bit */ +#define V4L2_PIX_FMT_MTISP_SGRB8F v4l2_fourcc('M', 'F', '8', 'P') /* three planes Full-G 8-bit */ +#define V4L2_PIX_FMT_MTISP_SGRB10F v4l2_fourcc('M', 'F', 'A', 'P') /* three planes Full-G 10-bit */ +#define V4L2_PIX_FMT_MTISP_SGRB12F v4l2_fourcc('M', 'F', 'C', 'P') /* three planes Full-G 12-bit */ + +/* Vendor specific - MediaTek Luminance+Chrominance formats */ +#define V4L2_PIX_FMT_MTISP_YUYV10P v4l2_fourcc('Y', 'U', 'A', 'P') /* YUV 4:2:2 10-bit packed */ +#define V4L2_PIX_FMT_MTISP_YVYU10P v4l2_fourcc('Y', 'V', 'A', 'P') /* YUV 4:2:2 10-bit packed */ +#define V4L2_PIX_FMT_MTISP_UYVY10P v4l2_fourcc('U', 'Y', 'A', 'P') /* YUV 4:2:2 10-bit packed */ +#define V4L2_PIX_FMT_MTISP_VYUY10P v4l2_fourcc('V', 'Y', 'A', 'P') /* YUV 4:2:2 10-bit packed */ +#define V4L2_PIX_FMT_MTISP_NV12_10P v4l2_fourcc('1', '2', 'A', 'P') /* Y/CbCr 4:2:0 10 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV21_10P v4l2_fourcc('2', '1', 'A', 'P') /* Y/CrCb 4:2:0 10 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV16_10P v4l2_fourcc('1', '6', 'A', 'P') /* Y/CbCr 4:2:2 10 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV61_10P v4l2_fourcc('6', '1', 'A', 'P') /* Y/CrCb 4:2:2 10 bits packed */ +#define V4L2_PIX_FMT_MTISP_YUYV12P v4l2_fourcc('Y', 'U', 'C', 'P') /* YUV 4:2:2 12-bit packed */ +#define V4L2_PIX_FMT_MTISP_YVYU12P v4l2_fourcc('Y', 'V', 'C', 'P') /* YUV 4:2:2 12-bit packed */ +#define V4L2_PIX_FMT_MTISP_UYVY12P v4l2_fourcc('U', 'Y', 'C', 'P') /* YUV 4:2:2 12-bit packed */ +#define V4L2_PIX_FMT_MTISP_VYUY12P v4l2_fourcc('V', 'Y', 'C', 'P') /* YUV 4:2:2 12-bit packed */ +#define V4L2_PIX_FMT_MTISP_NV12_12P v4l2_fourcc('1', '2', 'C', 'P') /* Y/CbCr 4:2:0 12 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV21_12P v4l2_fourcc('2', '1', 'C', 'P') /* Y/CrCb 4:2:0 12 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV16_12P v4l2_fourcc('1', '6', 'C', 'P') /* Y/CbCr 4:2:2 12 bits packed */ +#define V4L2_PIX_FMT_MTISP_NV61_12P v4l2_fourcc('6', '1', 'C', 'P') /* Y/CrCb 4:2:2 12 bits packed */ + +/* Vendor specific - MediaTek specified compressed format */ +#define V4L2_PIX_FMT_MTISP_NV12_UFBC v4l2_fourcc('1', '2', '8', 'F') /* Y/CbCr 4:2:0 8 bits compressed */ +#define V4L2_PIX_FMT_MTISP_NV21_UFBC v4l2_fourcc('2', '1', '8', 'F') /* Y/CrCb 4:2:0 8 bits compressed */ +#define V4L2_PIX_FMT_MTISP_NV12_10_UFBC v4l2_fourcc('1', '2', 'A', 'F') /* Y/CbCr 4:2:0 10 bits compressed */ +#define V4L2_PIX_FMT_MTISP_NV21_10_UFBC v4l2_fourcc('2', '1', 'A', 'F') /* Y/CrCb 4:2:0 10 bits compressed */ +#define V4L2_PIX_FMT_MTISP_NV12_12_UFBC v4l2_fourcc('1', '2', 'C', 'F') /* Y/CbCr 4:2:0 12 bits compressed */ +#define V4L2_PIX_FMT_MTISP_NV21_12_UFBC v4l2_fourcc('2', '1', 'C', 'F') /* Y/CrCb 4:2:0 12 bits compressed */ +#define V4L2_PIX_FMT_MTISP_BAYER8_UFBC v4l2_fourcc('M', 'B', '8', 'U') /* Raw 8 bits compressed */ +#define V4L2_PIX_FMT_MTISP_BAYER10_UFBC v4l2_fourcc('M', 'B', 'A', 'U') /* Raw 10 bits compressed */ +#define V4L2_PIX_FMT_MTISP_BAYER12_UFBC v4l2_fourcc('M', 'B', 'C', 'U') /* Raw 12 bits compressed */ +#define V4L2_PIX_FMT_MTISP_BAYER14_UFBC v4l2_fourcc('M', 'B', 'E', 'U') /* Raw 14 bits compressed */ + +/* Vendor specific - MediaTek ISP parameters for firmware */ +#define V4L2_META_FMT_MTISP_3A v4l2_fourcc('M', 'T', 'f', 'a') /* AE/AWB histogram */ +#define V4L2_META_FMT_MTISP_AF v4l2_fourcc('M', 'T', 'f', 'f') /* AF histogram */ +#define V4L2_META_FMT_MTISP_LCS v4l2_fourcc('M', 'T', 'f', 'c') /* Local contrast enhanced statistics */ +#define V4L2_META_FMT_MTISP_LMV v4l2_fourcc('M', 'T', 'f', 'm') /* Local motion vector histogram */ +#define V4L2_META_FMT_MTISP_PARAMS v4l2_fourcc('M', 'T', 'f', 'p') /* ISP tuning parameters */ + +/* + * struct mtk_cam_resource_sensor - sensor resoruces for format negotiation + * + */ +struct mtk_cam_resource_sensor { + struct v4l2_fract interval; + __u32 hblank; + __u32 vblank; + __u64 pixel_rate; + __u64 cust_pixel_rate; +}; + +/* + * struct mtk_cam_resource_raw - MTK camsys raw resoruces for format negotiation + * + * @feature: value of V4L2_CID_MTK_CAM_FEATURE the user want to check the + * resource with. If it is used in set CTRL, we will apply the value + * to V4L2_CID_MTK_CAM_FEATURE ctrl directly. + * @strategy: indicate the order of multiple raws, binning or DVFS to be selected + * when doing format negotiation of raw's source pads (output pads). + * Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to + * determine it. + * @raw_max: indicate the max number of raw to be used for the raw pipeline. + * Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to + * determine it. + * @raw_min: indicate the max number of raw to be used for the raw pipeline. + * Please pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to + * determine it. + * @raw_used: The number of raw used. The used don't need to writ this failed, + * the driver always updates the field. + * @bin: indicate if the driver should enable the bining or not. The driver + * update the field depanding the hardware supporting status. Please pass + * MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to determine it. + * @path_sel: indicate the user selected raw path. The driver + * update the field depanding the hardware supporting status. Please + * pass MTK_CAM_RESOURCE_DEFAULT if you want camsys driver to + * determine it. + * @pixel_mode: the pixel mode driver used in the raw pipeline. It is written by + * driver only. + * @throughput: the throughput be used in the raw pipeline. It is written by + * driver only. + * + */ +struct mtk_cam_resource_raw { + __s64 feature; + __u16 strategy; + __u8 raw_max; + __u8 raw_min; + __u8 raw_used; + __u8 bin; + __u8 path_sel; + __u8 pixel_mode; + __u64 throughput; +}; + +/* + * struct mtk_cam_resource - MTK camsys resoruces for format negotiation + * + * @sink_fmt: sink_fmt pad's format, it must be return by g_fmt or s_fmt + * from driver. + * @sensor_res: senor information to calculate the required resource, it is + * read-only and camsys driver will not change it. + * @raw_res: user hint and resource negotiation result. + * @status: resource negotiation status. + * + */ +struct mtk_cam_resource { + __u64 sink_fmt; + struct mtk_cam_resource_sensor sensor_res; + struct mtk_cam_resource_raw raw_res; + __u8 status; +}; + +/** + * struct mtk_cam_pde_info - PDE module information for raw + * + * @pdo_max_size: the max pdo size of pde sensor. + * @pdi_max_size: the max pdi size of pde sensor or max pd table size. + * @pd_table_offset: the offest of meta config for pd table content. + */ +struct mtk_cam_pde_info { + __u32 pdo_max_size; + __u32 pdi_max_size; + __u32 pd_table_offset; +}; +#endif /* _MTKISP_CAMSYS_USER_H */