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: 13828298 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 C7965CEDD8F for ; Wed, 9 Oct 2024 12:30:50 +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=bN7SwKKEtvlLqX2jDQl1usym2o GY0aktTEcasUDozrWelFy6iyu7nUYe4KoXapg8gMYBnyHwVBTsQWZVjvD+iCLB6tKn+IRLujnvJX5 2iehBRh936TLFIFUKZU5mqkUjR60RT1v/CgxAbdSiZHPqCIGRWoort7TqT14u2WfCpSMMc6+I02wl jGvW7NFx6U3psgekUGA6GN/fd2xTqDkVY07jelE2XKypHlCzmfK5+0QRGASPOrzR3oir0rCy7i/X4 r8rpSKj2wiUIRNIhKqKovk4QGT3mqDJAqhypCRYrTrVueWaDufGeJaLc6OIpLoaQYLeDQuUAICKDn ylx1Ymzw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syVq6-00000009DP0-1CgI; Wed, 09 Oct 2024 12:30:50 +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-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=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:43 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: 13828183 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 17B4CCF0457 for ; Wed, 9 Oct 2024 11:21:44 +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=K8BNr280JSlR7cP0FVamfOuSAUagH9mHOhVDVP8fLWw=; b=Kn+cbWu8iL8YoLHTuIuFUbAv8W LWJf3xkbP9zj7PVWe32uspHFS4UprHXOCHLGkqvDWGL/ywXGIatWoJEUj5zUAM+EuU4Fmb2wYJugt W58OZowsNvf5nNT38wp+teLCR8f2y8yze8Giu3TUiMPTPjIXYdAZrljk7r8CtJFG4o1K/ZPLBeHxq 7L+T76+Y/kRY5smxTD+9CIlIKo5FZeXtP5pNu5XZ4DYWxbEDlb27nPPvsUmb1v84UbN2n6Zaq8N83 3TcpBuBYliVW5BicOFuXa0RZ3U2bwMd2vcYoB1Cw9LSOeTtKFbrkS6wCf4ZY+qbLSFPlUvKwfbIE6 NEtuDDZA==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUlC-000000092Mc-2tM9; Wed, 09 Oct 2024 11:21:42 +0000 Received: from mailgw02.mediatek.com ([216.200.240.185]) by bombadil.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUfw-000000091FD-3Jom; Wed, 09 Oct 2024 11:16:21 +0000 X-UUID: e3092e70862f11efba0aef63c0775dbf-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=K8BNr280JSlR7cP0FVamfOuSAUagH9mHOhVDVP8fLWw=; b=AelIzUc/2btIoMGWlFG2nflOil+dt4Hf6OXuIQTaXLScRkueAYesvWIhgTSXi/bvN6L2A5i6i//Vpj4bq8JpEErRbW8gXaXjyLevR+EVzqKxhg2m1KWOW3Oin1Japlr1DTyNBzv9vGgqz81grkp3AHOfDPJ53M06Oykju6srNqc=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:c77f8f59-2483-44cf-9822-d1e19693e0ca,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:fb53fe64-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: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: e3092e70862f11efba0aef63c0775dbf-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 200941413; Wed, 09 Oct 2024 04:16:10 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by MTKMBS14N1.mediatek.inc (172.21.101.75) 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:06 +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:06 +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 02/10] media: platform: mediatek: add seninf controller Date: Wed, 9 Oct 2024 19:15:43 +0800 Message-ID: <20241009111551.27052-3-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--17.556000-8.000000 X-TMASE-MatchedRID: EOzCvkUI2XJCC3JecVI9Vq+dYEguu4aVJq5DgTAZDtsnynQtBMZAAtnf JrUSEbFD0pQCgxG38xUIkFSbCXH0xc3AmdtMjGJV7spMO3HwKCDDHSNFHFxB8/EJBoK3pfxuUQ3 NFKzJAeyMPepmK8xHyNVf+xUxOpYQN8PEWMb3wtiimtMQe97AAOJ6l5ocmTNK1JVSTP0E9d58rw AwWerBmIKuFcvdRxJ2OvJz+HZ1ghGQqMvYg6LYsJA6S0SjvcYUHQwQ9gfpMR5tw+n+iKWyyBXjz 2Yr0Ugb9mO4udLA1/iVkysc+ADcMw+/n/431GMSJmbrB1j4XwphBfGxmdHCgh68dIEhVd3VjGyk vTEeLpFoBVJLx4KfEAlzTqJYFPTwVo9xxUteKSuyBjDX4sGuTSG4xLksx3hx3HqWhvh1onWPdZV YbQwPh6okLK+BXKXp0uU94EBIvxQUhfC/ipzRk6IBnfMCFBiCzV4D+5YmeSJX14Hy+eYp7yG6/1 cZ3ZJy8DYhDIi7GCYVaq9ckOs5Fn86HKSa2b5kEPf7TDUOGop+iqFlMGARD9BkxehC6ozfXWjvA 8TpWFjy2UZqCS3UtUjBgsju+zn2FO8S2NY+rmVQiFNNqFvt1eTWKSbLQnNIRrVBy6YVY3ieti5l U6HVXLbmsw77/ZAPc+bjHkTJKQR4tYfpnu6UT93FiZsHvaPcfS0Ip2eEHnwj/1Rbkzl1EzZJ+97 rXjiZZvJ+4w4nZnXdB/CxWTRRu4BQLWahPl6cftwZ3X11IV0= X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--17.556000-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: D8B3024DF2B3BE7226B45E2FAF7B41A06BA7CE91B492EA68B86B8AC2FF89AC352000:8 X-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Introduces support for the sensor interface in the MediaTek SoC, with the focus on CSI and stream control. The key functionalities include parameter control, metering and maintaining status information, interrupt handling, and debugging. These features ensure effective management and debugging of the camera sensor interface hardware. Signed-off-by: Shu-hsiang Yang --- .../isp_7x/camsys/mtk_csi_phy_2_0/Makefile | 5 + .../mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h | 911 ++++++ .../mtk_cam-seninf-csi0-cphy.h | 69 + .../mtk_cam-seninf-csi0-dphy.h | 139 + .../mtk_cam-seninf-hw_phy_2_0.c | 2879 +++++++++++++++++ .../mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h | 257 ++ .../mtk_cam-seninf-seninf1-csi2.h | 415 +++ .../mtk_cam-seninf-seninf1-mux.h | 147 + .../mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h | 47 + .../mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h | 49 + .../mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h | 99 + 11 files changed, 5017 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile new file mode 100644 index 000000000000..e00b8d3904a9 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: GPL-2.0 +# Copyright (C) 2022 MediaTek Inc. + +mtk-cam-isp-objs += \ + mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.o diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h new file mode 100644 index 000000000000..ec3c621d742a --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-cammux.h @@ -0,0 +1,911 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF_CAM_MUX_H__ +#define __SENINF_CAM_MUX_H__ + +#define SENINF_CAM_MUX_CTRL_0 0x0000 +#define RG_SENINF_CAM_MUX0_SRC_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX0_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_CAM_MUX1_SRC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX1_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_CAM_MUX2_SRC_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX2_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_CAM_MUX3_SRC_SEL_SHIFT 24 +#define RG_SENINF_CAM_MUX3_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_CTRL_1 0x0004 +#define RG_SENINF_CAM_MUX4_SRC_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX4_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_CAM_MUX5_SRC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX5_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_CAM_MUX6_SRC_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX6_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_CAM_MUX7_SRC_SEL_SHIFT 24 +#define RG_SENINF_CAM_MUX7_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_CTRL_2 0x0008 +#define RG_SENINF_CAM_MUX8_SRC_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX8_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_CAM_MUX9_SRC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX9_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_CAM_MUX10_SRC_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX10_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_CAM_MUX11_SRC_SEL_SHIFT 24 +#define RG_SENINF_CAM_MUX11_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_CTRL_3 0x000c +#define RG_SENINF_CAM_MUX12_SRC_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX12_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_CAM_MUX13_SRC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX13_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_CAM_MUX14_SRC_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX14_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_CAM_MUX15_SRC_SEL_SHIFT 24 +#define RG_SENINF_CAM_MUX15_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_EN 0x0010 +#define SENINF_CAM_MUX0_EN_SHIFT 0 +#define SENINF_CAM_MUX0_EN_MASK (0x1 << 0) +#define SENINF_CAM_MUX1_EN_SHIFT 1 +#define SENINF_CAM_MUX1_EN_MASK (0x1 << 1) +#define SENINF_CAM_MUX2_EN_SHIFT 2 +#define SENINF_CAM_MUX2_EN_MASK (0x1 << 2) +#define SENINF_CAM_MUX3_EN_SHIFT 3 +#define SENINF_CAM_MUX3_EN_MASK (0x1 << 3) +#define SENINF_CAM_MUX4_EN_SHIFT 4 +#define SENINF_CAM_MUX4_EN_MASK (0x1 << 4) +#define SENINF_CAM_MUX5_EN_SHIFT 5 +#define SENINF_CAM_MUX5_EN_MASK (0x1 << 5) +#define SENINF_CAM_MUX6_EN_SHIFT 6 +#define SENINF_CAM_MUX6_EN_MASK (0x1 << 6) +#define SENINF_CAM_MUX7_EN_SHIFT 7 +#define SENINF_CAM_MUX7_EN_MASK (0x1 << 7) +#define SENINF_CAM_MUX8_EN_SHIFT 8 +#define SENINF_CAM_MUX8_EN_MASK (0x1 << 8) +#define SENINF_CAM_MUX9_EN_SHIFT 9 +#define SENINF_CAM_MUX9_EN_MASK (0x1 << 9) +#define SENINF_CAM_MUX10_EN_SHIFT 10 +#define SENINF_CAM_MUX10_EN_MASK (0x1 << 10) +#define SENINF_CAM_MUX11_EN_SHIFT 11 +#define SENINF_CAM_MUX11_EN_MASK (0x1 << 11) +#define SENINF_CAM_MUX12_EN_SHIFT 12 +#define SENINF_CAM_MUX12_EN_MASK (0x1 << 12) +#define SENINF_CAM_MUX13_EN_SHIFT 13 +#define SENINF_CAM_MUX13_EN_MASK (0x1 << 13) +#define SENINF_CAM_MUX14_EN_SHIFT 14 +#define SENINF_CAM_MUX14_EN_MASK (0x1 << 14) +#define SENINF_CAM_MUX15_EN_SHIFT 15 +#define SENINF_CAM_MUX15_EN_MASK (0x1 << 15) + +#define SENINF_CAM_MUX_CHK_EN 0x0018 +#define SENINF_CAM_MUX0_CHK_EN_SHIFT 0 +#define SENINF_CAM_MUX0_CHK_EN_MASK (0x1 << 0) +#define SENINF_CAM_MUX1_CHK_EN_SHIFT 1 +#define SENINF_CAM_MUX1_CHK_EN_MASK (0x1 << 1) +#define SENINF_CAM_MUX2_CHK_EN_SHIFT 2 +#define SENINF_CAM_MUX2_CHK_EN_MASK (0x1 << 2) +#define SENINF_CAM_MUX3_CHK_EN_SHIFT 3 +#define SENINF_CAM_MUX3_CHK_EN_MASK (0x1 << 3) +#define SENINF_CAM_MUX4_CHK_EN_SHIFT 4 +#define SENINF_CAM_MUX4_CHK_EN_MASK (0x1 << 4) +#define SENINF_CAM_MUX5_CHK_EN_SHIFT 5 +#define SENINF_CAM_MUX5_CHK_EN_MASK (0x1 << 5) +#define SENINF_CAM_MUX6_CHK_EN_SHIFT 6 +#define SENINF_CAM_MUX6_CHK_EN_MASK (0x1 << 6) +#define SENINF_CAM_MUX7_CHK_EN_SHIFT 7 +#define SENINF_CAM_MUX7_CHK_EN_MASK (0x1 << 7) +#define SENINF_CAM_MUX8_CHK_EN_SHIFT 8 +#define SENINF_CAM_MUX8_CHK_EN_MASK (0x1 << 8) +#define SENINF_CAM_MUX9_CHK_EN_SHIFT 9 +#define SENINF_CAM_MUX9_CHK_EN_MASK (0x1 << 9) +#define SENINF_CAM_MUX10_CHK_EN_SHIFT 10 +#define SENINF_CAM_MUX10_CHK_EN_MASK (0x1 << 10) +#define SENINF_CAM_MUX11_CHK_EN_SHIFT 11 +#define SENINF_CAM_MUX11_CHK_EN_MASK (0x1 << 11) +#define SENINF_CAM_MUX12_CHK_EN_SHIFT 12 +#define SENINF_CAM_MUX12_CHK_EN_MASK (0x1 << 12) +#define SENINF_CAM_MUX13_CHK_EN_SHIFT 13 +#define SENINF_CAM_MUX13_CHK_EN_MASK (0x1 << 13) +#define SENINF_CAM_MUX14_CHK_EN_SHIFT 14 +#define SENINF_CAM_MUX14_CHK_EN_MASK (0x1 << 14) +#define SENINF_CAM_MUX15_CHK_EN_SHIFT 15 +#define SENINF_CAM_MUX15_CHK_EN_MASK (0x1 << 15) + +#define SENINF_CAM_MUX0_OPT 0x0020 +#define RG_SENINF_CAM_MUX0_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX0_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX0_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX0_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX0_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX0_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX0_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX0_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX0_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX0_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX1_OPT 0x0024 +#define RG_SENINF_CAM_MUX1_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX1_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX1_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX1_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX1_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX1_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX1_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX1_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX1_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX1_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX2_OPT 0x0028 +#define RG_SENINF_CAM_MUX2_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX2_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX2_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX2_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX2_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX2_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX2_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX2_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX2_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX2_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX3_OPT 0x002c +#define RG_SENINF_CAM_MUX3_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX3_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX3_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX3_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX3_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX3_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX3_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX3_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX3_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX3_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX4_OPT 0x0030 +#define RG_SENINF_CAM_MUX4_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX4_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX4_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX4_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX4_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX4_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX4_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX4_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX4_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX4_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX5_OPT 0x0034 +#define RG_SENINF_CAM_MUX5_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX5_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX5_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX5_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX5_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX5_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX5_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX5_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX5_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX5_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX6_OPT 0x0038 +#define RG_SENINF_CAM_MUX6_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX6_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX6_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX6_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX6_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX6_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX6_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX6_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX6_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX6_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX7_OPT 0x003c +#define RG_SENINF_CAM_MUX7_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX7_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX7_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX7_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX7_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX7_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX7_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX7_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX7_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX7_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX8_OPT 0x0040 +#define RG_SENINF_CAM_MUX8_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX8_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX8_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX8_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX8_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX8_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX8_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX8_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX8_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX8_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX9_OPT 0x0044 +#define RG_SENINF_CAM_MUX9_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX9_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX9_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX9_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX9_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX9_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX9_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX9_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX9_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX9_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX10_OPT 0x0048 +#define RG_SENINF_CAM_MUX10_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX10_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX10_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX10_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX10_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX10_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX10_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX10_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX10_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX10_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX11_OPT 0x004c +#define RG_SENINF_CAM_MUX11_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX11_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX11_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX11_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX11_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX11_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX11_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX11_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX11_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX11_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX12_OPT 0x0050 +#define RG_SENINF_CAM_MUX12_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX12_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX12_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX12_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX12_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX12_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX12_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX12_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX12_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX12_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX13_OPT 0x0054 +#define RG_SENINF_CAM_MUX13_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX13_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX13_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX13_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX13_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX13_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX13_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX13_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX13_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX13_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX14_OPT 0x0058 +#define RG_SENINF_CAM_MUX14_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX14_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX14_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX14_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX14_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX14_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX14_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX14_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX14_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX14_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX15_OPT 0x005c +#define RG_SENINF_CAM_MUX15_VC_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX15_VC_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX15_DT_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX15_DT_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX15_VC_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX15_VC_SEL_MASK (0x1f << 8) +#define RG_SENINF_CAM_MUX15_DT_SEL_SHIFT 16 +#define RG_SENINF_CAM_MUX15_DT_SEL_MASK (0x3f << 16) +#define RG_SENINF_CAM_MUX15_VSYNC_BYPASS_SHIFT 24 +#define RG_SENINF_CAM_MUX15_VSYNC_BYPASS_MASK (0x1 << 24) + +#define SENINF_CAM_MUX_CTRL 0x0080 +#define SENINF_CAM_MUX_SW_RST_SHIFT 0 +#define SENINF_CAM_MUX_SW_RST_MASK (0x1 << 0) +#define SENINF_CAM_MUX_IRQ_SW_RST_SHIFT 1 +#define SENINF_CAM_MUX_IRQ_SW_RST_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX_SLICE_FULL_OPT_SHIFT 7 +#define RG_SENINF_CAM_MUX_SLICE_FULL_OPT_MASK (0x1 << 7) +#define RG_SENINF_CAM_MUX_IRQ_CLR_MODE_SHIFT 8 +#define RG_SENINF_CAM_MUX_IRQ_CLR_MODE_MASK (0x1 << 8) +#define RG_SENINF_CAM_MUX_IRQ_VERIF_EN_SHIFT 9 +#define RG_SENINF_CAM_MUX_IRQ_VERIF_EN_MASK (0x1 << 9) + +#define SENINF_CAM_MUX_DYN_CTRL 0x0088 +#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0_SHIFT 0 +#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1_SHIFT 4 +#define RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1_MASK (0x1 << 4) +#define CAM_MUX_DYN_PAGE_SEL_SHIFT 28 +#define CAM_MUX_DYN_PAGE_SEL_MASK (0x1 << 28) + +#define SENINF_CAM_MUX_DYN_EN 0x008c +#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN0_SHIFT 0 +#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN0_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN1_SHIFT 16 +#define RG_SENINF_CAM_MUX_DYN_SWITCH_EN1_MASK (0xffff << 16) + +#define SENINF_CAM_MUX_NEXT_CTRL_0 0x0090 +#define CAM_MUX0_NEXT_SRC_SEL_SHIFT 0 +#define CAM_MUX0_NEXT_SRC_SEL_MASK (0xf << 0) +#define CAM_MUX1_NEXT_SRC_SEL_SHIFT 8 +#define CAM_MUX1_NEXT_SRC_SEL_MASK (0xf << 8) +#define CAM_MUX2_NEXT_SRC_SEL_SHIFT 16 +#define CAM_MUX2_NEXT_SRC_SEL_MASK (0xf << 16) +#define CAM_MUX3_NEXT_SRC_SEL_SHIFT 24 +#define CAM_MUX3_NEXT_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_NEXT_CTRL_1 0x0094 +#define CAM_MUX4_NEXT_SRC_SEL_SHIFT 0 +#define CAM_MUX4_NEXT_SRC_SEL_MASK (0xf << 0) +#define CAM_MUX5_NEXT_SRC_SEL_SHIFT 8 +#define CAM_MUX5_NEXT_SRC_SEL_MASK (0xf << 8) +#define CAM_MUX6_NEXT_SRC_SEL_SHIFT 16 +#define CAM_MUX6_NEXT_SRC_SEL_MASK (0xf << 16) +#define CAM_MUX7_NEXT_SRC_SEL_SHIFT 24 +#define CAM_MUX7_NEXT_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_NEXT_CTRL_2 0x0098 +#define CAM_MUX8_NEXT_SRC_SEL_SHIFT 0 +#define CAM_MUX8_NEXT_SRC_SEL_MASK (0xf << 0) +#define CAM_MUX9_NEXT_SRC_SEL_SHIFT 8 +#define CAM_MUX9_NEXT_SRC_SEL_MASK (0xf << 8) +#define CAM_MUX10_NEXT_SRC_SEL_SHIFT 16 +#define CAM_MUX10_NEXT_SRC_SEL_MASK (0xf << 16) +#define CAM_MUX11_NEXT_SRC_SEL_SHIFT 24 +#define CAM_MUX11_NEXT_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_NEXT_CTRL_3 0x009c +#define CAM_MUX12_NEXT_SRC_SEL_SHIFT 0 +#define CAM_MUX12_NEXT_SRC_SEL_MASK (0xf << 0) +#define CAM_MUX13_NEXT_SRC_SEL_SHIFT 8 +#define CAM_MUX13_NEXT_SRC_SEL_MASK (0xf << 8) +#define CAM_MUX14_NEXT_SRC_SEL_SHIFT 16 +#define CAM_MUX14_NEXT_SRC_SEL_MASK (0xf << 16) +#define CAM_MUX15_NEXT_SRC_SEL_SHIFT 24 +#define CAM_MUX15_NEXT_SRC_SEL_MASK (0xf << 24) + +#define SENINF_CAM_MUX_IRQ_EN 0x00a0 +#define RG_SENINF_CAM_MUX0_HSIZE_ERR_IRQ_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX0_HSIZE_ERR_IRQ_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX0_VSIZE_ERR_IRQ_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX0_VSIZE_ERR_IRQ_EN_MASK (0x1 << 1) +#define RG_SENINF_CAM_MUX1_HSIZE_ERR_IRQ_EN_SHIFT 2 +#define RG_SENINF_CAM_MUX1_HSIZE_ERR_IRQ_EN_MASK (0x1 << 2) +#define RG_SENINF_CAM_MUX1_VSIZE_ERR_IRQ_EN_SHIFT 3 +#define RG_SENINF_CAM_MUX1_VSIZE_ERR_IRQ_EN_MASK (0x1 << 3) +#define RG_SENINF_CAM_MUX2_HSIZE_ERR_IRQ_EN_SHIFT 4 +#define RG_SENINF_CAM_MUX2_HSIZE_ERR_IRQ_EN_MASK (0x1 << 4) +#define RG_SENINF_CAM_MUX2_VSIZE_ERR_IRQ_EN_SHIFT 5 +#define RG_SENINF_CAM_MUX2_VSIZE_ERR_IRQ_EN_MASK (0x1 << 5) +#define RG_SENINF_CAM_MUX3_HSIZE_ERR_IRQ_EN_SHIFT 6 +#define RG_SENINF_CAM_MUX3_HSIZE_ERR_IRQ_EN_MASK (0x1 << 6) +#define RG_SENINF_CAM_MUX3_VSIZE_ERR_IRQ_EN_SHIFT 7 +#define RG_SENINF_CAM_MUX3_VSIZE_ERR_IRQ_EN_MASK (0x1 << 7) +#define RG_SENINF_CAM_MUX4_HSIZE_ERR_IRQ_EN_SHIFT 8 +#define RG_SENINF_CAM_MUX4_HSIZE_ERR_IRQ_EN_MASK (0x1 << 8) +#define RG_SENINF_CAM_MUX4_VSIZE_ERR_IRQ_EN_SHIFT 9 +#define RG_SENINF_CAM_MUX4_VSIZE_ERR_IRQ_EN_MASK (0x1 << 9) +#define RG_SENINF_CAM_MUX5_HSIZE_ERR_IRQ_EN_SHIFT 10 +#define RG_SENINF_CAM_MUX5_HSIZE_ERR_IRQ_EN_MASK (0x1 << 10) +#define RG_SENINF_CAM_MUX5_VSIZE_ERR_IRQ_EN_SHIFT 11 +#define RG_SENINF_CAM_MUX5_VSIZE_ERR_IRQ_EN_MASK (0x1 << 11) +#define RG_SENINF_CAM_MUX6_HSIZE_ERR_IRQ_EN_SHIFT 12 +#define RG_SENINF_CAM_MUX6_HSIZE_ERR_IRQ_EN_MASK (0x1 << 12) +#define RG_SENINF_CAM_MUX6_VSIZE_ERR_IRQ_EN_SHIFT 13 +#define RG_SENINF_CAM_MUX6_VSIZE_ERR_IRQ_EN_MASK (0x1 << 13) +#define RG_SENINF_CAM_MUX7_HSIZE_ERR_IRQ_EN_SHIFT 14 +#define RG_SENINF_CAM_MUX7_HSIZE_ERR_IRQ_EN_MASK (0x1 << 14) +#define RG_SENINF_CAM_MUX7_VSIZE_ERR_IRQ_EN_SHIFT 15 +#define RG_SENINF_CAM_MUX7_VSIZE_ERR_IRQ_EN_MASK (0x1 << 15) +#define RG_SENINF_CAM_MUX8_HSIZE_ERR_IRQ_EN_SHIFT 16 +#define RG_SENINF_CAM_MUX8_HSIZE_ERR_IRQ_EN_MASK (0x1 << 16) +#define RG_SENINF_CAM_MUX8_VSIZE_ERR_IRQ_EN_SHIFT 17 +#define RG_SENINF_CAM_MUX8_VSIZE_ERR_IRQ_EN_MASK (0x1 << 17) +#define RG_SENINF_CAM_MUX9_HSIZE_ERR_IRQ_EN_SHIFT 18 +#define RG_SENINF_CAM_MUX9_HSIZE_ERR_IRQ_EN_MASK (0x1 << 18) +#define RG_SENINF_CAM_MUX9_VSIZE_ERR_IRQ_EN_SHIFT 19 +#define RG_SENINF_CAM_MUX9_VSIZE_ERR_IRQ_EN_MASK (0x1 << 19) +#define RG_SENINF_CAM_MUX10_HSIZE_ERR_IRQ_EN_SHIFT 20 +#define RG_SENINF_CAM_MUX10_HSIZE_ERR_IRQ_EN_MASK (0x1 << 20) +#define RG_SENINF_CAM_MUX10_VSIZE_ERR_IRQ_EN_SHIFT 21 +#define RG_SENINF_CAM_MUX10_VSIZE_ERR_IRQ_EN_MASK (0x1 << 21) +#define RG_SENINF_CAM_MUX11_HSIZE_ERR_IRQ_EN_SHIFT 22 +#define RG_SENINF_CAM_MUX11_HSIZE_ERR_IRQ_EN_MASK (0x1 << 22) +#define RG_SENINF_CAM_MUX11_VSIZE_ERR_IRQ_EN_SHIFT 23 +#define RG_SENINF_CAM_MUX11_VSIZE_ERR_IRQ_EN_MASK (0x1 << 23) +#define RG_SENINF_CAM_MUX12_HSIZE_ERR_IRQ_EN_SHIFT 24 +#define RG_SENINF_CAM_MUX12_HSIZE_ERR_IRQ_EN_MASK (0x1 << 24) +#define RG_SENINF_CAM_MUX12_VSIZE_ERR_IRQ_EN_SHIFT 25 +#define RG_SENINF_CAM_MUX12_VSIZE_ERR_IRQ_EN_MASK (0x1 << 25) +#define RG_SENINF_CAM_MUX13_HSIZE_ERR_IRQ_EN_SHIFT 26 +#define RG_SENINF_CAM_MUX13_HSIZE_ERR_IRQ_EN_MASK (0x1 << 26) +#define RG_SENINF_CAM_MUX13_VSIZE_ERR_IRQ_EN_SHIFT 27 +#define RG_SENINF_CAM_MUX13_VSIZE_ERR_IRQ_EN_MASK (0x1 << 27) +#define RG_SENINF_CAM_MUX14_HSIZE_ERR_IRQ_EN_SHIFT 28 +#define RG_SENINF_CAM_MUX14_HSIZE_ERR_IRQ_EN_MASK (0x1 << 28) +#define RG_SENINF_CAM_MUX14_VSIZE_ERR_IRQ_EN_SHIFT 29 +#define RG_SENINF_CAM_MUX14_VSIZE_ERR_IRQ_EN_MASK (0x1 << 29) +#define RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN_SHIFT 30 +#define RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN_MASK (0x1 << 30) +#define RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN_SHIFT 31 +#define RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN_MASK (0x1 << 31) + +#define SENINF_CAM_MUX_IRQ_STATUS 0x00a8 +#define RO_SENINF_CAM_MUX0_HSIZE_ERR_IRQ_SHIFT 0 +#define RO_SENINF_CAM_MUX0_HSIZE_ERR_IRQ_MASK (0x1 << 0) +#define RO_SENINF_CAM_MUX0_VSIZE_ERR_IRQ_SHIFT 1 +#define RO_SENINF_CAM_MUX0_VSIZE_ERR_IRQ_MASK (0x1 << 1) +#define RO_SENINF_CAM_MUX1_HSIZE_ERR_IRQ_SHIFT 2 +#define RO_SENINF_CAM_MUX1_HSIZE_ERR_IRQ_MASK (0x1 << 2) +#define RO_SENINF_CAM_MUX1_VSIZE_ERR_IRQ_SHIFT 3 +#define RO_SENINF_CAM_MUX1_VSIZE_ERR_IRQ_MASK (0x1 << 3) +#define RO_SENINF_CAM_MUX2_HSIZE_ERR_IRQ_SHIFT 4 +#define RO_SENINF_CAM_MUX2_HSIZE_ERR_IRQ_MASK (0x1 << 4) +#define RO_SENINF_CAM_MUX2_VSIZE_ERR_IRQ_SHIFT 5 +#define RO_SENINF_CAM_MUX2_VSIZE_ERR_IRQ_MASK (0x1 << 5) +#define RO_SENINF_CAM_MUX3_HSIZE_ERR_IRQ_SHIFT 6 +#define RO_SENINF_CAM_MUX3_HSIZE_ERR_IRQ_MASK (0x1 << 6) +#define RO_SENINF_CAM_MUX3_VSIZE_ERR_IRQ_SHIFT 7 +#define RO_SENINF_CAM_MUX3_VSIZE_ERR_IRQ_MASK (0x1 << 7) +#define RO_SENINF_CAM_MUX4_HSIZE_ERR_IRQ_SHIFT 8 +#define RO_SENINF_CAM_MUX4_HSIZE_ERR_IRQ_MASK (0x1 << 8) +#define RO_SENINF_CAM_MUX4_VSIZE_ERR_IRQ_SHIFT 9 +#define RO_SENINF_CAM_MUX4_VSIZE_ERR_IRQ_MASK (0x1 << 9) +#define RO_SENINF_CAM_MUX5_HSIZE_ERR_IRQ_SHIFT 10 +#define RO_SENINF_CAM_MUX5_HSIZE_ERR_IRQ_MASK (0x1 << 10) +#define RO_SENINF_CAM_MUX5_VSIZE_ERR_IRQ_SHIFT 11 +#define RO_SENINF_CAM_MUX5_VSIZE_ERR_IRQ_MASK (0x1 << 11) +#define RO_SENINF_CAM_MUX6_HSIZE_ERR_IRQ_SHIFT 12 +#define RO_SENINF_CAM_MUX6_HSIZE_ERR_IRQ_MASK (0x1 << 12) +#define RO_SENINF_CAM_MUX6_VSIZE_ERR_IRQ_SHIFT 13 +#define RO_SENINF_CAM_MUX6_VSIZE_ERR_IRQ_MASK (0x1 << 13) +#define RO_SENINF_CAM_MUX7_HSIZE_ERR_IRQ_SHIFT 14 +#define RO_SENINF_CAM_MUX7_HSIZE_ERR_IRQ_MASK (0x1 << 14) +#define RO_SENINF_CAM_MUX7_VSIZE_ERR_IRQ_SHIFT 15 +#define RO_SENINF_CAM_MUX7_VSIZE_ERR_IRQ_MASK (0x1 << 15) +#define RO_SENINF_CAM_MUX8_HSIZE_ERR_IRQ_SHIFT 16 +#define RO_SENINF_CAM_MUX8_HSIZE_ERR_IRQ_MASK (0x1 << 16) +#define RO_SENINF_CAM_MUX8_VSIZE_ERR_IRQ_SHIFT 17 +#define RO_SENINF_CAM_MUX8_VSIZE_ERR_IRQ_MASK (0x1 << 17) +#define RO_SENINF_CAM_MUX9_HSIZE_ERR_IRQ_SHIFT 18 +#define RO_SENINF_CAM_MUX9_HSIZE_ERR_IRQ_MASK (0x1 << 18) +#define RO_SENINF_CAM_MUX9_VSIZE_ERR_IRQ_SHIFT 19 +#define RO_SENINF_CAM_MUX9_VSIZE_ERR_IRQ_MASK (0x1 << 19) +#define RO_SENINF_CAM_MUX10_HSIZE_ERR_IRQ_SHIFT 20 +#define RO_SENINF_CAM_MUX10_HSIZE_ERR_IRQ_MASK (0x1 << 20) +#define RO_SENINF_CAM_MUX10_VSIZE_ERR_IRQ_SHIFT 21 +#define RO_SENINF_CAM_MUX10_VSIZE_ERR_IRQ_MASK (0x1 << 21) +#define RO_SENINF_CAM_MUX11_HSIZE_ERR_IRQ_SHIFT 22 +#define RO_SENINF_CAM_MUX11_HSIZE_ERR_IRQ_MASK (0x1 << 22) +#define RO_SENINF_CAM_MUX11_VSIZE_ERR_IRQ_SHIFT 23 +#define RO_SENINF_CAM_MUX11_VSIZE_ERR_IRQ_MASK (0x1 << 23) +#define RO_SENINF_CAM_MUX12_HSIZE_ERR_IRQ_SHIFT 24 +#define RO_SENINF_CAM_MUX12_HSIZE_ERR_IRQ_MASK (0x1 << 24) +#define RO_SENINF_CAM_MUX12_VSIZE_ERR_IRQ_SHIFT 25 +#define RO_SENINF_CAM_MUX12_VSIZE_ERR_IRQ_MASK (0x1 << 25) +#define RO_SENINF_CAM_MUX13_HSIZE_ERR_IRQ_SHIFT 26 +#define RO_SENINF_CAM_MUX13_HSIZE_ERR_IRQ_MASK (0x1 << 26) +#define RO_SENINF_CAM_MUX13_VSIZE_ERR_IRQ_SHIFT 27 +#define RO_SENINF_CAM_MUX13_VSIZE_ERR_IRQ_MASK (0x1 << 27) +#define RO_SENINF_CAM_MUX14_HSIZE_ERR_IRQ_SHIFT 28 +#define RO_SENINF_CAM_MUX14_HSIZE_ERR_IRQ_MASK (0x1 << 28) +#define RO_SENINF_CAM_MUX14_VSIZE_ERR_IRQ_SHIFT 29 +#define RO_SENINF_CAM_MUX14_VSIZE_ERR_IRQ_MASK (0x1 << 29) +#define RO_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_SHIFT 30 +#define RO_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_MASK (0x1 << 30) +#define RO_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_SHIFT 31 +#define RO_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_MASK (0x1 << 31) + +#define SENINF_CAM_MUX_VSYNC_IRQ_EN 0x00b0 +#define RG_SENINF_CAM_MUX_VSYNC_IRQ_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX_VSYNC_IRQ_EN_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX_VSYNC_ALL_IRQ_EN_SHIFT 24 +#define RG_SENINF_CAM_MUX_VSYNC_ALL_IRQ_EN_MASK (0x3 << 24) +#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ_EN_SHIFT 28 +#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ_EN_MASK (0x3 << 28) + +#define SENINF_CAM_MUX_VSYNC_IRQ_STS 0x00b4 +#define RO_SENINF_CAM_MUX_VSYNC_IRQ_SHIFT 0 +#define RO_SENINF_CAM_MUX_VSYNC_IRQ_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX_VSYNC_ALL_IRQ_SHIFT 24 +#define RO_SENINF_CAM_MUX_VSYNC_ALL_IRQ_MASK (0x3 << 24) +#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ_SHIFT 28 +#define RG_SENINF_CAM_MUX_VSYNC_ALL_NONE_IRQ_MASK (0x3 << 28) + +#define SENINF_CAM_MUX_DBG_CTRL 0x00c0 +#define RG_SENINF_CAM_MUX_DBG_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX_DBG_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX_DBG_SEL_SHIFT 8 +#define RG_SENINF_CAM_MUX_DBG_SEL_MASK (0xff << 8) + +#define SENINF_CAM_MUX_DBG_OUT 0x00c4 +#define RO_SENINF_CAM_MUX_DBG_OUT_SHIFT 0 +#define RO_SENINF_CAM_MUX_DBG_OUT_MASK (0xffffffff << 0) + +#define SENINF_CAM_MUX_VSYNC_T0_WINDOW_L 0x00d0 +#define RG_SENINF_CAM_MUX_VSYNC_TIMER0_WINDOW_L_SHIFT 0 +#define RG_SENINF_CAM_MUX_VSYNC_TIMER0_WINDOW_L_MASK (0xffffffff << 0) + +#define SENINF_CAM_MUX_VSYNC_T1_WINDOW_L 0x00d8 +#define RG_SENINF_CAM_MUX_VSYNC_TIMER1_WINDOW_L_SHIFT 0 +#define RG_SENINF_CAM_MUX_VSYNC_TIMER1_WINDOW_L_MASK (0xffffffff << 0) + +#define SENINF_CAM_MUX_SAT_IRQ_EN 0x00e0 +#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ_EN_SHIFT 0 +#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ_EN_MASK (0x1 << 0) +#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ_EN_SHIFT 1 +#define RG_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ_EN_MASK (0x1 << 1) + +#define SENINF_CAM_MUX_SAT_IRQ_STATUS 0x00e8 +#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ_SHIFT 0 +#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE0_IRQ_MASK (0x1 << 0) +#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ_SHIFT 1 +#define RO_SENINF_CAM_MUX_SKIP_NEXT_FRAME_EN_RISE1_IRQ_MASK (0x1 << 1) + +#define SENINF_CAM_SPARE 0x00f8 +#define RG_SENINF_TOP_SPARE_0_SHIFT 0 +#define RG_SENINF_TOP_SPARE_0_MASK (0xff << 0) +#define RG_SENINF_TOP_SPARE_1_SHIFT 16 +#define RG_SENINF_TOP_SPARE_1_MASK (0xff << 16) + +#define SENINF_CAM_MUX0_CHK_CTL_0 0x0100 +#define RG_SENINF_CAM_MUX0_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX0_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX0_CHK_CTL_1 0x0104 +#define RG_SENINF_CAM_MUX0_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX0_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX0_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX0_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX0_CHK_RES 0x0108 +#define RO_SENINF_CAM_MUX0_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX0_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX0_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX0_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX0_CHK_ERR_RES 0x010c +#define RO_SENINF_CAM_MUX0_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX0_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX0_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX0_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX1_CHK_CTL_0 0x0110 +#define RG_SENINF_CAM_MUX1_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX1_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX1_CHK_CTL_1 0x0114 +#define RG_SENINF_CAM_MUX1_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX1_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX1_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX1_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX1_CHK_RES 0x0118 +#define RO_SENINF_CAM_MUX1_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX1_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX1_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX1_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX1_CHK_ERR_RES 0x011c +#define RO_SENINF_CAM_MUX1_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX1_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX1_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX1_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX2_CHK_CTL_0 0x0120 +#define RG_SENINF_CAM_MUX2_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX2_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX2_CHK_CTL_1 0x0124 +#define RG_SENINF_CAM_MUX2_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX2_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX2_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX2_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX2_CHK_RES 0x0128 +#define RO_SENINF_CAM_MUX2_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX2_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX2_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX2_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX2_CHK_ERR_RES 0x012c +#define RO_SENINF_CAM_MUX2_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX2_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX2_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX2_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX3_CHK_CTL_0 0x0130 +#define RG_SENINF_CAM_MUX3_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX3_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX3_CHK_CTL_1 0x0134 +#define RG_SENINF_CAM_MUX3_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX3_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX3_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX3_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX3_CHK_RES 0x0138 +#define RO_SENINF_CAM_MUX3_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX3_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX3_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX3_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX3_CHK_ERR_RES 0x013c +#define RO_SENINF_CAM_MUX3_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX3_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX3_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX3_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX4_CHK_CTL_0 0x0140 +#define RG_SENINF_CAM_MUX4_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX4_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX4_CHK_CTL_1 0x0144 +#define RG_SENINF_CAM_MUX4_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX4_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX4_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX4_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX4_CHK_RES 0x0148 +#define RO_SENINF_CAM_MUX4_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX4_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX4_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX4_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX4_CHK_ERR_RES 0x014c +#define RO_SENINF_CAM_MUX4_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX4_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX4_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX4_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX5_CHK_CTL_0 0x0150 +#define RG_SENINF_CAM_MUX5_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX5_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX5_CHK_CTL_1 0x0154 +#define RG_SENINF_CAM_MUX5_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX5_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX5_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX5_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX5_CHK_RES 0x0158 +#define RO_SENINF_CAM_MUX5_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX5_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX5_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX5_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX5_CHK_ERR_RES 0x015c +#define RO_SENINF_CAM_MUX5_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX5_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX5_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX5_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX6_CHK_CTL_0 0x0160 +#define RG_SENINF_CAM_MUX6_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX6_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX6_CHK_CTL_1 0x0164 +#define RG_SENINF_CAM_MUX6_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX6_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX6_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX6_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX6_CHK_RES 0x0168 +#define RO_SENINF_CAM_MUX6_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX6_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX6_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX6_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX6_CHK_ERR_RES 0x016c +#define RO_SENINF_CAM_MUX6_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX6_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX6_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX6_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX7_CHK_CTL_0 0x0170 +#define RG_SENINF_CAM_MUX7_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX7_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX7_CHK_CTL_1 0x0174 +#define RG_SENINF_CAM_MUX7_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX7_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX7_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX7_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX7_CHK_RES 0x0178 +#define RO_SENINF_CAM_MUX7_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX7_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX7_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX7_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX7_CHK_ERR_RES 0x017c +#define RO_SENINF_CAM_MUX7_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX7_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX7_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX7_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX8_CHK_CTL_0 0x0180 +#define RG_SENINF_CAM_MUX8_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX8_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX8_CHK_CTL_1 0x0184 +#define RG_SENINF_CAM_MUX8_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX8_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX8_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX8_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX8_CHK_RES 0x0188 +#define RO_SENINF_CAM_MUX8_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX8_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX8_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX8_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX8_CHK_ERR_RES 0x018c +#define RO_SENINF_CAM_MUX8_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX8_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX8_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX8_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX9_CHK_CTL_0 0x0190 +#define RG_SENINF_CAM_MUX9_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX9_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX9_CHK_CTL_1 0x0194 +#define RG_SENINF_CAM_MUX9_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX9_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX9_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX9_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX9_CHK_RES 0x0198 +#define RO_SENINF_CAM_MUX9_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX9_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX9_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX9_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX9_CHK_ERR_RES 0x019c +#define RO_SENINF_CAM_MUX9_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX9_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX9_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX9_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX10_CHK_CTL_0 0x01a0 +#define RG_SENINF_CAM_MUX10_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX10_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX10_CHK_CTL_1 0x01a4 +#define RG_SENINF_CAM_MUX10_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX10_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX10_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX10_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX10_CHK_RES 0x01a8 +#define RO_SENINF_CAM_MUX10_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX10_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX10_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX10_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX10_CHK_ERR_RES 0x01ac +#define RO_SENINF_CAM_MUX10_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX10_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX10_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX10_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX11_CHK_CTL_0 0x01b0 +#define RG_SENINF_CAM_MUX11_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX11_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX11_CHK_CTL_1 0x01b4 +#define RG_SENINF_CAM_MUX11_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX11_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX11_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX11_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX11_CHK_RES 0x01b8 +#define RO_SENINF_CAM_MUX11_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX11_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX11_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX11_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX11_CHK_ERR_RES 0x01bc +#define RO_SENINF_CAM_MUX11_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX11_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX11_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX11_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX12_CHK_CTL_0 0x01c0 +#define RG_SENINF_CAM_MUX12_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX12_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX12_CHK_CTL_1 0x01c4 +#define RG_SENINF_CAM_MUX12_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX12_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX12_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX12_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX12_CHK_RES 0x01c8 +#define RO_SENINF_CAM_MUX12_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX12_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX12_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX12_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX12_CHK_ERR_RES 0x01cc +#define RO_SENINF_CAM_MUX12_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX12_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX12_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX12_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX13_CHK_CTL_0 0x01d0 +#define RG_SENINF_CAM_MUX13_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX13_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX13_CHK_CTL_1 0x01d4 +#define RG_SENINF_CAM_MUX13_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX13_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX13_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX13_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX13_CHK_RES 0x01d8 +#define RO_SENINF_CAM_MUX13_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX13_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX13_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX13_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX13_CHK_ERR_RES 0x01dc +#define RO_SENINF_CAM_MUX13_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX13_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX13_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX13_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX14_CHK_CTL_0 0x01e0 +#define RG_SENINF_CAM_MUX14_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX14_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX14_CHK_CTL_1 0x01e4 +#define RG_SENINF_CAM_MUX14_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX14_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX14_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX14_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX14_CHK_RES 0x01e8 +#define RO_SENINF_CAM_MUX14_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX14_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX14_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX14_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX14_CHK_ERR_RES 0x01ec +#define RO_SENINF_CAM_MUX14_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX14_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX14_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX14_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX15_CHK_CTL_0 0x01f0 +#define RG_SENINF_CAM_MUX15_PIX_MODE_SEL_SHIFT 0 +#define RG_SENINF_CAM_MUX15_PIX_MODE_SEL_MASK (0x3 << 0) + +#define SENINF_CAM_MUX15_CHK_CTL_1 0x01f4 +#define RG_SENINF_CAM_MUX15_EXP_HSIZE_SHIFT 0 +#define RG_SENINF_CAM_MUX15_EXP_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_CAM_MUX15_EXP_VSIZE_SHIFT 16 +#define RG_SENINF_CAM_MUX15_EXP_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX15_CHK_RES 0x01f8 +#define RO_SENINF_CAM_MUX15_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX15_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX15_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX15_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_CAM_MUX15_CHK_ERR_RES 0x01fc +#define RO_SENINF_CAM_MUX15_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_CAM_MUX15_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_CAM_MUX15_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_CAM_MUX15_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h new file mode 100644 index 000000000000..84447bc76b40 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-cphy.h @@ -0,0 +1,69 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __CSI0_CPHY_TOP_H__ +#define __CSI0_CPHY_TOP_H__ + +#define CPHY_RX_CTRL 0x0000 +#define CPHY_RX_TR0_LPRX_EN_SHIFT 0 +#define CPHY_RX_TR0_LPRX_EN_MASK (0x1 << 0) +#define CPHY_RX_TR1_LPRX_EN_SHIFT 1 +#define CPHY_RX_TR1_LPRX_EN_MASK (0x1 << 1) +#define CPHY_RX_TR2_LPRX_EN_SHIFT 2 +#define CPHY_RX_TR2_LPRX_EN_MASK (0x1 << 2) +#define CPHY_RX_TR3_LPRX_EN_SHIFT 3 +#define CPHY_RX_TR3_LPRX_EN_MASK (0x1 << 3) +#define CPHY_RX_TR0_HSRX_EN_SHIFT 4 +#define CPHY_RX_TR0_HSRX_EN_MASK (0x1 << 4) +#define CPHY_RX_TR1_HSRX_EN_SHIFT 5 +#define CPHY_RX_TR1_HSRX_EN_MASK (0x1 << 5) +#define CPHY_RX_TR2_HSRX_EN_SHIFT 6 +#define CPHY_RX_TR2_HSRX_EN_MASK (0x1 << 6) +#define CPHY_RX_TR3_HSRX_EN_SHIFT 7 +#define CPHY_RX_TR3_HSRX_EN_MASK (0x1 << 7) +#define CPHY_RX_TR0_BIST_EN_SHIFT 16 +#define CPHY_RX_TR0_BIST_EN_MASK (0x1 << 16) +#define CPHY_RX_TR1_BIST_EN_SHIFT 17 +#define CPHY_RX_TR1_BIST_EN_MASK (0x1 << 17) +#define CPHY_RX_TR2_BIST_EN_SHIFT 18 +#define CPHY_RX_TR2_BIST_EN_MASK (0x1 << 18) +#define CPHY_RX_TR3_BIST_EN_SHIFT 19 +#define CPHY_RX_TR3_BIST_EN_MASK (0x1 << 19) + +#define CPHY_RX_DETECT_CTRL_SYNC 0x0010 +#define RG_CPHY_RX_DETECT_7S_DIS_SYNC_SHIFT 0 +#define RG_CPHY_RX_DETECT_7S_DIS_SYNC_MASK (0x1 << 0) +#define RG_CPHY_RX_DETECT_7S_MASK_SYNC_SHIFT 1 +#define RG_CPHY_RX_DETECT_7S_MASK_SYNC_MASK (0x7f << 1) +#define RG_CPHY_RX_DETECT_7S_WORD_SYNC_SHIFT 8 +#define RG_CPHY_RX_DETECT_7S_WORD_SYNC_MASK (0x1fffff << 8) + +#define CPHY_RX_DETECT_CTRL_ESCAPE 0x0014 +#define RG_CPHY_RX_DETECT_7S_DIS_ESCAPE_SHIFT 0 +#define RG_CPHY_RX_DETECT_7S_DIS_ESCAPE_MASK (0x1 << 0) +#define RG_CPHY_RX_DETECT_7S_MASK_ESCAPE_SHIFT 1 +#define RG_CPHY_RX_DETECT_7S_MASK_ESCAPE_MASK (0x7f << 1) +#define RG_CPHY_RX_DETECT_7S_WORD_ESCAPE_SHIFT 8 +#define RG_CPHY_RX_DETECT_7S_WORD_ESCAPE_MASK (0x1fffff << 8) + +#define CPHY_RX_DETECT_CTRL_POST 0x0018 +#define RG_CPHY_RX_DETECT_7S_DIS_POST_SHIFT 0 +#define RG_CPHY_RX_DETECT_7S_DIS_POST_MASK (0x1 << 0) +#define RG_CPHY_RX_DATA_VALID_POST_EN_SHIFT 4 +#define RG_CPHY_RX_DATA_VALID_POST_EN_MASK (0x1 << 4) +#define RG_CPHY_RX_DETECT_7S_WORD_POST_SHIFT 8 +#define RG_CPHY_RX_DETECT_7S_WORD_POST_MASK (0x1fffff << 8) + +#define CPHY_RX_FSM_STATUS 0x00e4 +#define RO_CPHY_RX_TR0_FSM_SHIFT 0 +#define RO_CPHY_RX_TR0_FSM_MASK (0xff << 0) +#define RO_CPHY_RX_TR1_FSM_SHIFT 8 +#define RO_CPHY_RX_TR1_FSM_MASK (0xff << 8) +#define RO_CPHY_RX_TR2_FSM_SHIFT 16 +#define RO_CPHY_RX_TR2_FSM_MASK (0xff << 16) +#define RO_CPHY_RX_TR3_FSM_SHIFT 24 +#define RO_CPHY_RX_TR3_FSM_MASK (0xff << 24) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h new file mode 100644 index 000000000000..7fc7dced8e7f --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-csi0-dphy.h @@ -0,0 +1,139 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __CSI0_DPHY_TOP_H__ +#define __CSI0_DPHY_TOP_H__ + +#define DPHY_RX_LANE_EN 0x0000 +#define DPHY_RX_LC0_EN_SHIFT 0 +#define DPHY_RX_LC0_EN_MASK (0x1 << 0) +#define DPHY_RX_LC1_EN_SHIFT 1 +#define DPHY_RX_LC1_EN_MASK (0x1 << 1) +#define DPHY_RX_LD0_EN_SHIFT 8 +#define DPHY_RX_LD0_EN_MASK (0x1 << 8) +#define DPHY_RX_LD1_EN_SHIFT 9 +#define DPHY_RX_LD1_EN_MASK (0x1 << 9) +#define DPHY_RX_LD2_EN_SHIFT 10 +#define DPHY_RX_LD2_EN_MASK (0x1 << 10) +#define DPHY_RX_LD3_EN_SHIFT 11 +#define DPHY_RX_LD3_EN_MASK (0x1 << 11) +#define DPHY_RX_SW_RST_SHIFT 31 +#define DPHY_RX_SW_RST_MASK (0x1 << 31) + +#define DPHY_RX_LANE_SELECT 0x0004 +#define RG_DPHY_RX_LC0_SEL_SHIFT 0 +#define RG_DPHY_RX_LC0_SEL_MASK (0x7 << 0) +#define RG_DPHY_RX_LC1_SEL_SHIFT 4 +#define RG_DPHY_RX_LC1_SEL_MASK (0x7 << 4) +#define RG_DPHY_RX_LD0_SEL_SHIFT 8 +#define RG_DPHY_RX_LD0_SEL_MASK (0x7 << 8) +#define RG_DPHY_RX_LD1_SEL_SHIFT 12 +#define RG_DPHY_RX_LD1_SEL_MASK (0x7 << 12) +#define RG_DPHY_RX_LD2_SEL_SHIFT 16 +#define RG_DPHY_RX_LD2_SEL_MASK (0x7 << 16) +#define RG_DPHY_RX_LD3_SEL_SHIFT 20 +#define RG_DPHY_RX_LD3_SEL_MASK (0x7 << 20) +#define DPHY_RX_CK_DATA_MUX_EN_SHIFT 31 +#define DPHY_RX_CK_DATA_MUX_EN_MASK (0x1 << 31) + +#define DPHY_RX_HS_RX_EN_SW 0x0008 +#define RG_DPHY_RX_LC0_HSRX_EN_SW_SHIFT 0 +#define RG_DPHY_RX_LC0_HSRX_EN_SW_MASK (0x1 << 0) +#define RG_DPHY_RX_LC1_HSRX_EN_SW_SHIFT 1 +#define RG_DPHY_RX_LC1_HSRX_EN_SW_MASK (0x1 << 1) +#define RG_CDPHY_RX_LD0_TRIO0_HSRX_EN_SW_SHIFT 8 +#define RG_CDPHY_RX_LD0_TRIO0_HSRX_EN_SW_MASK (0x1 << 8) +#define RG_CDPHY_RX_LD1_TRIO1_HSRX_EN_SW_SHIFT 9 +#define RG_CDPHY_RX_LD1_TRIO1_HSRX_EN_SW_MASK (0x1 << 9) +#define RG_CDPHY_RX_LD2_TRIO2_HSRX_EN_SW_SHIFT 10 +#define RG_CDPHY_RX_LD2_TRIO2_HSRX_EN_SW_MASK (0x1 << 10) +#define RG_CDPHY_RX_LD2_TRIO3_HSRX_EN_SW_SHIFT 11 +#define RG_CDPHY_RX_LD2_TRIO3_HSRX_EN_SW_MASK (0x1 << 11) + +#define DPHY_RX_CLOCK_LANE0_HS_PARAMETER 0x0010 +#define RG_DPHY_RX_LC0_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_DPHY_RX_LC0_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_DPHY_RX_LC0_HS_PREPARE_EN_SHIFT 28 +#define RG_DPHY_RX_LC0_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LC0_HS_OPTION_SHIFT 30 +#define RG_DPHY_RX_LC0_HS_OPTION_MASK (0x1 << 30) + +#define DPHY_RX_CLOCK_LANE1_HS_PARAMETER 0x0014 +#define RG_DPHY_RX_LC1_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_DPHY_RX_LC1_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_DPHY_RX_LC1_HS_PREPARE_EN_SHIFT 28 +#define RG_DPHY_RX_LC1_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LC1_HS_OPTION_SHIFT 30 +#define RG_DPHY_RX_LC1_HS_OPTION_MASK (0x1 << 30) + +#define DPHY_RX_DATA_LANE0_HS_PARAMETER 0x0020 +#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER_SHIFT 8 +#define RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER_MASK (0xff << 8) +#define RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_EN_SHIFT 28 +#define RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LD0_HS_TRAIL_EN_SHIFT 29 +#define RG_DPHY_RX_LD0_HS_TRAIL_EN_MASK (0x1 << 29) + +#define DPHY_RX_DATA_LANE1_HS_PARAMETER 0x0024 +#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER_SHIFT 8 +#define RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER_MASK (0xff << 8) +#define RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_EN_SHIFT 28 +#define RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LD1_HS_TRAIL_EN_SHIFT 29 +#define RG_DPHY_RX_LD1_HS_TRAIL_EN_MASK (0x1 << 29) + +#define DPHY_RX_DATA_LANE2_HS_PARAMETER 0x0028 +#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER_SHIFT 8 +#define RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER_MASK (0xff << 8) +#define RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_EN_SHIFT 28 +#define RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LD2_HS_TRAIL_EN_SHIFT 29 +#define RG_DPHY_RX_LD2_HS_TRAIL_EN_MASK (0x1 << 29) + +#define DPHY_RX_DATA_LANE3_HS_PARAMETER 0x002c +#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_PARAMETER_SHIFT 0 +#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_PARAMETER_MASK (0xff << 0) +#define RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER_SHIFT 8 +#define RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER_MASK (0xff << 8) +#define RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER_SHIFT 16 +#define RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER_MASK (0xff << 16) +#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_EN_SHIFT 28 +#define RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_EN_MASK (0x1 << 28) +#define RG_DPHY_RX_LD3_HS_TRAIL_EN_SHIFT 29 +#define RG_DPHY_RX_LD3_HS_TRAIL_EN_MASK (0x1 << 29) + +#define DPHY_RX_CLOCK_LANE_FSM 0x0030 +#define RO_DPHY_RX_CL0_FSM_SHIFT 0 +#define RO_DPHY_RX_CL0_FSM_MASK (0x3f << 0) +#define RO_DPHY_RX_CL1_FSM_SHIFT 8 +#define RO_DPHY_RX_CL1_FSM_MASK (0x3f << 8) + +#define DPHY_RX_DATA_LANE_FSM 0x0034 +#define RO_DPHY_RX_DL0_FSM_SHIFT 0 +#define RO_DPHY_RX_DL0_FSM_MASK (0xff << 0) +#define RO_DPHY_RX_DL1_FSM_SHIFT 8 +#define RO_DPHY_RX_DL1_FSM_MASK (0xff << 8) +#define RO_DPHY_RX_DL2_FSM_SHIFT 16 +#define RO_DPHY_RX_DL2_FSM_MASK (0xff << 16) +#define RO_DPHY_RX_DL3_FSM_SHIFT 24 +#define RO_DPHY_RX_DL3_FSM_MASK (0xff << 24) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c new file mode 100644 index 000000000000..f24d8a056d0e --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-hw_phy_2_0.c @@ -0,0 +1,2879 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2022 MediaTek Inc. + +#include +#include + +#include "../mtk_cam-seninf.h" +#include "../mtk_cam-seninf-hw.h" +#include "../mtk_cam-seninf-regs.h" +#include "mtk_cam-seninf-top-ctrl.h" +#include "mtk_cam-seninf-seninf1-mux.h" +#include "mtk_cam-seninf-seninf1.h" +#include "mtk_cam-seninf-seninf1-csi2.h" +#include "mtk_cam-seninf-tg1.h" +#include "mtk_cam-seninf-cammux.h" +#include "mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h" +#include "mtk_cam-seninf-csi0-cphy.h" +#include "mtk_cam-seninf-csi0-dphy.h" +#include "../kd_imgsensor_define_v4l2.h" + +/* seninf cfg default, dts may override */ +static struct mtk_cam_seninf_cfg _seninf_cfg = { + .mux_num = 8, + .seninf_num = 4, + .cam_mux_num = 11, + .pref_mux_num = 11, +}; + +struct mtk_cam_seninf_cfg *g_seninf_cfg = &_seninf_cfg; + +static inline void mtk_cam_seninf_set_di_ch_ctrl(void __iomem *pseninf, + unsigned int stream_id, + struct seninf_vc *vc) +{ + if (stream_id > 7) + return; + + SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2), + RG_CSI2_DT_SEL, vc->dt); + SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2), + RG_CSI2_VC_SEL, vc->vc); + SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2), + RG_CSI2_DT_INTERLEAVE_MODE, 1); + SENINF_BITS(pseninf, SENINF_CSI2_S0_DI_CTRL + (stream_id << 0x2), + RG_CSI2_VC_INTERLEAVE_EN, 1); + + switch (stream_id) { + case 0: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S0_GRP_EN, 1); + break; + case 1: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S1_GRP_EN, 1); + break; + case 2: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S2_GRP_EN, 1); + break; + case 3: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S3_GRP_EN, 1); + break; + case 4: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S4_GRP_EN, 1); + break; + case 5: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S5_GRP_EN, 1); + break; + case 6: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S6_GRP_EN, 1); + break; + case 7: + SENINF_BITS(pseninf, SENINF_CSI2_CH0_CTRL + (vc->group << 0x2), + RG_CSI2_S7_GRP_EN, 1); + break; + default: + return; + } +} + +int mtk_cam_seninf_init_iomem(struct seninf_ctx *ctx, void __iomem *if_base, + void __iomem *ana_base) +{ + u32 i; + + ctx->reg_ana_csi_rx[CSI_PORT_0] = + ctx->reg_ana_csi_rx[CSI_PORT_0A] = ana_base + 0; + ctx->reg_ana_csi_rx[CSI_PORT_0B] = ana_base + 0x1000; + + ctx->reg_ana_csi_rx[CSI_PORT_1] = + ctx->reg_ana_csi_rx[CSI_PORT_1A] = ana_base + 0x4000; + ctx->reg_ana_csi_rx[CSI_PORT_1B] = ana_base + 0x5000; + + ctx->reg_ana_csi_rx[CSI_PORT_2] = + ctx->reg_ana_csi_rx[CSI_PORT_2A] = ana_base + 0x8000; + ctx->reg_ana_csi_rx[CSI_PORT_2B] = ana_base + 0x9000; + + ctx->reg_ana_csi_rx[CSI_PORT_3] = + ctx->reg_ana_csi_rx[CSI_PORT_3A] = ana_base + 0xc000; + ctx->reg_ana_csi_rx[CSI_PORT_3B] = ana_base + 0xd000; + + ctx->reg_ana_dphy_top[CSI_PORT_0A] = + ctx->reg_ana_dphy_top[CSI_PORT_0B] = + ctx->reg_ana_dphy_top[CSI_PORT_0] = ana_base + 0x2000; + + ctx->reg_ana_dphy_top[CSI_PORT_1A] = + ctx->reg_ana_dphy_top[CSI_PORT_1B] = + ctx->reg_ana_dphy_top[CSI_PORT_1] = ana_base + 0x6000; + + ctx->reg_ana_dphy_top[CSI_PORT_2A] = + ctx->reg_ana_dphy_top[CSI_PORT_2B] = + ctx->reg_ana_dphy_top[CSI_PORT_2] = ana_base + 0xa000; + + ctx->reg_ana_dphy_top[CSI_PORT_3A] = + ctx->reg_ana_dphy_top[CSI_PORT_3B] = + ctx->reg_ana_dphy_top[CSI_PORT_3] = ana_base + 0xe000; + + ctx->reg_ana_cphy_top[CSI_PORT_0A] = + ctx->reg_ana_cphy_top[CSI_PORT_0B] = + ctx->reg_ana_cphy_top[CSI_PORT_0] = ana_base + 0x3000; + + ctx->reg_ana_cphy_top[CSI_PORT_1A] = + ctx->reg_ana_cphy_top[CSI_PORT_1B] = + ctx->reg_ana_cphy_top[CSI_PORT_1] = ana_base + 0x7000; + + ctx->reg_ana_cphy_top[CSI_PORT_2A] = + ctx->reg_ana_cphy_top[CSI_PORT_2B] = + ctx->reg_ana_cphy_top[CSI_PORT_2] = ana_base + 0xb000; + + ctx->reg_ana_cphy_top[CSI_PORT_3A] = + ctx->reg_ana_cphy_top[CSI_PORT_3B] = + ctx->reg_ana_cphy_top[CSI_PORT_3] = ana_base + 0xf000; + + ctx->reg_if_top = if_base; + + for (i = SENINF_1; i < _seninf_cfg.seninf_num; i++) { + ctx->reg_if_ctrl[i] = if_base + 0x0200 + (0x1000 * i); + ctx->reg_if_tg[i] = if_base + 0x0F00 + (0x1000 * i); + ctx->reg_if_csi2[i] = if_base + 0x0a00 + (0x1000 * i); + } + + for (i = SENINF_MUX1; i < _seninf_cfg.mux_num; i++) + ctx->reg_if_mux[i] = if_base + 0x0d00 + (0x1000 * i); + + ctx->reg_if_cam_mux = if_base + 0x0400; + + return 0; +} + +int mtk_cam_seninf_init_port(struct seninf_ctx *ctx, int port) +{ + u32 port_num; + + if (port >= CSI_PORT_0A) + port_num = (port - CSI_PORT_0) >> 1; + else + port_num = port; + + ctx->port = port; + ctx->port_num = port_num; + ctx->port_a = CSI_PORT_0A + (port_num << 1); + ctx->port_b = ctx->port_a + 1; + ctx->is_4d1c = (port == port_num); + + switch (port) { + case CSI_PORT_0: + ctx->seninf_idx = SENINF_1; + break; + case CSI_PORT_0A: + ctx->seninf_idx = SENINF_1; + break; + case CSI_PORT_0B: + ctx->seninf_idx = SENINF_2; + break; + case CSI_PORT_1: + ctx->seninf_idx = SENINF_3; + break; + case CSI_PORT_1A: + ctx->seninf_idx = SENINF_3; + break; + case CSI_PORT_1B: + ctx->seninf_idx = SENINF_4; + break; + case CSI_PORT_2: + ctx->seninf_idx = SENINF_5; + break; + case CSI_PORT_2A: + ctx->seninf_idx = SENINF_5; + break; + case CSI_PORT_2B: + ctx->seninf_idx = SENINF_6; + break; + case CSI_PORT_3: + ctx->seninf_idx = SENINF_7; + break; + case CSI_PORT_3A: + ctx->seninf_idx = SENINF_7; + break; + case CSI_PORT_3B: + ctx->seninf_idx = SENINF_8; + break; + default: + dev_dbg(ctx->dev, "invalid port %d\n", port); + return -EINVAL; + } + + return 0; +} + +int mtk_cam_seninf_is_cammux_used(struct seninf_ctx *ctx, int cam_mux) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + u32 temp = SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_EN); + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + return !!(temp & (1 << cam_mux)); +} + +int mtk_cam_seninf_cammux(struct seninf_ctx *ctx, int cam_mux) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + u32 temp; + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + temp = SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_EN); + SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_EN, + temp | (1 << cam_mux)); + + SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_IRQ_STATUS, + 3 << (cam_mux * 2)); /* clr irq */ + + dev_dbg(ctx->dev, "cam_mux %d EN 0x%x IRQ_EN 0x%x IRQ_STATUS 0x%x\n", + cam_mux, SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_EN), + SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN), + SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_IRQ_STATUS)); + + return 0; +} + +int mtk_cam_seninf_disable_cammux(struct seninf_ctx *ctx, int cam_mux) +{ + void __iomem *base = ctx->reg_if_cam_mux; + u32 temp; + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + temp = SENINF_READ_REG(base, SENINF_CAM_MUX_EN); + + if ((1 << cam_mux) & temp) { + SENINF_WRITE_REG(base, SENINF_CAM_MUX_EN, + temp & (~(1 << cam_mux))); + + dev_dbg(ctx->dev, "cammux %d EN %x IRQ_EN %x IRQ_STATUS %x", + cam_mux, SENINF_READ_REG(base, SENINF_CAM_MUX_EN), + SENINF_READ_REG(base, SENINF_CAM_MUX_IRQ_EN), + SENINF_READ_REG(base, SENINF_CAM_MUX_IRQ_STATUS)); + } + + return 0; +} + +int mtk_cam_seninf_disable_all_cammux(struct seninf_ctx *ctx) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + + SENINF_WRITE_REG(seninf_cam_mux, SENINF_CAM_MUX_EN, 0); + + dev_dbg(ctx->dev, "%s all cam_mux EN 0x%x\n", __func__, + SENINF_READ_REG(seninf_cam_mux, SENINF_CAM_MUX_EN)); + + return 0; +} + +int mtk_cam_seninf_set_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx, + int seninf_src) +{ + void __iomem *seninf = ctx->reg_if_top; + + switch (mux_idx) { + case SENINF_MUX1: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX1_SRC_SEL, seninf_src); + break; + case SENINF_MUX2: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX2_SRC_SEL, seninf_src); + break; + case SENINF_MUX3: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX3_SRC_SEL, seninf_src); + break; + case SENINF_MUX4: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX4_SRC_SEL, seninf_src); + break; + case SENINF_MUX5: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX5_SRC_SEL, seninf_src); + break; + case SENINF_MUX6: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX6_SRC_SEL, seninf_src); + break; + case SENINF_MUX7: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX7_SRC_SEL, seninf_src); + break; + case SENINF_MUX8: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX8_SRC_SEL, seninf_src); + break; + case SENINF_MUX9: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX9_SRC_SEL, seninf_src); + break; + case SENINF_MUX10: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX10_SRC_SEL, seninf_src); + break; + case SENINF_MUX11: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX11_SRC_SEL, seninf_src); + break; + case SENINF_MUX12: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX12_SRC_SEL, seninf_src); + break; + case SENINF_MUX13: + SENINF_BITS(seninf, SENINF_TOP_MUX_CTRL_3, + RG_SENINF_MUX13_SRC_SEL, seninf_src); + break; + default: + dev_dbg(ctx->dev, "invalid mux_idx %d\n", mux_idx); + return -EINVAL; + } + + return 0; +} + +int mtk_cam_seninf_get_top_mux_ctrl(struct seninf_ctx *ctx, int mux_idx) +{ + void __iomem *seninf = ctx->reg_if_top; + u32 seninf_src = 0; + + switch (mux_idx) { + case SENINF_MUX1: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX1_SRC_SEL); + break; + case SENINF_MUX2: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX2_SRC_SEL); + break; + case SENINF_MUX3: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX3_SRC_SEL); + break; + case SENINF_MUX4: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_0, + RG_SENINF_MUX4_SRC_SEL); + break; + case SENINF_MUX5: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX5_SRC_SEL); + break; + case SENINF_MUX6: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX6_SRC_SEL); + break; + case SENINF_MUX7: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX7_SRC_SEL); + break; + case SENINF_MUX8: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_1, + RG_SENINF_MUX8_SRC_SEL); + break; + case SENINF_MUX9: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX9_SRC_SEL); + break; + case SENINF_MUX10: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX10_SRC_SEL); + break; + case SENINF_MUX11: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX11_SRC_SEL); + break; + case SENINF_MUX12: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_2, + RG_SENINF_MUX12_SRC_SEL); + break; + case SENINF_MUX13: + seninf_src = SENINF_READ_BITS(seninf, SENINF_TOP_MUX_CTRL_3, + RG_SENINF_MUX13_SRC_SEL); + break; + default: + dev_dbg(ctx->dev, "invalid mux_idx %d", mux_idx); + return -EINVAL; + } + + return seninf_src; +} + +int mtk_cam_seninf_get_cammux_ctrl(struct seninf_ctx *ctx, int cam_mux) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + u32 seninf_mux_src = 0; + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + switch (cam_mux) { + case SENINF_CAM_MUX0: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX0_SRC_SEL); + break; + case SENINF_CAM_MUX1: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX1_SRC_SEL); + break; + case SENINF_CAM_MUX2: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX2_SRC_SEL); + break; + case SENINF_CAM_MUX3: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX3_SRC_SEL); + break; + case SENINF_CAM_MUX4: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX4_SRC_SEL); + break; + case SENINF_CAM_MUX5: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX5_SRC_SEL); + break; + case SENINF_CAM_MUX6: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX6_SRC_SEL); + break; + case SENINF_CAM_MUX7: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX7_SRC_SEL); + break; + case SENINF_CAM_MUX8: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX8_SRC_SEL); + break; + case SENINF_CAM_MUX9: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX9_SRC_SEL); + break; + case SENINF_CAM_MUX10: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX10_SRC_SEL); + break; + case SENINF_CAM_MUX11: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX11_SRC_SEL); + break; + case SENINF_CAM_MUX12: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX12_SRC_SEL); + break; + case SENINF_CAM_MUX13: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX13_SRC_SEL); + break; + case SENINF_CAM_MUX14: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX14_SRC_SEL); + break; + case SENINF_CAM_MUX15: + seninf_mux_src = SENINF_READ_BITS(seninf_cam_mux, + SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX15_SRC_SEL); + break; + default: + dev_dbg(ctx->dev, "invalid cam_mux %d", cam_mux); + return -EINVAL; + } + + return seninf_mux_src; +} + +u32 mtk_cam_seninf_get_cammux_res(struct seninf_ctx *ctx, int cam_mux) +{ + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + return SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_RES + (0x10 * cam_mux)); +} + +static u32 mtk_cam_seninf_get_cammux_exp(struct seninf_ctx *ctx, int cam_mux) +{ + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + return SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_CTL_1 + (0x10 * 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) +{ + void __iomem *seninf_cam_mux_vc_addr = + ctx->reg_if_cam_mux + (cam_mux << 0x2); + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT, + RG_SENINF_CAM_MUX0_VC_SEL, vc_sel); + SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT, + RG_SENINF_CAM_MUX0_DT_SEL, dt_sel); + SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT, + RG_SENINF_CAM_MUX0_VC_EN, vc_en); + SENINF_BITS(seninf_cam_mux_vc_addr, SENINF_CAM_MUX0_OPT, + RG_SENINF_CAM_MUX0_DT_EN, dt_en); + + return 0; +} + +int mtk_cam_seninf_switch_to_cammux_inner_page(struct seninf_ctx *ctx, + bool inner) +{ + void __iomem *seninf_cam_mux_addr = ctx->reg_if_cam_mux; + + SENINF_BITS(seninf_cam_mux_addr, SENINF_CAM_MUX_DYN_CTRL, + CAM_MUX_DYN_PAGE_SEL, inner ? 0 : 1); + + return 0; +} + +int mtk_cam_seninf_set_cammux_next_ctrl(struct seninf_ctx *ctx, int src, + int target) +{ + void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux; + + if (target >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, target, _seninf_cfg.cam_mux_num); + + return 0; + } + + switch (target) { + case SENINF_CAM_MUX0: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0, + CAM_MUX0_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX1: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0, + CAM_MUX1_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX2: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0, + CAM_MUX2_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX3: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_0, + CAM_MUX3_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX4: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1, + CAM_MUX4_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX5: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1, + CAM_MUX5_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX6: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1, + CAM_MUX6_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX7: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_1, + CAM_MUX7_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX8: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2, + CAM_MUX8_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX9: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2, + CAM_MUX9_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX10: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2, + CAM_MUX10_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX11: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_2, + CAM_MUX11_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX12: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3, + CAM_MUX12_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX13: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3, + CAM_MUX13_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX14: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3, + CAM_MUX14_NEXT_SRC_SEL, src); + break; + case SENINF_CAM_MUX15: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_NEXT_CTRL_3, + CAM_MUX15_NEXT_SRC_SEL, src); + break; + default: + dev_dbg(ctx->dev, "invalid src %d target %d", src, target); + return -EINVAL; + } + + return 0; +} + +int mtk_cam_seninf_set_cammux_src(struct seninf_ctx *ctx, int src, + int target, int exp_hsize, int exp_vsize) +{ + void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux; + + if (target >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, target, _seninf_cfg.cam_mux_num); + + return 0; + } + + switch (target) { + case SENINF_CAM_MUX0: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX0_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX0_CHK_CTL_1, + RG_SENINF_CAM_MUX0_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX0_CHK_CTL_1, + RG_SENINF_CAM_MUX0_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX1: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX1_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX1_CHK_CTL_1, + RG_SENINF_CAM_MUX1_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX1_CHK_CTL_1, + RG_SENINF_CAM_MUX1_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX2: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX2_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX2_CHK_CTL_1, + RG_SENINF_CAM_MUX2_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX2_CHK_CTL_1, + RG_SENINF_CAM_MUX2_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX3: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_0, + RG_SENINF_CAM_MUX3_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX3_CHK_CTL_1, + RG_SENINF_CAM_MUX3_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX3_CHK_CTL_1, + RG_SENINF_CAM_MUX3_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX4: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX4_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX4_CHK_CTL_1, + RG_SENINF_CAM_MUX4_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX4_CHK_CTL_1, + RG_SENINF_CAM_MUX4_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX5: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX5_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX5_CHK_CTL_1, + RG_SENINF_CAM_MUX5_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX5_CHK_CTL_1, + RG_SENINF_CAM_MUX5_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX6: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX6_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX6_CHK_CTL_1, + RG_SENINF_CAM_MUX6_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX6_CHK_CTL_1, + RG_SENINF_CAM_MUX6_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX7: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_1, + RG_SENINF_CAM_MUX7_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX7_CHK_CTL_1, + RG_SENINF_CAM_MUX7_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX7_CHK_CTL_1, + RG_SENINF_CAM_MUX7_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX8: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX8_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX8_CHK_CTL_1, + RG_SENINF_CAM_MUX8_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX8_CHK_CTL_1, + RG_SENINF_CAM_MUX8_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX9: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX9_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX9_CHK_CTL_1, + RG_SENINF_CAM_MUX9_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX9_CHK_CTL_1, + RG_SENINF_CAM_MUX9_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX10: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX10_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX10_CHK_CTL_1, + RG_SENINF_CAM_MUX10_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX10_CHK_CTL_1, + RG_SENINF_CAM_MUX10_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX11: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_2, + RG_SENINF_CAM_MUX11_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX11_CHK_CTL_1, + RG_SENINF_CAM_MUX11_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX11_CHK_CTL_1, + RG_SENINF_CAM_MUX11_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX12: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX12_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX12_CHK_CTL_1, + RG_SENINF_CAM_MUX12_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX12_CHK_CTL_1, + RG_SENINF_CAM_MUX12_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX13: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX13_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX13_CHK_CTL_1, + RG_SENINF_CAM_MUX13_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX13_CHK_CTL_1, + RG_SENINF_CAM_MUX13_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX14: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX14_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX14_CHK_CTL_1, + RG_SENINF_CAM_MUX14_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX14_CHK_CTL_1, + RG_SENINF_CAM_MUX14_EXP_VSIZE, exp_vsize); + break; + case SENINF_CAM_MUX15: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX_CTRL_3, + RG_SENINF_CAM_MUX15_SRC_SEL, src); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX15_CHK_CTL_1, + RG_SENINF_CAM_MUX15_EXP_HSIZE, exp_hsize); + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX15_CHK_CTL_1, + RG_SENINF_CAM_MUX15_EXP_VSIZE, exp_vsize); + break; + default: + dev_dbg(ctx->dev, "invalid src %d target %d", src, target); + return -EINVAL; + } + + return 0; +} + +int mtk_cam_seninf_set_vc(struct seninf_ctx *ctx, u32 seninf_idx, + struct seninf_vcinfo *vcinfo) +{ + void __iomem *seninf_csi2 = ctx->reg_if_csi2[seninf_idx]; + int i; + struct seninf_vc *vc; + + if (!vcinfo || !vcinfo->cnt) + return 0; + + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S0_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S1_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S2_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S3_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S4_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S5_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S6_DI_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_S7_DI_CTRL, 0); + + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH0_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH1_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH2_CTRL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_CH3_CTRL, 0); + + for (i = 0; i < vcinfo->cnt; i++) { + vc = &vcinfo->vc[i]; + + /* General Long Packet Data Types: 0x10-0x17 */ + if (vc->dt >= 0x10 && vc->dt <= 0x17) { + SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT, + RG_CSI2_GENERIC_LONG_PACKET_EN, 1); + } + + mtk_cam_seninf_set_di_ch_ctrl(seninf_csi2, i, vc); + } + + dev_dbg(ctx->dev, "DI_CTRL 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S0_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S1_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S2_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S3_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S4_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S5_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S6_DI_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_S7_DI_CTRL)); + + dev_dbg(ctx->dev, "CH_CTRL 0x%x 0x%x 0x%x 0x%x\n", + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_CH0_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_CH1_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_CH2_CTRL), + SENINF_READ_REG(seninf_csi2, SENINF_CSI2_CH3_CTRL)); + + return 0; +} + +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) +{ + u32 temp = 0; + void __iomem *seninf_mux; + + seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1, + RG_SENINF_MUX_SRC_SEL, src_sel); + + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1, + RG_SENINF_MUX_PIX_MODE_SEL, pixel_mode); + + SENINF_BITS(seninf_mux, SENINF_MUX_OPT, + RG_SENINF_MUX_HSYNC_POL, hs_pol); + + SENINF_BITS(seninf_mux, SENINF_MUX_OPT, + RG_SENINF_MUX_VSYNC_POL, vs_pol); + + temp = SENINF_READ_REG(seninf_mux, SENINF_MUX_CTRL_0); + SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp | + SENINF_MUX_IRQ_SW_RST_MASK | SENINF_MUX_SW_RST_MASK); + SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp & 0xFFFFFFF9); + + return 0; +} + +int mtk_cam_seninf_update_mux_pixel_mode(struct seninf_ctx *ctx, u32 mux, + int pixel_mode) +{ + u32 temp = 0; + void __iomem *seninf_mux; + + seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1, + RG_SENINF_MUX_PIX_MODE_SEL, pixel_mode); + + temp = SENINF_READ_REG(seninf_mux, SENINF_MUX_CTRL_0); + SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp | + SENINF_MUX_IRQ_SW_RST_MASK | SENINF_MUX_SW_RST_MASK); + SENINF_WRITE_REG(seninf_mux, SENINF_MUX_CTRL_0, temp & 0xFFFFFFF9); + + dev_dbg(ctx->dev, + "%s mux %d SENINF_MUX_CTRL_1(0x%x), SENINF_MUX_OPT(0x%x)", + __func__, mux, SENINF_READ_REG(seninf_mux, SENINF_MUX_CTRL_1), + SENINF_READ_REG(seninf_mux, SENINF_MUX_OPT)); + + return 0; +} + +int mtk_cam_seninf_set_mux_crop(struct seninf_ctx *ctx, u32 mux, int start_x, + int end_x, int enable) +{ + void __iomem *seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_CROP_PIX_CTRL, + RG_SENINF_MUX_CROP_START_8PIX_CNT, start_x / 8); + SENINF_BITS(seninf_mux, SENINF_MUX_CROP_PIX_CTRL, + RG_SENINF_MUX_CROP_END_8PIX_CNT, + start_x / 8 + (end_x - start_x + 1) / 8 - 1 + + (((end_x - start_x + 1) % 8) > 0 ? 1 : 0)); + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_1, + RG_SENINF_MUX_CROP_EN, enable); + + dev_dbg(ctx->dev, "MUX_CROP_PIX_CTRL 0x%x MUX_CTRL_1 0x%x\n", + SENINF_READ_REG(seninf_mux, SENINF_MUX_CROP_PIX_CTRL), + SENINF_READ_REG(seninf_mux, SENINF_MUX_CTRL_1)); + + dev_dbg(ctx->dev, "mux %d, start %d, end %d, enable %d\n", + mux, start_x, end_x, enable); + + return 0; +} + +int mtk_cam_seninf_is_mux_used(struct seninf_ctx *ctx, u32 mux) +{ + void __iomem *seninf_mux = ctx->reg_if_mux[mux]; + + return SENINF_READ_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN); +} + +int mtk_cam_seninf_mux(struct seninf_ctx *ctx, u32 mux) +{ + void __iomem *seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 1); + return 0; +} + +int mtk_cam_seninf_disable_mux(struct seninf_ctx *ctx, u32 mux) +{ + int i; + void __iomem *seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 0); + + /* also disable CAM_MUX with input from mux */ + for (i = SENINF_CAM_MUX0; i < _seninf_cfg.cam_mux_num; i++) { + if (mux == mtk_cam_seninf_get_cammux_ctrl(ctx, i)) + mtk_cam_seninf_disable_cammux(ctx, i); + } + + return 0; +} + +int mtk_cam_seninf_disable_all_mux(struct seninf_ctx *ctx) +{ + int i; + void __iomem *seninf_mux; + + for (i = 0; i < _seninf_cfg.mux_num; i++) { + seninf_mux = ctx->reg_if_mux[i]; + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, SENINF_MUX_EN, 0); + } + + return 0; +} + +int mtk_cam_seninf_set_cammux_chk_pixel_mode(struct seninf_ctx *ctx, + int cam_mux, int pixel_mode) +{ + void __iomem *seninf_cam_mux_base = ctx->reg_if_cam_mux; + + if (cam_mux >= _seninf_cfg.cam_mux_num) { + dev_dbg(ctx->dev, + "%s err cam_mux %d >= SENINF_CAM_MUX_NUM %d\n", + __func__, cam_mux, _seninf_cfg.cam_mux_num); + + return 0; + } + + switch (cam_mux) { + case SENINF_CAM_MUX0: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX0_CHK_CTL_0, + RG_SENINF_CAM_MUX0_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX1: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX1_CHK_CTL_0, + RG_SENINF_CAM_MUX1_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX2: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX2_CHK_CTL_0, + RG_SENINF_CAM_MUX2_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX3: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX3_CHK_CTL_0, + RG_SENINF_CAM_MUX3_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX4: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX4_CHK_CTL_0, + RG_SENINF_CAM_MUX4_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX5: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX5_CHK_CTL_0, + RG_SENINF_CAM_MUX5_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX6: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX6_CHK_CTL_0, + RG_SENINF_CAM_MUX6_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX7: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX7_CHK_CTL_0, + RG_SENINF_CAM_MUX7_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX8: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX8_CHK_CTL_0, + RG_SENINF_CAM_MUX8_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX9: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX9_CHK_CTL_0, + RG_SENINF_CAM_MUX9_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX10: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX10_CHK_CTL_0, + RG_SENINF_CAM_MUX10_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX11: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX11_CHK_CTL_0, + RG_SENINF_CAM_MUX11_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX12: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX12_CHK_CTL_0, + RG_SENINF_CAM_MUX12_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX13: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX13_CHK_CTL_0, + RG_SENINF_CAM_MUX13_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX14: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX14_CHK_CTL_0, + RG_SENINF_CAM_MUX14_PIX_MODE_SEL, pixel_mode); + break; + case SENINF_CAM_MUX15: + SENINF_BITS(seninf_cam_mux_base, SENINF_CAM_MUX15_CHK_CTL_0, + RG_SENINF_CAM_MUX15_PIX_MODE_SEL, pixel_mode); + break; + default: + dev_dbg(ctx->dev, "invalid cam_mux %d pixel_mode %d\n", + cam_mux, pixel_mode); + return -EINVAL; + } + + return 0; +} + +int mtk_cam_seninf_set_test_model(struct seninf_ctx *ctx, int mux, int cam_mux, + int pixel_mode) +{ + int intf; + void __iomem *seninf; + void __iomem *seninf_tg; + + intf = mux % 5; /* testmdl by platform seninf */ + + seninf = ctx->reg_if_ctrl[intf]; + seninf_tg = ctx->reg_if_tg[intf]; + + mtk_cam_seninf_reset(ctx, intf); + mtk_cam_seninf_mux(ctx, mux); + mtk_cam_seninf_set_mux_ctrl(ctx, mux, 0, 0, TEST_MODEL, pixel_mode); + mtk_cam_seninf_set_top_mux_ctrl(ctx, mux, intf); + + mtk_cam_seninf_set_cammux_vc(ctx, cam_mux, 0, 0, 0, 0); + mtk_cam_seninf_set_cammux_src(ctx, mux, cam_mux, 0, 0); + mtk_cam_seninf_set_cammux_chk_pixel_mode(ctx, cam_mux, pixel_mode); + mtk_cam_seninf_cammux(ctx, cam_mux); + + SENINF_BITS(seninf, SENINF_TESTMDL_CTRL, RG_SENINF_TESTMDL_EN, 1); + SENINF_BITS(seninf, SENINF_CTRL, SENINF_EN, 1); + + SENINF_BITS(seninf_tg, TM_SIZE, TM_LINE, 4224); + SENINF_BITS(seninf_tg, TM_SIZE, TM_PXL, 5632); + SENINF_BITS(seninf_tg, TM_CLK, TM_CLK_CNT, 7); + + SENINF_BITS(seninf_tg, TM_DUM, TM_VSYNC, 100); + SENINF_BITS(seninf_tg, TM_DUM, TM_DUMMYPXL, 100); + + SENINF_BITS(seninf_tg, TM_CTL, TM_PAT, 0xC); + SENINF_BITS(seninf_tg, TM_CTL, TM_EN, 1); + + return 0; +} + +static int csirx_phyA_power_on(struct seninf_ctx *ctx, u32 port_idx, int en) +{ + void __iomem *base = ctx->reg_ana_csi_rx[port_idx]; + + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L0_T0AB_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L1_T1AB_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_L2_T1BC_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0BC_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T0CA_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_8, RG_CSI0_XX_T1CA_EQ_OS_CAL_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_LPF_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, RG_CSI0_BG_CORE_EN, 0); + usleep_range(200, 300); + + if (en) { + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_BG_CORE_EN, 1); + usleep_range(30, 40); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_BG_LPF_EN, 1); + udelay(1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_L0_T0AB_EQ_OS_CAL_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_L1_T1AB_EQ_OS_CAL_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_L2_T1BC_EQ_OS_CAL_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_XX_T0BC_EQ_OS_CAL_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_XX_T0CA_EQ_OS_CAL_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_8, + RG_CSI0_XX_T1CA_EQ_OS_CAL_EN, 1); + udelay(1); + } + + return 0; +} + +static int apply_efuse_data(struct seninf_ctx *ctx) +{ + int ret = 0; + void __iomem *base; + u32 port; + u32 m_csi_efuse = ctx->m_csi_efuse; + + if (m_csi_efuse == 0) { + dev_dbg(ctx->dev, "No efuse data. Returned.\n"); + return -1; + } + + port = ctx->port; + base = ctx->reg_ana_csi_rx[port]; + + SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0P_T0A_HSRT_CODE, + (m_csi_efuse >> 27) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0N_T0B_HSRT_CODE, + (m_csi_efuse >> 27) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1P_T0C_HSRT_CODE, + (m_csi_efuse >> 22) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1N_T1A_HSRT_CODE, + (m_csi_efuse >> 22) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2P_T1B_HSRT_CODE, + (m_csi_efuse >> 17) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2N_T1C_HSRT_CODE, + (m_csi_efuse >> 17) & 0x1f); + + dev_dbg(ctx->dev, + "CSI%dA CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x) CDPHY_RX_ANA_4(0x%x)", + ctx->port, + SENINF_READ_REG(base, CDPHY_RX_ANA_2), + SENINF_READ_REG(base, CDPHY_RX_ANA_3), + SENINF_READ_REG(base, CDPHY_RX_ANA_4)); + + if (ctx->is_4d1c == 0) + return ret; + + port = ctx->port_b; + base = ctx->reg_ana_csi_rx[port]; + + SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0P_T0A_HSRT_CODE, + (m_csi_efuse >> 12) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_2, RG_CSI0_L0N_T0B_HSRT_CODE, + (m_csi_efuse >> 12) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1P_T0C_HSRT_CODE, + (m_csi_efuse >> 7) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_3, RG_CSI0_L1N_T1A_HSRT_CODE, + (m_csi_efuse >> 7) & 0x1f); + + if (port < CSI_PORT_2A) { + SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2P_T1B_HSRT_CODE, + (m_csi_efuse >> 2) & 0x1f); + SENINF_BITS(base, CDPHY_RX_ANA_4, RG_CSI0_L2N_T1C_HSRT_CODE, + (m_csi_efuse >> 2) & 0x1f); + dev_dbg(ctx->dev, + "CSI%dB CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x) CDPHY_RX_ANA_4(0x%x)", + ctx->port, + SENINF_READ_REG(base, CDPHY_RX_ANA_2), + SENINF_READ_REG(base, CDPHY_RX_ANA_3), + SENINF_READ_REG(base, CDPHY_RX_ANA_4)); + } else { + dev_dbg(ctx->dev, + "CSI%dB CDPHY_RX_ANA_2(0x%x) CDPHY_RX_ANA_3(0x%x)", + ctx->port, + SENINF_READ_REG(base, CDPHY_RX_ANA_2), + SENINF_READ_REG(base, CDPHY_RX_ANA_3)); + } + + return ret; +} + +static int csirx_phyA_init(struct seninf_ctx *ctx) +{ + u32 i, port; + void __iomem *base; + + port = ctx->port; + for (i = 0; i <= ctx->is_4d1c; i++) { + port = i ? ctx->port_b : ctx->port; + base = ctx->reg_ana_csi_rx[port]; + SENINF_BITS(base, CDPHY_RX_ANA_1, + RG_CSI0_BG_LPRX_VTL_SEL, 0x4); + SENINF_BITS(base, CDPHY_RX_ANA_1, + RG_CSI0_BG_LPRX_VTH_SEL, 0x4); + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_BG_ALP_RX_VTL_SEL, 0x4); + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_BG_ALP_RX_VTH_SEL, 0x4); + SENINF_BITS(base, CDPHY_RX_ANA_1, + RG_CSI0_BG_VREF_SEL, 0x8); + SENINF_BITS(base, CDPHY_RX_ANA_1, + RG_CSI0_CDPHY_EQ_DES_VREF_SEL, 0x2); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_9, + RG_CSI0_RESERVE, 0x3003); + SENINF_BITS(base, CDPHY_RX_ANA_SETTING_0, + CSR_CSI_RST_MODE, 0x2); + + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_L0P_T0A_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_L0N_T0B_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_3, + RG_CSI0_L1P_T0C_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_3, + RG_CSI0_L1N_T1A_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_4, + RG_CSI0_L2P_T1B_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_4, + RG_CSI0_L2N_T1C_HSRT_CODE, 0x10); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_T0_CDR_FIRST_EDGE_EN, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_T1_CDR_FIRST_EDGE_EN, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_CPHY_T0_CDR_SELF_CAL_EN, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_2, + RG_CSI0_CPHY_T1_CDR_SELF_CAL_EN, 0x0); + + SENINF_BITS(base, CDPHY_RX_ANA_6, + RG_CSI0_CPHY_T0_CDR_CK_DELAY, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_7, + RG_CSI0_CPHY_T1_CDR_CK_DELAY, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_6, + RG_CSI0_CPHY_T0_CDR_AB_WIDTH, 0x9); + SENINF_BITS(base, CDPHY_RX_ANA_6, + RG_CSI0_CPHY_T0_CDR_BC_WIDTH, 0x9); + SENINF_BITS(base, CDPHY_RX_ANA_6, + RG_CSI0_CPHY_T0_CDR_CA_WIDTH, 0x9); + SENINF_BITS(base, CDPHY_RX_ANA_7, + RG_CSI0_CPHY_T1_CDR_AB_WIDTH, 0x9); + SENINF_BITS(base, CDPHY_RX_ANA_7, + RG_CSI0_CPHY_T1_CDR_BC_WIDTH, 0x9); + SENINF_BITS(base, CDPHY_RX_ANA_7, + RG_CSI0_CPHY_T1_CDR_CA_WIDTH, 0x9); + + dev_dbg(ctx->dev, "port:%d CDPHY_RX_ANA_0(0x%x)\n", + port, SENINF_READ_REG(base, CDPHY_RX_ANA_0)); + } + + apply_efuse_data(ctx); + + return 0; +} + +static int csirx_dphy_init(struct seninf_ctx *ctx) +{ + void __iomem *base = ctx->reg_ana_dphy_top[ctx->port]; + int settle_delay_dt, settle_delay_ck, hs_trail, hs_trail_en; + int bit_per_pixel; + u64 data_rate; + + settle_delay_dt = ctx->is_cphy ? ctx->core->cphy_settle_delay_dt : + ctx->core->dphy_settle_delay_dt; + + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER, + settle_delay_dt); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER, + settle_delay_dt); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER, + settle_delay_dt); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER, + settle_delay_dt); + + settle_delay_ck = ctx->core->settle_delay_ck; + + SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER, + RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER, + settle_delay_ck); + SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER, + RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER, + settle_delay_ck); + + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_CDPHY_RX_LD0_TRIO0_HS_PREPARE_PARAMETER, 2); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_CDPHY_RX_LD1_TRIO1_HS_PREPARE_PARAMETER, 2); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_CDPHY_RX_LD2_TRIO2_HS_PREPARE_PARAMETER, 2); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_CDPHY_RX_LD3_TRIO3_HS_PREPARE_PARAMETER, 2); + + hs_trail = ctx->hs_trail_parameter; + + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, hs_trail); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, hs_trail); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, hs_trail); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, hs_trail); + + if (!ctx->is_cphy) { + bit_per_pixel = 10; + if (ctx->customized_pixel_rate != 0) + data_rate = ctx->customized_pixel_rate * bit_per_pixel; + else + data_rate = ctx->mipi_pixel_rate * bit_per_pixel; + + do_div(data_rate, ctx->num_data_lanes); + hs_trail_en = data_rate < 1400000000; + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_EN, hs_trail_en); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_DPHY_RX_LD1_HS_TRAIL_EN, hs_trail_en); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_DPHY_RX_LD2_HS_TRAIL_EN, hs_trail_en); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_DPHY_RX_LD3_HS_TRAIL_EN, hs_trail_en); + } + + return 0; +} + +static int csirx_cphy_init(struct seninf_ctx *ctx) +{ + void __iomem *base = ctx->reg_ana_cphy_top[ctx->port]; + + SENINF_BITS(base, CPHY_RX_DETECT_CTRL_POST, + RG_CPHY_RX_DATA_VALID_POST_EN, 1); + + return 0; +} + +static int csirx_phy_init(struct seninf_ctx *ctx) +{ + csirx_phyA_init(ctx); + + csirx_dphy_init(ctx); + csirx_cphy_init(ctx); + + return 0; +} + +static int csirx_seninf_csi2_setting(struct seninf_ctx *ctx) +{ + void __iomem *seninf_csi2 = ctx->reg_if_csi2[ctx->seninf_idx]; + int csi_en; + + SENINF_BITS(seninf_csi2, SENINF_CSI2_DBG_CTRL, + RG_CSI2_DBG_PACKET_CNT_EN, 1); + + /* lane/trio count */ + SENINF_BITS(seninf_csi2, SENINF_CSI2_RESYNC_MERGE_CTRL, + RG_CSI2_RESYNC_CYCLE_CNT_OPT, 1); + + csi_en = (1 << ctx->num_data_lanes) - 1; + + if (!ctx->is_cphy) { + SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT, RG_CSI2_CPHY_SEL, 0); + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, csi_en); + SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0, + RG_CSI2_HEADER_MODE, 0); + SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0, + RG_CSI2_HEADER_LEN, 0); + } else { + u8 map_hdr_len[] = {0, 1, 2, 4, 5}; + + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, csi_en); + SENINF_BITS(seninf_csi2, SENINF_CSI2_OPT, + RG_CSI2_CPHY_SEL, 1); + SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0, + RG_CSI2_HEADER_MODE, 2); + SENINF_BITS(seninf_csi2, SENINF_CSI2_HDR_MODE_0, + RG_CSI2_HEADER_LEN, + map_hdr_len[ctx->num_data_lanes]); + } + + return 0; +} + +static int csirx_seninf_setting(struct seninf_ctx *ctx) +{ + void __iomem *seninf = ctx->reg_if_ctrl[ctx->seninf_idx]; + + /* enable/disable seninf csi2 */ + SENINF_BITS(seninf, SENINF_CSI2_CTRL, RG_SENINF_CSI2_EN, 1); + + /* enable/disable seninf, enable after csi2, testmdl is done */ + SENINF_BITS(seninf, SENINF_CTRL, SENINF_EN, 1); + + return 0; +} + +static int csirx_seninf_top_setting(struct seninf_ctx *ctx) +{ + void __iomem *seninf_top = ctx->reg_if_top; + + switch (ctx->port) { + case CSI_PORT_0: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + RG_PHY_SENINF_MUX0_CPHY_MODE, 0); + break; + case CSI_PORT_0A: + case CSI_PORT_0B: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + RG_PHY_SENINF_MUX0_CPHY_MODE, 2); + break; + case CSI_PORT_1: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + RG_PHY_SENINF_MUX1_CPHY_MODE, 0); + break; + case CSI_PORT_1A: + case CSI_PORT_1B: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + RG_PHY_SENINF_MUX1_CPHY_MODE, 2); + break; + case CSI_PORT_2: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + RG_PHY_SENINF_MUX2_CPHY_MODE, 0); + break; + case CSI_PORT_2A: + case CSI_PORT_2B: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + RG_PHY_SENINF_MUX2_CPHY_MODE, 2); + break; + case CSI_PORT_3: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + RG_PHY_SENINF_MUX3_CPHY_MODE, 0); + break; + case CSI_PORT_3A: + case CSI_PORT_3B: + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + RG_PHY_SENINF_MUX3_CPHY_MODE, 2); + break; + default: + break; + } + + /* port operation mode */ + switch (ctx->port) { + case CSI_PORT_0: + case CSI_PORT_0A: + case CSI_PORT_0B: + if (!ctx->is_cphy) { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + PHY_SENINF_MUX0_CPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + PHY_SENINF_MUX0_DPHY_EN, 1); + } else { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + PHY_SENINF_MUX0_DPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI0, + PHY_SENINF_MUX0_CPHY_EN, 1); + } + break; + case CSI_PORT_1: + case CSI_PORT_1A: + case CSI_PORT_1B: + if (!ctx->is_cphy) { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + PHY_SENINF_MUX1_CPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + PHY_SENINF_MUX1_DPHY_EN, 1); + } else { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + PHY_SENINF_MUX1_DPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI1, + PHY_SENINF_MUX1_CPHY_EN, 1); + } + break; + case CSI_PORT_2: + case CSI_PORT_2A: + case CSI_PORT_2B: + if (!ctx->is_cphy) { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + PHY_SENINF_MUX2_CPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + PHY_SENINF_MUX2_DPHY_EN, 1); + } else { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + PHY_SENINF_MUX2_DPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI2, + PHY_SENINF_MUX2_CPHY_EN, 1); + } + break; + case CSI_PORT_3: + case CSI_PORT_3A: + case CSI_PORT_3B: + if (!ctx->is_cphy) { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + PHY_SENINF_MUX3_CPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + PHY_SENINF_MUX3_DPHY_EN, 1); + } else { + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + PHY_SENINF_MUX3_DPHY_EN, 0); + SENINF_BITS(seninf_top, SENINF_TOP_PHY_CTRL_CSI3, + PHY_SENINF_MUX3_CPHY_EN, 1); + } + break; + default: + break; + } + + return 0; +} + +static int csirx_phyA_setting(struct seninf_ctx *ctx) +{ + void __iomem *base, *baseA, *baseB; + + base = ctx->reg_ana_csi_rx[ctx->port]; + baseA = ctx->reg_ana_csi_rx[ctx->port_a]; + baseB = ctx->reg_ana_csi_rx[ctx->port_b]; + + if (!ctx->is_cphy) { /* dphy */ + if (ctx->is_4d1c) { + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 0); + /* clear clk sel first */ + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 0); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 0); + + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKSEL, 1); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKSEL, 1); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKSEL, 1); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKSEL, 1); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKSEL, 1); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKSEL, 1); + + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 0); + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 1); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 0); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 0); + + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x1); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x1); + SENINF_BITS(baseB, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + } else { + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 0); + /* clear clk sel first */ + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 0); + + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKSEL, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKSEL, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKSEL, 0); + + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L0_CKMODE_EN, 0); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L1_CKMODE_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_DPHY_L2_CKMODE_EN, 0); + + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + } + } else { /* cphy */ + if (ctx->is_4d1c) { + SENINF_BITS(baseA, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 1); + SENINF_BITS(baseB, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 1); + + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x0); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x3); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x0); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x3); + SENINF_BITS(baseA, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + } else { + SENINF_BITS(base, CDPHY_RX_ANA_0, + RG_CSI0_CPHY_EN, 1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_BW, 0x3); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_IS, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_LATCH_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG0_EN, 0x1); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_DG1_EN, 0x0); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR0, 0x3); + SENINF_BITS(base, CDPHY_RX_ANA_5, + RG_CSI0_CDPHY_EQ_SR1, 0x0); + } + } + + /* phyA power on */ + if (ctx->is_4d1c) { + csirx_phyA_power_on(ctx, ctx->port_a, 1); + csirx_phyA_power_on(ctx, ctx->port_b, 1); + } else { + csirx_phyA_power_on(ctx, ctx->port, 1); + } + + return 0; +} + +static int csirx_dphy_setting(struct seninf_ctx *ctx) +{ + void __iomem *base = ctx->reg_ana_dphy_top[ctx->port]; + + if (ctx->is_4d1c) { + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD3_SEL, 4); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD2_SEL, 0); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD1_SEL, 3); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD0_SEL, 1); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC0_SEL, 2); + + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD0_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD1_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD2_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD3_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC0_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC1_EN, 0); + } else { + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD3_SEL, 5); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD2_SEL, 3); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD1_SEL, 2); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LD0_SEL, 0); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC1_SEL, 4); + SENINF_BITS(base, DPHY_RX_LANE_SELECT, RG_DPHY_RX_LC0_SEL, 1); + + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD0_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD1_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD2_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LD3_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC0_EN, 1); + SENINF_BITS(base, DPHY_RX_LANE_EN, DPHY_RX_LC1_EN, 1); + } + + SENINF_BITS(base, DPHY_RX_LANE_SELECT, DPHY_RX_CK_DATA_MUX_EN, 1); + + return 0; +} + +static int csirx_cphy_setting(struct seninf_ctx *ctx) +{ + void __iomem *base = ctx->reg_ana_cphy_top[ctx->port]; + + switch (ctx->port) { + case CSI_PORT_0: + case CSI_PORT_1: + case CSI_PORT_2: + case CSI_PORT_3: + case CSI_PORT_0A: + case CSI_PORT_1A: + case CSI_PORT_2A: + case CSI_PORT_3A: + if (ctx->num_data_lanes == 3) { + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1); + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR1_LPRX_EN, 1); + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1); + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR3_LPRX_EN, 0); + } else if (ctx->num_data_lanes == 2) { + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1); + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR1_LPRX_EN, 1); + } else { + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR0_LPRX_EN, 1); + } + break; + case CSI_PORT_0B: + case CSI_PORT_1B: + case CSI_PORT_2B: + case CSI_PORT_3B: + if (ctx->num_data_lanes == 2) { + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1); + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR3_LPRX_EN, 1); + } else { + SENINF_BITS(base, CPHY_RX_CTRL, CPHY_RX_TR2_LPRX_EN, 1); + } + break; + default: + break; + } + + return 0; +} + +static int csirx_phy_setting(struct seninf_ctx *ctx) +{ + csirx_phyA_setting(ctx); + + if (!ctx->is_cphy) + csirx_dphy_setting(ctx); + else + csirx_cphy_setting(ctx); + + return 0; +} + +int mtk_cam_seninf_set_csi_mipi(struct seninf_ctx *ctx) +{ + csirx_phy_init(ctx); + + /* seninf csi2 */ + csirx_seninf_csi2_setting(ctx); + + /* seninf */ + csirx_seninf_setting(ctx); + + /* seninf top */ + csirx_seninf_top_setting(ctx); + + /* phy */ + csirx_phy_setting(ctx); + + return 0; +} + +int mtk_cam_seninf_poweroff(struct seninf_ctx *ctx) +{ + void __iomem *seninf_csi2; + + seninf_csi2 = ctx->reg_if_csi2[ctx->seninf_idx]; + + SENINF_WRITE_REG(seninf_csi2, SENINF_CSI2_EN, 0x0); + + if (ctx->is_4d1c) { + csirx_phyA_power_on(ctx, ctx->port_a, 0); + csirx_phyA_power_on(ctx, ctx->port_b, 0); + } else { + csirx_phyA_power_on(ctx, ctx->port, 0); + } + + return 0; +} + +int mtk_cam_seninf_reset(struct seninf_ctx *ctx, u32 seninf_idx) +{ + int i; + void __iomem *seninf_mux; + void __iomem *seninf = ctx->reg_if_ctrl[seninf_idx]; + + SENINF_BITS(seninf, SENINF_CSI2_CTRL, SENINF_CSI2_SW_RST, 1); + udelay(1); + SENINF_BITS(seninf, SENINF_CSI2_CTRL, SENINF_CSI2_SW_RST, 0); + + dev_dbg(ctx->dev, "reset seninf %d\n", seninf_idx); + + for (i = SENINF_MUX1; i < _seninf_cfg.mux_num; i++) + if (mtk_cam_seninf_get_top_mux_ctrl(ctx, i) == seninf_idx && + mtk_cam_seninf_is_mux_used(ctx, i)) { + seninf_mux = ctx->reg_if_mux[i]; + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, + SENINF_MUX_SW_RST, 1); + udelay(1); + SENINF_BITS(seninf_mux, SENINF_MUX_CTRL_0, + SENINF_MUX_SW_RST, 0); + dev_dbg(ctx->dev, "reset mux %d\n", i); + } + + return 0; +} + +int mtk_cam_seninf_set_idle(struct seninf_ctx *ctx) +{ + int i; + struct seninf_vcinfo *vcinfo = &ctx->vcinfo; + struct seninf_vc *vc; + + for (i = 0; i < vcinfo->cnt; i++) { + vc = &vcinfo->vc[i]; + if (vc->enable) { + mtk_cam_seninf_disable_mux(ctx, vc->mux); + mtk_cam_seninf_disable_cammux(ctx, vc->cam); + ctx->pad2cam[vc->out_pad] = 0xff; + } + } + + return 0; +} + +int mtk_cam_seninf_get_mux_meter(struct seninf_ctx *ctx, u32 mux, + struct mtk_cam_seninf_mux_meter *meter) +{ + void __iomem *seninf_mux; + s64 hv, hb, vv, vb, w, h; + u64 mipi_pixel_rate, vb_in_us, hb_in_us, line_time_in_us; + u32 res; + + seninf_mux = ctx->reg_if_mux[mux]; + + SENINF_BITS(seninf_mux, SENINF_MUX_FRAME_SIZE_MON_CTRL, + RG_SENINF_MUX_FRAME_SIZE_MON_EN, 1); + + hv = SENINF_READ_REG(seninf_mux, SENINF_MUX_FRAME_SIZE_MON_H_VALID); + hb = SENINF_READ_REG(seninf_mux, SENINF_MUX_FRAME_SIZE_MON_H_BLANK); + vv = SENINF_READ_REG(seninf_mux, SENINF_MUX_FRAME_SIZE_MON_V_VALID); + vb = SENINF_READ_REG(seninf_mux, SENINF_MUX_FRAME_SIZE_MON_V_BLANK); + res = SENINF_READ_REG(seninf_mux, SENINF_MUX_SIZE); + + w = res & 0xffff; + h = res >> 16; + + if (ctx->fps_n && ctx->fps_d) { + mipi_pixel_rate = w * ctx->fps_n * (vv + vb); + do_div(mipi_pixel_rate, ctx->fps_d); + do_div(mipi_pixel_rate, hv); + + vb_in_us = vb * ctx->fps_d * 1000000; + do_div(vb_in_us, vv + vb); + do_div(vb_in_us, ctx->fps_n); + + hb_in_us = hb * ctx->fps_d * 1000000; + do_div(hb_in_us, vv + vb); + do_div(hb_in_us, ctx->fps_n); + + line_time_in_us = (hv + hb) * ctx->fps_d * 1000000; + do_div(line_time_in_us, vv + vb); + do_div(line_time_in_us, ctx->fps_n); + + meter->mipi_pixel_rate = mipi_pixel_rate; + meter->vb_in_us = vb_in_us; + meter->hb_in_us = hb_in_us; + meter->line_time_in_us = line_time_in_us; + } else { + meter->mipi_pixel_rate = -1; + meter->vb_in_us = -1; + meter->hb_in_us = -1; + meter->line_time_in_us = -1; + } + + meter->width = w; + meter->height = h; + + meter->h_valid = hv; + meter->h_blank = hb; + meter->v_valid = vv; + meter->v_blank = vb; + + return 0; +} + +ssize_t mtk_cam_seninf_show_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, len; + struct seninf_core *core; + struct seninf_ctx *ctx; + struct seninf_vc *vc; + struct media_link *link; + struct media_pad *pad; + struct mtk_cam_seninf_mux_meter meter; + void __iomem *csi2, *pmux; + void __iomem *rx, *pcammux; + + core = dev_get_drvdata(dev); + len = 0; + + mutex_lock(&core->mutex); + + list_for_each_entry(ctx, &core->list, list) { + len += snprintf(buf + len, PAGE_SIZE - len, + "\n[%s] port %d intf %d test %d cphy %d lanes %d\n", + ctx->subdev.name, ctx->port, ctx->seninf_idx, + ctx->is_test_model, ctx->is_cphy, + ctx->num_data_lanes); + + pad = &ctx->pads[PAD_SINK]; + list_for_each_entry(link, &pad->entity->links, list) { + if (link->sink == pad) { + len += snprintf(buf + len, PAGE_SIZE - len, + "source %s flags 0x%lx\n", + link->source->entity->name, + link->flags); + } + } + + if (!ctx->streaming) + continue; + + csi2 = ctx->reg_if_csi2[ctx->seninf_idx]; + rx = ctx->reg_ana_dphy_top[ctx->port]; + + len += snprintf(buf + len, PAGE_SIZE - len, + "csi2 irq_stat 0x%08x\n", + SENINF_READ_REG(csi2, SENINF_CSI2_IRQ_STATUS)); + len += snprintf(buf + len, PAGE_SIZE - len, + "csi2 line_frame_num 0x%08x\n", + SENINF_READ_REG(csi2, SENINF_CSI2_LINE_FRAME_NUM)); + len += snprintf(buf + len, PAGE_SIZE - len, + "csi2 packet_status 0x%08x\n", + SENINF_READ_REG(csi2, SENINF_CSI2_PACKET_STATUS)); + len += snprintf(buf + len, PAGE_SIZE - len, + "csi2 packet_cnt_status 0x%08x\n", + SENINF_READ_REG(csi2, SENINF_CSI2_PACKET_CNT_STATUS)); + len += snprintf(buf + len, PAGE_SIZE - len, + "rx-ana settle ck 0x%02x dt 0x%02x\n", + SENINF_READ_BITS(rx, DPHY_RX_CLOCK_LANE0_HS_PARAMETER, + RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER), + SENINF_READ_BITS(rx, + DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER)); + len += snprintf(buf + len, PAGE_SIZE - len, + "rx-ana trail en %u param 0x%02x\n", + SENINF_READ_BITS(rx, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_EN), + SENINF_READ_BITS(rx, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER)); + + len += snprintf(buf + len, PAGE_SIZE - len, + "data_not_enough_cnt : <%d>", + ctx->data_not_enough_cnt); + len += snprintf(buf + len, PAGE_SIZE - len, + "err_lane_resync_cnt : <%d>", + ctx->err_lane_resync_cnt); + len += snprintf(buf + len, PAGE_SIZE - len, + "crc_err_cnt : <%d>", ctx->crc_err_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "ecc_err_double_cnt : <%d>", + ctx->ecc_err_double_cnt); + len += snprintf(buf + len, PAGE_SIZE - len, + "ecc_err_corrected_cnt : <%d>\n", + ctx->ecc_err_corrected_cnt); + + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + pmux = ctx->reg_if_mux[vc->mux]; + pcammux = ctx->reg_if_cam_mux; + + len += snprintf(buf + len, PAGE_SIZE - len, + "[%d] vc 0x%x dt 0x%x mux %d cam %d\n", + i, vc->vc, vc->dt, vc->mux, vc->cam); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tmux[%d] en %d src %d irq_stat 0x%x\n", + vc->mux, + mtk_cam_seninf_is_mux_used(ctx, vc->mux), + mtk_cam_seninf_get_top_mux_ctrl(ctx, vc->mux), + SENINF_READ_REG(pmux, SENINF_MUX_IRQ_STATUS)); + len += snprintf(buf + len, PAGE_SIZE - len, + "\t\tfifo_overrun_cnt : <%d>\n", + ctx->fifo_overrun_cnt); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tcam[%d] en %d src %d exp 0x%x res 0x%x irq_stat 0x%x\n", + vc->cam, + mtk_cam_seninf_is_cammux_used(ctx, vc->cam), + mtk_cam_seninf_get_cammux_ctrl(ctx, vc->cam), + mtk_cam_seninf_get_cammux_exp(ctx, vc->cam), + mtk_cam_seninf_get_cammux_res(ctx, vc->cam), + SENINF_READ_REG(pcammux, + SENINF_CAM_MUX_IRQ_STATUS)); + len += snprintf(buf + len, PAGE_SIZE - len, + "\t\tsize_err_cnt : <%d>\n", + ctx->size_err_cnt); + + if (vc->feature == VC_RAW_DATA || + vc->feature == VC_STAGGER_NE || + vc->feature == VC_STAGGER_ME || + vc->feature == VC_STAGGER_SE) { + mtk_cam_seninf_get_mux_meter(ctx, vc->mux, + &meter); + len += snprintf(buf + len, PAGE_SIZE - len, + "\t--- mux meter ---\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "\twidth %d height %d\n", + meter.width, meter.height); + len += snprintf(buf + len, PAGE_SIZE - len, + "\th_valid %d, h_blank %d\n", + meter.h_valid, meter.h_blank); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tv_valid %d, v_blank %d\n", + meter.v_valid, meter.v_blank); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tmipi_pixel_rate %lld\n", + meter.mipi_pixel_rate); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tv_blank %lld us\n", + meter.vb_in_us); + len += snprintf(buf + len, PAGE_SIZE - len, + "\th_blank %lld us\n", + meter.hb_in_us); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tline_time %lld us\n", + meter.line_time_in_us); + } + } + } + + mutex_unlock(&core->mutex); + + return len; +} + +#define SENINF_DRV_DEBUG_MAX_DELAY 400 + +static inline void +mtk_cam_seninf_clear_matched_cam_mux_irq(struct seninf_ctx *ctx, + u32 cam_mux_idx, + u32 vc_idx, + s32 enabled) +{ + u8 used_cammux; + + if (cam_mux_idx >= SENINF_CAM_MUX_NUM) { + dev_info(ctx->dev, "unsupport cam_mux(%u)", cam_mux_idx); + return; + } + if (vc_idx >= SENINF_VC_MAXCNT) { + dev_info(ctx->dev, "unsupport vc_idx(%u)", vc_idx); + return; + } + + used_cammux = ctx->vcinfo.vc[vc_idx].cam; + if (used_cammux == cam_mux_idx && + enabled & (1 << cam_mux_idx)) { + dev_dbg(ctx->dev, + "before clear cam mux%u recSize = 0x%x, irq = 0x%x", + cam_mux_idx, + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_RES + (0x10 * cam_mux_idx)), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX_IRQ_STATUS)); + + SENINF_WRITE_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX_IRQ_STATUS, + 3 << (cam_mux_idx * 2)); + } +} + +static inline void mtk_cam_seninf_check_matched_cam_mux(struct seninf_ctx *ctx, + u32 cam_mux_idx, + u32 vc_idx, + s32 enabled, + s32 irq_status) +{ + u8 used_cammux; + + if (cam_mux_idx >= SENINF_CAM_MUX_NUM) { + dev_info(ctx->dev, "unsupport cam_mux(%u)", cam_mux_idx); + return; + } + if (vc_idx >= SENINF_VC_MAXCNT) { + dev_info(ctx->dev, "unsupport vc_idx(%u)", vc_idx); + return; + } + + used_cammux = ctx->vcinfo.vc[vc_idx].cam; + + if (used_cammux == cam_mux_idx && enabled & (1 << cam_mux_idx)) { + int rec_size = SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_RES + (0x10 * cam_mux_idx)); + int exp_size = SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_CTL_1 + (0x10 * cam_mux_idx)); + if (rec_size != exp_size) { + dev_dbg(ctx->dev, + "cam mux%u size mismatch, (rec, exp) = (0x%x, 0x%x)", + cam_mux_idx, rec_size, exp_size); + } + if ((irq_status & + (3 << (cam_mux_idx * 2))) != 0) { + dev_dbg(ctx->dev, + "cam mux%u size mismatch!, irq = 0x%x", + cam_mux_idx, irq_status); + } + } +} + +int mtk_cam_seninf_debug(struct seninf_ctx *ctx) +{ + void __iomem *base_ana, *base_cphy, *base_dphy, *base_csi, *base_mux; + unsigned int temp = 0; + int pkg_cnt_changed = 0; + unsigned int mipi_packet_cnt = 0; + unsigned int tmp_mipi_packet_cnt = 0; + unsigned long total_delay = 0; + int irq_status = 0; + int enabled = 0; + int ret = 0; + int j, k; + unsigned long debug_ft = 33; + unsigned long debug_vb = 1; + + for (j = CSI_PORT_0A; j < CSI_PORT_3A; j++) { + base_ana = ctx->reg_ana_csi_rx[j]; + dev_dbg(ctx->dev, + "MipiRx_ANA%d: CDPHY_RX_ANA_0(0x%x) ANA_2(0x%x) ANA_4(0x%x) ANA_5(0x%x) ANA_8(0x%x)\n", + j - 3, + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_0), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_2), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_4), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_5), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_8)); + dev_dbg(ctx->dev, + "MipiRx_ANA%d: CDPHY_RX_ANA_AD_0(0x%x) AD_HS_0(0x%x) AD_HS_1(0x%x)\n", + j - 3, + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_AD_0), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_AD_HS_0), + SENINF_READ_REG(base_ana, CDPHY_RX_ANA_AD_HS_1)); + } + + for (j = CSI_PORT_0; j < CSI_PORT_3; j++) { + base_cphy = ctx->reg_ana_cphy_top[j]; + base_dphy = ctx->reg_ana_dphy_top[j]; + + dev_dbg(ctx->dev, + "Csi%d_Dphy_Top: LANE_EN(0x%x) LANE_SELECT(0x%x) DATA_LANE0_HS(0x%x) DATA_LANE1_HS(0x%x) DATA_LANE2_HS(0x%x) DATA_LANE3_HS(0x%x)\n", + j, SENINF_READ_REG(base_dphy, DPHY_RX_LANE_EN), + SENINF_READ_REG(base_dphy, DPHY_RX_LANE_SELECT), + SENINF_READ_REG(base_dphy, + DPHY_RX_DATA_LANE0_HS_PARAMETER), + SENINF_READ_REG(base_dphy, + DPHY_RX_DATA_LANE1_HS_PARAMETER), + SENINF_READ_REG(base_dphy, + DPHY_RX_DATA_LANE2_HS_PARAMETER), + SENINF_READ_REG(base_dphy, + DPHY_RX_DATA_LANE3_HS_PARAMETER)); + + dev_dbg(ctx->dev, + "Csi%d_Cphy_Top: CPHY_RX_CTRL(0x%x) CPHY_RX_DETECT_CTRL_POST(0x%x)\n", + j, SENINF_READ_REG(base_cphy, CPHY_RX_CTRL), + SENINF_READ_REG(base_cphy, CPHY_RX_DETECT_CTRL_POST)); + } + + dev_dbg(ctx->dev, + "SENINF_TOP_MUX_CTRL_0(0x%x) SENINF_TOP_MUX_CTRL_1(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_top, SENINF_TOP_MUX_CTRL_0), + SENINF_READ_REG(ctx->reg_if_top, SENINF_TOP_MUX_CTRL_1)); + + dev_dbg(ctx->dev, + "SENINF_CAM_MUX_CTRL_0(0x%x) SENINF_CAM_MUX_CTRL_1(0x%x) SENINF_CAM_MUX_CTRL_2(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_CTRL_0), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_CTRL_1), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_CTRL_2)); + + enabled = SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_EN); + /* clear cam mux irq */ + for (j = 0; j < ctx->vcinfo.cnt; j++) { + if (ctx->vcinfo.vc[j].enable) + for (k = SENINF_CAM_MUX0; k < SENINF_CAM_MUX_NUM; k++) + mtk_cam_seninf_clear_matched_cam_mux_irq(ctx, k, j, enabled); + } + + /* Seninf_csi status IRQ */ + for (j = SENINF_1; j < _seninf_cfg.seninf_num; j++) { + base_csi = ctx->reg_if_csi2[j]; + temp = SENINF_READ_REG(base_csi, SENINF_CSI2_IRQ_STATUS); + if (temp & ~(0x324)) { + SENINF_WRITE_REG(base_csi, SENINF_CSI2_IRQ_STATUS, + 0xffffffff); + } + dev_dbg(ctx->dev, + "SENINF%d_CSI2_EN(0x%x) SENINF_CSI2_OPT(0x%x) SENINF_CSI2_IRQ_STATUS(0x%x)\n", + j, SENINF_READ_REG(base_csi, SENINF_CSI2_EN), + SENINF_READ_REG(base_csi, SENINF_CSI2_OPT), temp); + } + + /* Seninf_csi packet count */ + pkg_cnt_changed = 0; + base_csi = ctx->reg_if_csi2[(uint32_t)ctx->seninf_idx]; + if (SENINF_READ_REG(base_csi, SENINF_CSI2_EN) & 0x1) { + SENINF_BITS(base_csi, SENINF_CSI2_DBG_CTRL, + RG_CSI2_DBG_PACKET_CNT_EN, 1); + mipi_packet_cnt = SENINF_READ_REG(base_csi, + SENINF_CSI2_PACKET_CNT_STATUS); + + dev_dbg(ctx->dev, "total_delay %ld SENINF%d_PkCnt(0x%x)\n", + total_delay, ctx->seninf_idx, mipi_packet_cnt); + + while (total_delay <= debug_ft) { + tmp_mipi_packet_cnt = mipi_packet_cnt & 0xFFFF; + mdelay(debug_vb); + total_delay += debug_vb; + mipi_packet_cnt = SENINF_READ_REG(base_csi, + SENINF_CSI2_PACKET_CNT_STATUS); + dev_dbg(ctx->dev, + "total_delay %ld SENINF%d_PkCnt(0x%x)\n", + total_delay, ctx->seninf_idx, mipi_packet_cnt); + if (tmp_mipi_packet_cnt != (mipi_packet_cnt & 0xFFFF)) { + pkg_cnt_changed = 1; + break; + } + } + } + if (!pkg_cnt_changed) + ret = -1; + + /* Check csi status again */ + if (debug_ft > total_delay) { + mdelay(debug_ft - total_delay); + total_delay = debug_ft; + } + temp = SENINF_READ_REG(base_csi, SENINF_CSI2_IRQ_STATUS); + dev_dbg(ctx->dev, "SENINF%d_CSI2_IRQ_STATUS(0x%x)\n", + ctx->seninf_idx, temp); + if (total_delay < SENINF_DRV_DEBUG_MAX_DELAY) { + if (total_delay + debug_ft < SENINF_DRV_DEBUG_MAX_DELAY) + mdelay(debug_ft); + else + mdelay(SENINF_DRV_DEBUG_MAX_DELAY - total_delay); + } + temp = SENINF_READ_REG(base_csi, SENINF_CSI2_IRQ_STATUS); + dev_dbg(ctx->dev, "SENINF%d_CSI2_IRQ_STATUS(0x%x)\n", + ctx->seninf_idx, temp); + if ((temp & 0xD0) != 0) + ret = -2; /* multi lanes sync error, crc error, ecc error */ + + /* SENINF_MUX */ + for (j = SENINF_MUX1; j < _seninf_cfg.mux_num; j++) { + base_mux = ctx->reg_if_mux[j]; + dev_dbg(ctx->dev, + "SENINF%d_MUX_CTRL0(0x%x) SENINF%d_MUX_CTRL1(0x%x) SENINF_MUX_IRQ_STATUS(0x%x) SENINF%d_MUX_SIZE(0x%x) SENINF_MUX_ERR_SIZE(0x%x) SENINF_MUX_EXP_SIZE(0x%x)\n", + j, + SENINF_READ_REG(base_mux, SENINF_MUX_CTRL_0), + j, + SENINF_READ_REG(base_mux, SENINF_MUX_CTRL_1), + SENINF_READ_REG(base_mux, SENINF_MUX_IRQ_STATUS), + j, + SENINF_READ_REG(base_mux, SENINF_MUX_SIZE), + SENINF_READ_REG(base_mux, SENINF_MUX_ERR_SIZE), + SENINF_READ_REG(base_mux, SENINF_MUX_IMG_SIZE)); + + if (SENINF_READ_REG(base_mux, SENINF_MUX_IRQ_STATUS) & 0x1) { + SENINF_WRITE_REG(base_mux, SENINF_MUX_IRQ_STATUS, + 0xffffffff); + mdelay(debug_ft); + dev_dbg(ctx->dev, + "after reset overrun, SENINF_MUX_IRQ_STATUS(0x%x) SENINF%d_MUX_SIZE(0x%x)\n", + SENINF_READ_REG(base_mux, SENINF_MUX_IRQ_STATUS), + j, SENINF_READ_REG(base_mux, SENINF_MUX_SIZE)); + } + } + + irq_status = + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_IRQ_STATUS); + + dev_dbg(ctx->dev, + "SENINF_CAM_MUX_EN 0x%x SENINF_CAM_MUX_IRQ_EN 0x%x SENINF_CAM_MUX_IRQ_STATUS 0x%x", + enabled, + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX_IRQ_EN), + irq_status); + + /* check SENINF_CAM_MUX size */ + for (j = 0; j < ctx->vcinfo.cnt; j++) { + if (ctx->vcinfo.vc[j].enable) + for (k = SENINF_CAM_MUX0; k < SENINF_CAM_MUX_NUM; k++) + mtk_cam_seninf_check_matched_cam_mux(ctx, k, j, + enabled, + irq_status); + } + + dev_dbg(ctx->dev, + "SENINF_CAM_MUX size: MUX0(0x%x) MUX1(0x%x) MUX2(0x%x) MUX3(0x%x) MUX4(0x%x) MUX5(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX0_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX1_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX2_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX3_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX4_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX5_CHK_RES)); + dev_dbg(ctx->dev, + "SENINF_CAM_MUX size: MUX6(0x%x) MUX7(0x%x) MUX8(0x%x) MUX9(0x%x) MUX10(0x%x) MUX1(0x%x) MUX12(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX6_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX7_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX8_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX9_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX10_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX11_CHK_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX12_CHK_RES)); + dev_dbg(ctx->dev, + "SENINF_CAM_MUX err size: MUX0(0x%x) MUX1(0x%x) MUX2(0x%x) MUX3(0x%x) MUX4(0x%x) MUX5(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX0_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX1_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX2_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX3_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX4_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX5_CHK_ERR_RES)); + dev_dbg(ctx->dev, + "SENINF_CAM_MUX err size: MUX6(0x%x) MUX7(0x%x) MUX8(0x%x) MUX9(0x%x) MUX10(0x%x) MUX11(0x%x) MUX12(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX6_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX7_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX8_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX9_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX10_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX11_CHK_ERR_RES), + SENINF_READ_REG(ctx->reg_if_cam_mux, + SENINF_CAM_MUX12_CHK_ERR_RES)); + + /* check VC/DT split */ + dev_dbg(ctx->dev, + "VC/DT split:SENINF_CAM_MUX0_OPT(0x%x) MUX1(0x%x) MUX2(0x%x) MUX3(0x%x) MUX4(0x%x) MUX5(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX0_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX1_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX2_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX3_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX4_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX5_OPT)); + dev_dbg(ctx->dev, + "VC/DT split:SENINF_CAM_MUX6_OPT(0x%x) MUX7(0x%x) MUX8(0x%x) MUX9(0x%x) MUX10(0x%x) MUX11(0x%x) MUX12(0x%x)\n", + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX6_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX7_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX8_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX9_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX10_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX11_OPT), + SENINF_READ_REG(ctx->reg_if_cam_mux, SENINF_CAM_MUX12_OPT)); + + dev_dbg(ctx->dev, "ret = %d", ret); + + return ret; +} + +ssize_t mtk_cam_seninf_show_err_status(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, len; + struct seninf_core *core; + struct seninf_ctx *ctx; + struct seninf_vc *vc; + + core = dev_get_drvdata(dev); + len = 0; + + mutex_lock(&core->mutex); + + list_for_each_entry(ctx, &core->list, list) { + len += snprintf(buf + len, PAGE_SIZE - len, + "\n[%s] port %d intf %d test %d cphy %d lanes %d\n", + ctx->subdev.name, ctx->port, ctx->seninf_idx, + ctx->is_test_model, ctx->is_cphy, + ctx->num_data_lanes); + + len += snprintf(buf + len, PAGE_SIZE - len, + "---flag = errs exceed theshhold ? 1 : 0---\n"); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tdata_not_enough error flag : <%d>", + ctx->data_not_enough_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "\terr_lane_resync error flag : <%d>", + ctx->err_lane_resync_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tcrc_err error flag : <%d>", + ctx->crc_err_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tecc_err_double error flag : <%d>", + ctx->ecc_err_double_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tecc_err_corrected error flag : <%d>\n", + ctx->ecc_err_corrected_flag); + + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + len += snprintf(buf + len, PAGE_SIZE - len, + "[%d] vc 0x%x dt 0x%x mux %d cam %d\n", + i, vc->vc, vc->dt, vc->mux, vc->cam); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tfifo_overrun error flag : <%d>", + ctx->fifo_overrun_flag); + len += snprintf(buf + len, PAGE_SIZE - len, + "\tsize_err error flag : <%d>\n", + ctx->size_err_flag); + } + } + + mutex_unlock(&core->mutex); + + return len; +} + +#define SBUF 256 +int mtk_cam_seninf_irq_handler(int irq, void *data) +{ + struct seninf_core *core = (struct seninf_core *)data; + unsigned long flags; /* for mipi err detection */ + struct seninf_ctx *ctx; + struct seninf_vc *vc; + void __iomem *csi2, *pmux, *seninf_cam_mux; + int i; + unsigned int csi_irq_ro; + unsigned int mux_irq_ro; + unsigned int cam_irq_exp_ro; + unsigned int cam_irq_res_ro; + char seninf_log[SBUF]; + unsigned int wcnt = 0; + + spin_lock_irqsave(&core->spinlock_irq, flags); + + /* debug for set_reg case: REG_KEY_CSI_IRQ_EN */ + if (core->csi_irq_en_flag) { + list_for_each_entry(ctx, &core->list, list) { + csi2 = ctx->reg_if_csi2[ctx->seninf_idx]; + csi_irq_ro = + SENINF_READ_REG(csi2, SENINF_CSI2_IRQ_STATUS); + + if (csi_irq_ro) { + SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS, + 0xFFFFFFFF); + } + + if (csi_irq_ro & (0x1 << RO_CSI2_ECC_ERR_CORRECTED_IRQ_SHIFT)) + ctx->ecc_err_corrected_cnt++; + if (csi_irq_ro & (0x1 << RO_CSI2_ECC_ERR_DOUBLE_IRQ_SHIFT)) + ctx->ecc_err_double_cnt++; + if (csi_irq_ro & (0x1 << RO_CSI2_CRC_ERR_IRQ_SHIFT)) + ctx->crc_err_cnt++; + if (csi_irq_ro & (0x1 << RO_CSI2_ERR_LANE_RESYNC_IRQ_SHIFT)) + ctx->err_lane_resync_cnt++; + if (csi_irq_ro & (0x1 << RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_SHIFT)) + ctx->data_not_enough_cnt++; + + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + pmux = ctx->reg_if_mux[vc->mux]; + seninf_cam_mux = ctx->reg_if_cam_mux; + + mux_irq_ro = SENINF_READ_REG(pmux, + SENINF_MUX_IRQ_STATUS); + + cam_irq_exp_ro = SENINF_READ_REG(seninf_cam_mux, + SENINF_CAM_MUX0_CHK_CTL_1 + + (0x10 * (vc->cam))); + + cam_irq_res_ro = SENINF_READ_REG(seninf_cam_mux, + SENINF_CAM_MUX0_CHK_RES + + (0x10 * (vc->cam))); + + if (mux_irq_ro) + SENINF_WRITE_REG(pmux, + SENINF_MUX_IRQ_STATUS, + 0xFFFFFFFF); + + if (cam_irq_res_ro != cam_irq_exp_ro) + SENINF_WRITE_REG(seninf_cam_mux, + SENINF_CAM_MUX0_CHK_RES + + (0x10 * (vc->cam)), + 0xFFFFFFFF); + + if (mux_irq_ro & (0x1 << 0)) + ctx->fifo_overrun_cnt++; + + if (cam_irq_res_ro != cam_irq_exp_ro) + ctx->size_err_cnt++; + } + + /* dump status counter: debug for electrical signal */ + if (ctx->data_not_enough_cnt >= core->detection_cnt || + ctx->err_lane_resync_cnt >= core->detection_cnt || + ctx->crc_err_cnt >= core->detection_cnt || + ctx->ecc_err_double_cnt >= core->detection_cnt || + ctx->ecc_err_corrected_cnt >= core->detection_cnt || + ctx->fifo_overrun_cnt >= core->detection_cnt || + ctx->size_err_cnt >= core->detection_cnt) { + /* disable all interrupts */ + SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_EN, 0x80000000); + + if (ctx->data_not_enough_cnt >= core->detection_cnt) + ctx->data_not_enough_flag = 1; + if (ctx->err_lane_resync_cnt >= core->detection_cnt) + ctx->err_lane_resync_flag = 1; + if (ctx->crc_err_cnt >= core->detection_cnt) + ctx->crc_err_flag = 1; + if (ctx->ecc_err_double_cnt >= core->detection_cnt) + ctx->ecc_err_double_flag = 1; + if (ctx->ecc_err_corrected_cnt >= core->detection_cnt) + ctx->ecc_err_corrected_flag = 1; + if (ctx->fifo_overrun_cnt >= core->detection_cnt) + ctx->fifo_overrun_flag = 1; + if (ctx->size_err_cnt >= core->detection_cnt) + ctx->size_err_flag = 1; + + wcnt = snprintf(seninf_log, SBUF, "info: %s", __func__); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " data_not_enough_count: %d", + ctx->data_not_enough_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " err_lane_resync_count: %d", + ctx->err_lane_resync_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " crc_err_count: %d", + ctx->crc_err_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " ecc_err_double_count: %d", + ctx->ecc_err_double_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " ecc_err_corrected_count: %d", + ctx->ecc_err_corrected_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " fifo_overrun_count: %d", + ctx->fifo_overrun_cnt); + wcnt += snprintf(seninf_log + wcnt, SBUF - wcnt, + " size_err_count: %d", + ctx->size_err_cnt); + } + } + } + + spin_unlock_irqrestore(&core->spinlock_irq, flags); + + return 0; +} + +int mtk_cam_seninf_set_sw_cfg_busy(struct seninf_ctx *ctx, bool enable, + int index) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + + if (index == 0) + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_CTRL, + RG_SENINF_CAM_MUX_DYN_SWITCH_BSY0, enable); + else + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_CTRL, + RG_SENINF_CAM_MUX_DYN_SWITCH_BSY1, enable); + return 0; +} + +int mtk_cam_seninf_set_cam_mux_dyn_en(struct seninf_ctx *ctx, bool enable, + int cam_mux, int index) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + u32 tmp = 0; + + if (index == 0) { + tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN0); + if (enable) + tmp = tmp | (1 << cam_mux); + else + tmp = tmp & ~(1 << cam_mux); + + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN0, tmp); + } else { + tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN1); + if (enable) + tmp = tmp | (1 << cam_mux); + else + tmp = tmp & ~(1 << cam_mux); + + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN1, tmp); + } + + return 0; +} + +int mtk_cam_seninf_reset_cam_mux_dyn_en(struct seninf_ctx *ctx, int index) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + + if (index == 0) + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN0, 0); + else + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_DYN_EN, + RG_SENINF_CAM_MUX_DYN_SWITCH_EN1, 0); + + return 0; +} + +int mtk_cam_seninf_enable_global_drop_irq(struct seninf_ctx *ctx, bool enable, + int index) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + + if (index == 0) + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN, + RG_SENINF_CAM_MUX15_HSIZE_ERR_IRQ_EN, enable); + else + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_IRQ_EN, + RG_SENINF_CAM_MUX15_VSIZE_ERR_IRQ_EN, enable); + + return 0; +} + +int mtk_cam_seninf_enable_cam_mux_vsync_irq(struct seninf_ctx *ctx, bool enable, + int cam_mux) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + int tmp = 0; + + tmp = SENINF_READ_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN, + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN); + if (enable) + tmp |= (enable << cam_mux); + else + tmp &= ~(enable << cam_mux); + + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN, + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, tmp); + return 0; +} + +int mtk_cam_seninf_disable_all_cam_mux_vsync_irq(struct seninf_ctx *ctx) +{ + void __iomem *seninf_cam_mux = ctx->reg_if_cam_mux; + + SENINF_BITS(seninf_cam_mux, SENINF_CAM_MUX_VSYNC_IRQ_EN, + RG_SENINF_CAM_MUX_VSYNC_IRQ_EN, 0); + return 0; +} + +int mtk_cam_seninf_set_reg(struct seninf_ctx *ctx, u32 key, u32 val) +{ + int i; + void __iomem *base = ctx->reg_ana_dphy_top[ctx->port]; + void __iomem *csi2 = ctx->reg_if_csi2[ctx->seninf_idx]; + void __iomem *pmux, *pcammux; + struct seninf_vc *vc; + struct seninf_core *core; + struct seninf_ctx *ctx_; + void __iomem *csi2_; + + core = dev_get_drvdata(ctx->dev->parent); + + if (!ctx->streaming) + return 0; + + dev_dbg(ctx->dev, "%s key = 0x%x, val = 0x%x\n", __func__, key, val); + + switch (key) { + case REG_KEY_SETTLE_CK: + SENINF_BITS(base, DPHY_RX_CLOCK_LANE0_HS_PARAMETER, + RG_DPHY_RX_LC0_HS_SETTLE_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_CLOCK_LANE1_HS_PARAMETER, + RG_DPHY_RX_LC1_HS_SETTLE_PARAMETER, val); + break; + case REG_KEY_SETTLE_DT: + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_CDPHY_RX_LD0_TRIO0_HS_SETTLE_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_CDPHY_RX_LD1_TRIO1_HS_SETTLE_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_CDPHY_RX_LD2_TRIO2_HS_SETTLE_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_CDPHY_RX_LD3_TRIO3_HS_SETTLE_PARAMETER, val); + break; + case REG_KEY_HS_TRAIL_EN: + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_EN, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_DPHY_RX_LD1_HS_TRAIL_EN, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_DPHY_RX_LD2_HS_TRAIL_EN, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_DPHY_RX_LD3_HS_TRAIL_EN, val); + break; + case REG_KEY_HS_TRAIL_PARAM: + SENINF_BITS(base, DPHY_RX_DATA_LANE0_HS_PARAMETER, + RG_DPHY_RX_LD0_HS_TRAIL_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE1_HS_PARAMETER, + RG_DPHY_RX_LD1_HS_TRAIL_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE2_HS_PARAMETER, + RG_DPHY_RX_LD2_HS_TRAIL_PARAMETER, val); + SENINF_BITS(base, DPHY_RX_DATA_LANE3_HS_PARAMETER, + RG_DPHY_RX_LD3_HS_TRAIL_PARAMETER, val); + break; + case REG_KEY_CSI_IRQ_STAT: + SENINF_WRITE_REG(csi2, SENINF_CSI2_IRQ_STATUS, + val & 0xFFFFFFFF); + break; + case REG_KEY_MUX_IRQ_STAT: + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + pmux = ctx->reg_if_mux[vc->mux]; + SENINF_WRITE_REG(pmux, SENINF_MUX_IRQ_STATUS, + val & 0xFFFFFFFF); + } + break; + case REG_KEY_CAMMUX_IRQ_STAT: + for (i = 0; i < ctx->vcinfo.cnt; i++) { + vc = &ctx->vcinfo.vc[i]; + pcammux = ctx->reg_if_cam_mux; + SENINF_WRITE_REG(pcammux, SENINF_CAM_MUX_IRQ_STATUS, + val & 0xFFFFFFFF); + } + break; + case REG_KEY_CSI_IRQ_EN: + { + if (!val) { + core->csi_irq_en_flag = 0; + return 0; + } + + core->csi_irq_en_flag = 1; + core->detection_cnt = val; + list_for_each_entry(ctx_, &core->list, list) { + csi2_ = ctx_->reg_if_csi2[ctx_->seninf_idx]; + SENINF_WRITE_REG(csi2_, SENINF_CSI2_IRQ_EN, + 0xA0002058); + } + } + break; + } + + return 0; +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h new file mode 100644 index 000000000000..7c95b4fb840d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-mipi-rx-ana-cdphy-csi0a.h @@ -0,0 +1,257 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MIPI_RX_ANA_CDPHY_CSI0A_H__ +#define __MIPI_RX_ANA_CDPHY_CSI0A_H__ + +#define CDPHY_RX_ANA_0 0x0000 +#define RG_CSI0_BG_CORE_EN_SHIFT 0 +#define RG_CSI0_BG_CORE_EN_MASK (0x1 << 0) +#define RG_CSI0_BG_LPF_EN_SHIFT 1 +#define RG_CSI0_BG_LPF_EN_MASK (0x1 << 1) +#define RG_CSI0_EQ_PROTECT_EN_SHIFT 4 +#define RG_CSI0_EQ_PROTECT_EN_MASK (0x1 << 4) +#define RG_CSI0_BYTE_CK_RSTB_SEL_SHIFT 5 +#define RG_CSI0_BYTE_CK_RSTB_SEL_MASK (0x1 << 5) +#define RG_CSI0_DPHY_L0_CKSEL_SHIFT 8 +#define RG_CSI0_DPHY_L0_CKSEL_MASK (0x1 << 8) +#define RG_CSI0_DPHY_L1_CKSEL_SHIFT 9 +#define RG_CSI0_DPHY_L1_CKSEL_MASK (0x1 << 9) +#define RG_CSI0_DPHY_L2_CKSEL_SHIFT 10 +#define RG_CSI0_DPHY_L2_CKSEL_MASK (0x1 << 10) +#define RG_CSI0_DPHY_L0_CKMODE_EN_SHIFT 12 +#define RG_CSI0_DPHY_L0_CKMODE_EN_MASK (0x1 << 12) +#define RG_CSI0_DPHY_L1_CKMODE_EN_SHIFT 13 +#define RG_CSI0_DPHY_L1_CKMODE_EN_MASK (0x1 << 13) +#define RG_CSI0_DPHY_L2_CKMODE_EN_SHIFT 14 +#define RG_CSI0_DPHY_L2_CKMODE_EN_MASK (0x1 << 14) +#define RG_CSI0_CDPHY_L0_T0_BYTECK_INVERT_SHIFT 16 +#define RG_CSI0_CDPHY_L0_T0_BYTECK_INVERT_MASK (0x1 << 16) +#define RG_CSI0_DPHY_L1_BYTECK_INVERT_SHIFT 17 +#define RG_CSI0_DPHY_L1_BYTECK_INVERT_MASK (0x1 << 17) +#define RG_CSI0_CDPHY_L2_T1_BYTECK_INVERT_SHIFT 18 +#define RG_CSI0_CDPHY_L2_T1_BYTECK_INVERT_MASK (0x1 << 18) +#define RG_CSI0_CPHY_EN_SHIFT 20 +#define RG_CSI0_CPHY_EN_MASK (0x1 << 20) +#define RG_CSI0_CPHY_T0_CDR_FIRST_EDGE_EN_SHIFT 21 +#define RG_CSI0_CPHY_T0_CDR_FIRST_EDGE_EN_MASK (0x1 << 21) +#define RG_CSI0_CPHY_T1_CDR_FIRST_EDGE_EN_SHIFT 22 +#define RG_CSI0_CPHY_T1_CDR_FIRST_EDGE_EN_MASK (0x1 << 22) +#define RG_CSI0_CDPHY_L0_T0_FORCE_INIT_SHIFT 24 +#define RG_CSI0_CDPHY_L0_T0_FORCE_INIT_MASK (0x1 << 24) +#define RG_CSI0_DPHY_L1_FORCE_INIT_SHIFT 25 +#define RG_CSI0_DPHY_L1_FORCE_INIT_MASK (0x1 << 25) +#define RG_CSI0_CDPHY_L2_T1_FORCE_INIT_SHIFT 26 +#define RG_CSI0_CDPHY_L2_T1_FORCE_INIT_MASK (0x1 << 26) +#define RG_CSI0_CDPHY_L0_T0_SYNC_INIT_CTRL_SHIFT 28 +#define RG_CSI0_CDPHY_L0_T0_SYNC_INIT_CTRL_MASK (0x1 << 28) +#define RG_CSI0_DPHY_L1_SYNC_INIT_CTRL_SHIFT 29 +#define RG_CSI0_DPHY_L1_SYNC_INIT_CTRL_MASK (0x1 << 29) +#define RG_CSI0_CDPHY_L2_T1_SYNC_INIT_CTRL_SHIFT 30 +#define RG_CSI0_CDPHY_L2_T1_SYNC_INIT_CTRL_MASK (0x1 << 30) +#define RG_CSI0_FORCE_HSRT_EN_SHIFT 31 +#define RG_CSI0_FORCE_HSRT_EN_MASK (0x1 << 31) + +#define CDPHY_RX_ANA_1 0x0004 +#define RG_CSI0_BG_LPRX_VTL_SEL_SHIFT 0 +#define RG_CSI0_BG_LPRX_VTL_SEL_MASK (0x7 << 0) +#define RG_CSI0_BG_LPRX_VTH_SEL_SHIFT 4 +#define RG_CSI0_BG_LPRX_VTH_SEL_MASK (0x7 << 4) +#define RG_CSI0_BG_VREF_SEL_SHIFT 8 +#define RG_CSI0_BG_VREF_SEL_MASK (0xf << 8) +#define RG_CSI0_CDPHY_DELAYCAL_CK_SEL_SHIFT 12 +#define RG_CSI0_CDPHY_DELAYCAL_CK_SEL_MASK (0x7 << 12) +#define RG_CSI0_CDPHY_EQ_DES_VREF_SEL_SHIFT 16 +#define RG_CSI0_CDPHY_EQ_DES_VREF_SEL_MASK (0x7 << 16) +#define RG_CSI0_CDPHY_DELAY_VREF_SEL_SHIFT 20 +#define RG_CSI0_CDPHY_DELAY_VREF_SEL_MASK (0x7 << 20) +#define RG_CSI0_DPHY_L0_DELAYCAL_EN_SHIFT 24 +#define RG_CSI0_DPHY_L0_DELAYCAL_EN_MASK (0x1 << 24) +#define RG_CSI0_DPHY_L1_DELAYCAL_EN_SHIFT 25 +#define RG_CSI0_DPHY_L1_DELAYCAL_EN_MASK (0x1 << 25) +#define RG_CSI0_DPHY_L2_DELAYCAL_EN_SHIFT 26 +#define RG_CSI0_DPHY_L2_DELAYCAL_EN_MASK (0x1 << 26) +#define RG_CSI0_DPHY_L0_DELAYCAL_RSTB_SHIFT 28 +#define RG_CSI0_DPHY_L0_DELAYCAL_RSTB_MASK (0x1 << 28) +#define RG_CSI0_DPHY_L1_DELAYCAL_RSTB_SHIFT 29 +#define RG_CSI0_DPHY_L1_DELAYCAL_RSTB_MASK (0x1 << 29) +#define RG_CSI0_DPHY_L2_DELAYCAL_RSTB_SHIFT 30 +#define RG_CSI0_DPHY_L2_DELAYCAL_RSTB_MASK (0x1 << 30) + +#define CDPHY_RX_ANA_2 0x0008 +#define RG_CSI0_L0P_T0A_HSRT_CODE_SHIFT 0 +#define RG_CSI0_L0P_T0A_HSRT_CODE_MASK (0x1f << 0) +#define RG_CSI0_L0N_T0B_HSRT_CODE_SHIFT 8 +#define RG_CSI0_L0N_T0B_HSRT_CODE_MASK (0x1f << 8) +#define RG_CSI0_CPHY_T0_CDR_SELF_CAL_EN_SHIFT 16 +#define RG_CSI0_CPHY_T0_CDR_SELF_CAL_EN_MASK (0x1 << 16) +#define RG_CSI0_CPHY_T1_CDR_SELF_CAL_EN_SHIFT 17 +#define RG_CSI0_CPHY_T1_CDR_SELF_CAL_EN_MASK (0x1 << 17) +#define RG_CSI0_BG_ALP_RX_VTH_SEL_SHIFT 24 +#define RG_CSI0_BG_ALP_RX_VTH_SEL_MASK (0x7 << 24) +#define RG_CSI0_BG_ALP_RX_VTL_SEL_SHIFT 28 +#define RG_CSI0_BG_ALP_RX_VTL_SEL_MASK (0x7 << 28) + +#define CDPHY_RX_ANA_3 0x000c +#define RG_CSI0_L1P_T0C_HSRT_CODE_SHIFT 0 +#define RG_CSI0_L1P_T0C_HSRT_CODE_MASK (0x1f << 0) +#define RG_CSI0_L1N_T1A_HSRT_CODE_SHIFT 8 +#define RG_CSI0_L1N_T1A_HSRT_CODE_MASK (0x1f << 8) +#define RG_CSI0_OS_CAL_CNT_SEL_SHIFT 16 +#define RG_CSI0_OS_CAL_CNT_SEL_MASK (0x3 << 16) +#define RG_CSI0_EQ_DES_VREF_SEL_SHIFT 20 +#define RG_CSI0_EQ_DES_VREF_SEL_MASK (0x3f << 20) + +#define CDPHY_RX_ANA_4 0x0010 +#define RG_CSI0_L2P_T1B_HSRT_CODE_SHIFT 0 +#define RG_CSI0_L2P_T1B_HSRT_CODE_MASK (0x1f << 0) +#define RG_CSI0_L2N_T1C_HSRT_CODE_SHIFT 8 +#define RG_CSI0_L2N_T1C_HSRT_CODE_MASK (0x1f << 8) + +#define CDPHY_RX_ANA_5 0x0014 +#define RG_CSI0_CDPHY_EQ_BW_SHIFT 0 +#define RG_CSI0_CDPHY_EQ_BW_MASK (0x3 << 0) +#define RG_CSI0_CDPHY_EQ_IS_SHIFT 2 +#define RG_CSI0_CDPHY_EQ_IS_MASK (0x3 << 2) +#define RG_CSI0_CDPHY_EQ_DG0_EN_SHIFT 4 +#define RG_CSI0_CDPHY_EQ_DG0_EN_MASK (0x1 << 4) +#define RG_CSI0_CDPHY_EQ_DG1_EN_SHIFT 5 +#define RG_CSI0_CDPHY_EQ_DG1_EN_MASK (0x1 << 5) +#define RG_CSI0_CDPHY_EQ_LATCH_EN_SHIFT 6 +#define RG_CSI0_CDPHY_EQ_LATCH_EN_MASK (0x1 << 6) +#define RG_CSI0_CDPHY_EQ_SR0_SHIFT 8 +#define RG_CSI0_CDPHY_EQ_SR0_MASK (0xf << 8) +#define RG_CSI0_CDPHY_EQ_SR1_SHIFT 12 +#define RG_CSI0_CDPHY_EQ_SR1_MASK (0xf << 12) +#define RG_CSI0_L0_T0AB_EQ_MON_EN_SHIFT 16 +#define RG_CSI0_L0_T0AB_EQ_MON_EN_MASK (0x1 << 16) +#define RG_CSI0_L1_T1AB_EQ_MON_EN_SHIFT 17 +#define RG_CSI0_L1_T1AB_EQ_MON_EN_MASK (0x1 << 17) +#define RG_CSI0_L2_T1BC_EQ_MON_EN_SHIFT 18 +#define RG_CSI0_L2_T1BC_EQ_MON_EN_MASK (0x1 << 18) +#define RG_CSI0_XX_T0BC_EQ_MON_EN_SHIFT 24 +#define RG_CSI0_XX_T0BC_EQ_MON_EN_MASK (0x1 << 24) +#define RG_CSI0_XX_T0CA_EQ_MON_EN_SHIFT 25 +#define RG_CSI0_XX_T0CA_EQ_MON_EN_MASK (0x1 << 25) +#define RG_CSI0_XX_T1CA_EQ_MON_EN_SHIFT 26 +#define RG_CSI0_XX_T1CA_EQ_MON_EN_MASK (0x1 << 26) + +#define CDPHY_RX_ANA_6 0x0018 +#define RG_CSI0_CPHY_T0_CDR_AB_WIDTH_SHIFT 0 +#define RG_CSI0_CPHY_T0_CDR_AB_WIDTH_MASK (0x3f << 0) +#define RG_CSI0_CPHY_T0_CDR_BC_WIDTH_SHIFT 8 +#define RG_CSI0_CPHY_T0_CDR_BC_WIDTH_MASK (0x3f << 8) +#define RG_CSI0_CPHY_T0_CDR_CA_WIDTH_SHIFT 16 +#define RG_CSI0_CPHY_T0_CDR_CA_WIDTH_MASK (0x3f << 16) +#define RG_CSI0_CPHY_T0_CDR_CK_DELAY_SHIFT 24 +#define RG_CSI0_CPHY_T0_CDR_CK_DELAY_MASK (0x3f << 24) + +#define CDPHY_RX_ANA_7 0x001c +#define RG_CSI0_CPHY_T1_CDR_AB_WIDTH_SHIFT 0 +#define RG_CSI0_CPHY_T1_CDR_AB_WIDTH_MASK (0x3f << 0) +#define RG_CSI0_CPHY_T1_CDR_BC_WIDTH_SHIFT 8 +#define RG_CSI0_CPHY_T1_CDR_BC_WIDTH_MASK (0x3f << 8) +#define RG_CSI0_CPHY_T1_CDR_CA_WIDTH_SHIFT 16 +#define RG_CSI0_CPHY_T1_CDR_CA_WIDTH_MASK (0x3f << 16) +#define RG_CSI0_CPHY_T1_CDR_CK_DELAY_SHIFT 24 +#define RG_CSI0_CPHY_T1_CDR_CK_DELAY_MASK (0x3f << 24) + +#define CDPHY_RX_ANA_8 0x0020 +#define RGS_CSI0_CDPHY_L0_T0AB_OS_CAL_CPLT_SHIFT 0 +#define RGS_CSI0_CDPHY_L0_T0AB_OS_CAL_CPLT_MASK (0x1 << 0) +#define RGS_CSI0_CDPHY_L1_T1AB_OS_CAL_CPLT_SHIFT 1 +#define RGS_CSI0_CDPHY_L1_T1AB_OS_CAL_CPLT_MASK (0x1 << 1) +#define RGS_CSI0_CDPHY_L2_T1BC_OS_CAL_CPLT_SHIFT 2 +#define RGS_CSI0_CDPHY_L2_T1BC_OS_CAL_CPLT_MASK (0x1 << 2) +#define RGS_CSI0_CPHY_T0BC_OS_CAL_CPLT_SHIFT 3 +#define RGS_CSI0_CPHY_T0BC_OS_CAL_CPLT_MASK (0x1 << 3) +#define RGS_CSI0_CPHY_T0CA_OS_CAL_CPLT_SHIFT 4 +#define RGS_CSI0_CPHY_T0CA_OS_CAL_CPLT_MASK (0x1 << 4) +#define RGS_CSI0_CPHY_T1CA_OS_CAL_CPLT_SHIFT 5 +#define RGS_CSI0_CPHY_T1CA_OS_CAL_CPLT_MASK (0x1 << 5) +#define RGS_CSI0_OS_CAL_CODE_SHIFT 8 +#define RGS_CSI0_OS_CAL_CODE_MASK (0xff << 8) +#define RG_CSI0_L0_T0AB_EQ_OS_CAL_EN_SHIFT 16 +#define RG_CSI0_L0_T0AB_EQ_OS_CAL_EN_MASK (0x1 << 16) +#define RG_CSI0_L1_T1AB_EQ_OS_CAL_EN_SHIFT 17 +#define RG_CSI0_L1_T1AB_EQ_OS_CAL_EN_MASK (0x1 << 17) +#define RG_CSI0_L2_T1BC_EQ_OS_CAL_EN_SHIFT 18 +#define RG_CSI0_L2_T1BC_EQ_OS_CAL_EN_MASK (0x1 << 18) +#define RG_CSI0_XX_T0BC_EQ_OS_CAL_EN_SHIFT 19 +#define RG_CSI0_XX_T0BC_EQ_OS_CAL_EN_MASK (0x1 << 19) +#define RG_CSI0_XX_T0CA_EQ_OS_CAL_EN_SHIFT 20 +#define RG_CSI0_XX_T0CA_EQ_OS_CAL_EN_MASK (0x1 << 20) +#define RG_CSI0_XX_T1CA_EQ_OS_CAL_EN_SHIFT 21 +#define RG_CSI0_XX_T1CA_EQ_OS_CAL_EN_MASK (0x1 << 21) +#define RG_CSI0_OS_CAL_SEL_SHIFT 24 +#define RG_CSI0_OS_CAL_SEL_MASK (0x7 << 24) +#define RG_CSI0_OS_CAL_DIV_SHIFT 28 +#define RG_CSI0_OS_CAL_DIV_MASK (0x7 << 28) + +#define CDPHY_RX_ANA_9 0x0024 +#define RGS_CSI0_CPHY_T0_DLL_CODE_SHIFT 0 +#define RGS_CSI0_CPHY_T0_DLL_CODE_MASK (0xf << 0) +#define RGS_CSI0_CPHY_T0_MASK_CAL_CPLT_SHIFT 4 +#define RGS_CSI0_CPHY_T0_MASK_CAL_CPLT_MASK (0x1 << 4) +#define RGS_CSI0_CPHY_T0_MASK_CAL_OF_SHIFT 5 +#define RGS_CSI0_CPHY_T0_MASK_CAL_OF_MASK (0x1 << 5) +#define RGS_CSI0_CPHY_T1_DLL_CODE_SHIFT 8 +#define RGS_CSI0_CPHY_T1_DLL_CODE_MASK (0xf << 8) +#define RGS_CSI0_CPHY_T1_MASK_CAL_CPLT_SHIFT 12 +#define RGS_CSI0_CPHY_T1_MASK_CAL_CPLT_MASK (0x1 << 12) +#define RGS_CSI0_CPHY_T1_MASK_CAL_OF_SHIFT 13 +#define RGS_CSI0_CPHY_T1_MASK_CAL_OF_MASK (0x1 << 13) +#define RG_CSI0_RESERVE_SHIFT 16 +#define RG_CSI0_RESERVE_MASK (0xffff << 16) + +#define CDPHY_RX_ANA_AD_0 0x0048 +#define RO_AD_CSI0_CDPHY_L0P_T0A_LPRX_OUT_SHIFT 0 +#define RO_AD_CSI0_CDPHY_L0P_T0A_LPRX_OUT_MASK (0x1 << 0) +#define RO_AD_CSI0_CDPHY_L0N_T0B_LPRX_OUT_SHIFT 1 +#define RO_AD_CSI0_CDPHY_L0N_T0B_LPRX_OUT_MASK (0x1 << 1) +#define RO_AD_CSI0_CDPHY_L1P_T0C_LPRX_OUT_SHIFT 4 +#define RO_AD_CSI0_CDPHY_L1P_T0C_LPRX_OUT_MASK (0x1 << 4) +#define RO_AD_CSI0_CDPHY_L1N_T1A_LPRX_OUT_SHIFT 5 +#define RO_AD_CSI0_CDPHY_L1N_T1A_LPRX_OUT_MASK (0x1 << 5) +#define RO_AD_CSI0_CDPHY_L2P_T1B_LPRX_OUT_SHIFT 8 +#define RO_AD_CSI0_CDPHY_L2P_T1B_LPRX_OUT_MASK (0x1 << 8) +#define RO_AD_CSI0_CDPHY_L2N_T1C_LPRX_OUT_SHIFT 9 +#define RO_AD_CSI0_CDPHY_L2N_T1C_LPRX_OUT_MASK (0x1 << 9) + +#define CDPHY_RX_ANA_AD_HS_0 0x00a0 +#define RO_AD_CSI0_CPHY_T0CA_SHIFT 0 +#define RO_AD_CSI0_CPHY_T0CA_MASK (0xff << 0) +#define RO_AD_CSI0_CPHY_T0BC_SHIFT 8 +#define RO_AD_CSI0_CPHY_T0BC_MASK (0xff << 8) +#define RO_AD_CSI0_CDPHY_L0_T0AB_SHIFT 16 +#define RO_AD_CSI0_CDPHY_L0_T0AB_MASK (0xff << 16) + +#define CDPHY_RX_ANA_AD_HS_1 0x00a4 +#define RO_AD_CSI0_DPHY_L1_SHIFT 16 +#define RO_AD_CSI0_DPHY_L1_MASK (0xff << 16) + +#define CDPHY_RX_ANA_AD_HS_2 0x00a8 +#define RO_AD_CSI0_CPHY_T1CA_SHIFT 8 +#define RO_AD_CSI0_CPHY_T1CA_MASK (0xff << 8) +#define RO_AD_CSI0_CDPHY_L2_T1BC_SHIFT 16 +#define RO_AD_CSI0_CDPHY_L2_T1BC_MASK (0xff << 16) +#define RO_AD_CSI0_CPHY_T1AB_SHIFT 24 +#define RO_AD_CSI0_CPHY_T1AB_MASK (0xff << 24) + +#define CDPHY_RX_ANA_SETTING_0 0x00f0 +#define CSR_CSI_CLK_MON_SHIFT 0 +#define CSR_CSI_CLK_MON_MASK (0x1 << 0) +#define CSR_CSI_CLK_EN_SHIFT 1 +#define CSR_CSI_CLK_EN_MASK (0x1 << 1) +#define CSR_ASYNC_FIFO_GATING_SEL_SHIFT 4 +#define CSR_ASYNC_FIFO_GATING_SEL_MASK (0xf << 4) +#define CSR_CSI_MON_MUX_SHIFT 8 +#define CSR_CSI_MON_MUX_MASK (0xff << 8) +#define CSR_CSI_RST_MODE_SHIFT 16 +#define CSR_CSI_RST_MODE_MASK (0x3 << 16) +#define CSR_SW_RST_SHIFT 24 +#define CSR_SW_RST_MASK (0xf << 24) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h new file mode 100644 index 000000000000..1421f0baa419 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-csi2.h @@ -0,0 +1,415 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF1_CSI2_H__ +#define __SENINF1_CSI2_H__ + +#define SENINF_CSI2_EN 0x0000 +#define CSI2_LANE0_EN_SHIFT 0 +#define CSI2_LANE0_EN_MASK (0x1 << 0) +#define CSI2_LANE1_EN_SHIFT 1 +#define CSI2_LANE1_EN_MASK (0x1 << 1) +#define CSI2_LANE2_EN_SHIFT 2 +#define CSI2_LANE2_EN_MASK (0x1 << 2) +#define CSI2_LANE3_EN_SHIFT 3 +#define CSI2_LANE3_EN_MASK (0x1 << 3) + +#define SENINF_CSI2_OPT 0x0004 +#define RG_CSI2_CPHY_SEL_SHIFT 0 +#define RG_CSI2_CPHY_SEL_MASK (0x1 << 0) +#define RG_CSI2_ECC_EN_SHIFT 1 +#define RG_CSI2_ECC_EN_MASK (0x1 << 1) +#define RG_CSI2_B2P_EN_SHIFT 2 +#define RG_CSI2_B2P_EN_MASK (0x1 << 2) +#define RG_CSI2_GENERIC_LONG_PACKET_EN_SHIFT 3 +#define RG_CSI2_GENERIC_LONG_PACKET_EN_MASK (0x1 << 3) +#define RG_CSI2_IMG_PACKET_EN_SHIFT 4 +#define RG_CSI2_IMG_PACKET_EN_MASK (0x1 << 4) +#define RG_CSI2_SPEC_V2P0_SEL_SHIFT 5 +#define RG_CSI2_SPEC_V2P0_SEL_MASK (0x1 << 5) +#define RG_CSI2_DESCRAMBLE_EN_SHIFT 6 +#define RG_CSI2_DESCRAMBLE_EN_MASK (0x1 << 6) +#define RG_CSI2_VS_OUTPUT_MODE_SHIFT 8 +#define RG_CSI2_VS_OUTPUT_MODE_MASK (0x1 << 8) +#define RG_CSI2_VS_OUTPUT_LEN_SEL_SHIFT 9 +#define RG_CSI2_VS_OUTPUT_LEN_SEL_MASK (0x1 << 9) +#define RG_CSI2_HSYNC_POL_SHIFT 12 +#define RG_CSI2_HSYNC_POL_MASK (0x1 << 12) +#define RG_CSI2_VSYNC_POL_SHIFT 13 +#define RG_CSI2_VSYNC_POL_MASK (0x1 << 13) +#define RG_CSI2_FIFO_PUSH_EN_SHIFT 16 +#define RG_CSI2_FIFO_PUSH_EN_MASK (0x3f << 16) + +#define SENINF_CSI2_HDR_MODE_0 0x0008 +#define RG_CSI2_HEADER_MODE_SHIFT 0 +#define RG_CSI2_HEADER_MODE_MASK (0xff << 0) +#define RG_CSI2_HEADER_LEN_SHIFT 8 +#define RG_CSI2_HEADER_LEN_MASK (0x7 << 8) + +#define SENINF_CSI2_RESYNC_MERGE_CTRL 0x0010 +#define RG_CSI2_RESYNC_CYCLE_CNT_SHIFT 0 +#define RG_CSI2_RESYNC_CYCLE_CNT_MASK (0x1f << 0) +#define RG_CSI2_RESYNC_CYCLE_CNT_OPT_SHIFT 8 +#define RG_CSI2_RESYNC_CYCLE_CNT_OPT_MASK (0x1 << 8) +#define RG_CSI2_RESYNC_DATAOUT_OPT_SHIFT 9 +#define RG_CSI2_RESYNC_DATAOUT_OPT_MASK (0x1 << 9) +#define RG_CSI2_RESYNC_BYPASS_SHIFT 10 +#define RG_CSI2_RESYNC_BYPASS_MASK (0x1 << 10) + +#define RG_CSI2_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_VC_SEL_SHIFT 8 +#define RG_CSI2_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_DT_SEL_SHIFT 16 +#define RG_CSI2_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S0_DI_CTRL 0x0020 +#define RG_CSI2_S0_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S0_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S0_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S0_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S0_VC_SEL_SHIFT 8 +#define RG_CSI2_S0_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S0_DT_SEL_SHIFT 16 +#define RG_CSI2_S0_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S1_DI_CTRL 0x0024 +#define RG_CSI2_S1_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S1_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S1_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S1_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S1_VC_SEL_SHIFT 8 +#define RG_CSI2_S1_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S1_DT_SEL_SHIFT 16 +#define RG_CSI2_S1_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S2_DI_CTRL 0x0028 +#define RG_CSI2_S2_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S2_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S2_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S2_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S2_VC_SEL_SHIFT 8 +#define RG_CSI2_S2_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S2_DT_SEL_SHIFT 16 +#define RG_CSI2_S2_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S3_DI_CTRL 0x002c +#define RG_CSI2_S3_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S3_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S3_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S3_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S3_VC_SEL_SHIFT 8 +#define RG_CSI2_S3_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S3_DT_SEL_SHIFT 16 +#define RG_CSI2_S3_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S4_DI_CTRL 0x0030 +#define RG_CSI2_S4_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S4_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S4_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S4_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S4_VC_SEL_SHIFT 8 +#define RG_CSI2_S4_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S4_DT_SEL_SHIFT 16 +#define RG_CSI2_S4_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S5_DI_CTRL 0x0034 +#define RG_CSI2_S5_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S5_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S5_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S5_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S5_VC_SEL_SHIFT 8 +#define RG_CSI2_S5_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S5_DT_SEL_SHIFT 16 +#define RG_CSI2_S5_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S6_DI_CTRL 0x0038 +#define RG_CSI2_S6_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S6_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S6_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S6_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S6_VC_SEL_SHIFT 8 +#define RG_CSI2_S6_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S6_DT_SEL_SHIFT 16 +#define RG_CSI2_S6_DT_SEL_MASK (0x3f << 16) + +#define SENINF_CSI2_S7_DI_CTRL 0x003c +#define RG_CSI2_S7_VC_INTERLEAVE_EN_SHIFT 0 +#define RG_CSI2_S7_VC_INTERLEAVE_EN_MASK (0x1 << 0) +#define RG_CSI2_S7_DT_INTERLEAVE_MODE_SHIFT 4 +#define RG_CSI2_S7_DT_INTERLEAVE_MODE_MASK (0x3 << 4) +#define RG_CSI2_S7_VC_SEL_SHIFT 8 +#define RG_CSI2_S7_VC_SEL_MASK (0x1f << 8) +#define RG_CSI2_S7_DT_SEL_SHIFT 16 +#define RG_CSI2_S7_DT_SEL_MASK (0x3f << 16) + +#define RG_CSI2_GRP_MODE_SHIFT 0 +#define RG_CSI2_GRP_MODE_MASK (0x1 << 0) +#define RG_CSI2_VSYNC_BYPASS_SHIFT 1 +#define RG_CSI2_VSYNC_BYPASS_MASK (0x1 << 1) +#define RG_CSI2_S0_GRP_EN_SHIFT 8 +#define RG_CSI2_S0_GRP_EN_MASK (0x1 << 8) +#define RG_CSI2_S1_GRP_EN_SHIFT 9 +#define RG_CSI2_S1_GRP_EN_MASK (0x1 << 9) +#define RG_CSI2_S2_GRP_EN_SHIFT 10 +#define RG_CSI2_S2_GRP_EN_MASK (0x1 << 10) +#define RG_CSI2_S3_GRP_EN_SHIFT 11 +#define RG_CSI2_S3_GRP_EN_MASK (0x1 << 11) +#define RG_CSI2_S4_GRP_EN_SHIFT 12 +#define RG_CSI2_S4_GRP_EN_MASK (0x1 << 12) +#define RG_CSI2_S5_GRP_EN_SHIFT 13 +#define RG_CSI2_S5_GRP_EN_MASK (0x1 << 13) +#define RG_CSI2_S6_GRP_EN_SHIFT 14 +#define RG_CSI2_S6_GRP_EN_MASK (0x1 << 14) +#define RG_CSI2_S7_GRP_EN_SHIFT 15 +#define RG_CSI2_S7_GRP_EN_MASK (0x1 << 15) + +#define SENINF_CSI2_CH0_CTRL 0x0060 +#define RG_CSI2_CH0_GRP_MODE_SHIFT 0 +#define RG_CSI2_CH0_GRP_MODE_MASK (0x1 << 0) +#define RG_CSI2_CH0_VSYNC_BYPASS_SHIFT 1 +#define RG_CSI2_CH0_VSYNC_BYPASS_MASK (0x1 << 1) +#define RG_CSI2_CH0_S0_GRP_EN_SHIFT 8 +#define RG_CSI2_CH0_S0_GRP_EN_MASK (0x1 << 8) +#define RG_CSI2_CH0_S1_GRP_EN_SHIFT 9 +#define RG_CSI2_CH0_S1_GRP_EN_MASK (0x1 << 9) +#define RG_CSI2_CH0_S2_GRP_EN_SHIFT 10 +#define RG_CSI2_CH0_S2_GRP_EN_MASK (0x1 << 10) +#define RG_CSI2_CH0_S3_GRP_EN_SHIFT 11 +#define RG_CSI2_CH0_S3_GRP_EN_MASK (0x1 << 11) +#define RG_CSI2_CH0_S4_GRP_EN_SHIFT 12 +#define RG_CSI2_CH0_S4_GRP_EN_MASK (0x1 << 12) +#define RG_CSI2_CH0_S5_GRP_EN_SHIFT 13 +#define RG_CSI2_CH0_S5_GRP_EN_MASK (0x1 << 13) +#define RG_CSI2_CH0_S6_GRP_EN_SHIFT 14 +#define RG_CSI2_CH0_S6_GRP_EN_MASK (0x1 << 14) +#define RG_CSI2_CH0_S7_GRP_EN_SHIFT 15 +#define RG_CSI2_CH0_S7_GRP_EN_MASK (0x1 << 15) + +#define SENINF_CSI2_CH1_CTRL 0x0064 +#define RG_CSI2_CH1_GRP_MODE_SHIFT 0 +#define RG_CSI2_CH1_GRP_MODE_MASK (0x1 << 0) +#define RG_CSI2_CH1_VSYNC_BYPASS_SHIFT 1 +#define RG_CSI2_CH1_VSYNC_BYPASS_MASK (0x1 << 1) +#define RG_CSI2_CH1_S0_GRP_EN_SHIFT 8 +#define RG_CSI2_CH1_S0_GRP_EN_MASK (0x1 << 8) +#define RG_CSI2_CH1_S1_GRP_EN_SHIFT 9 +#define RG_CSI2_CH1_S1_GRP_EN_MASK (0x1 << 9) +#define RG_CSI2_CH1_S2_GRP_EN_SHIFT 10 +#define RG_CSI2_CH1_S2_GRP_EN_MASK (0x1 << 10) +#define RG_CSI2_CH1_S3_GRP_EN_SHIFT 11 +#define RG_CSI2_CH1_S3_GRP_EN_MASK (0x1 << 11) +#define RG_CSI2_CH1_S4_GRP_EN_SHIFT 12 +#define RG_CSI2_CH1_S4_GRP_EN_MASK (0x1 << 12) +#define RG_CSI2_CH1_S5_GRP_EN_SHIFT 13 +#define RG_CSI2_CH1_S5_GRP_EN_MASK (0x1 << 13) +#define RG_CSI2_CH1_S6_GRP_EN_SHIFT 14 +#define RG_CSI2_CH1_S6_GRP_EN_MASK (0x1 << 14) +#define RG_CSI2_CH1_S7_GRP_EN_SHIFT 15 +#define RG_CSI2_CH1_S7_GRP_EN_MASK (0x1 << 15) + +#define SENINF_CSI2_CH2_CTRL 0x0068 +#define RG_CSI2_CH2_GRP_MODE_SHIFT 0 +#define RG_CSI2_CH2_GRP_MODE_MASK (0x1 << 0) +#define RG_CSI2_CH2_VSYNC_BYPASS_SHIFT 1 +#define RG_CSI2_CH2_VSYNC_BYPASS_MASK (0x1 << 1) +#define RG_CSI2_CH2_S0_GRP_EN_SHIFT 8 +#define RG_CSI2_CH2_S0_GRP_EN_MASK (0x1 << 8) +#define RG_CSI2_CH2_S1_GRP_EN_SHIFT 9 +#define RG_CSI2_CH2_S1_GRP_EN_MASK (0x1 << 9) +#define RG_CSI2_CH2_S2_GRP_EN_SHIFT 10 +#define RG_CSI2_CH2_S2_GRP_EN_MASK (0x1 << 10) +#define RG_CSI2_CH2_S3_GRP_EN_SHIFT 11 +#define RG_CSI2_CH2_S3_GRP_EN_MASK (0x1 << 11) +#define RG_CSI2_CH2_S4_GRP_EN_SHIFT 12 +#define RG_CSI2_CH2_S4_GRP_EN_MASK (0x1 << 12) +#define RG_CSI2_CH2_S5_GRP_EN_SHIFT 13 +#define RG_CSI2_CH2_S5_GRP_EN_MASK (0x1 << 13) +#define RG_CSI2_CH2_S6_GRP_EN_SHIFT 14 +#define RG_CSI2_CH2_S6_GRP_EN_MASK (0x1 << 14) +#define RG_CSI2_CH2_S7_GRP_EN_SHIFT 15 +#define RG_CSI2_CH2_S7_GRP_EN_MASK (0x1 << 15) + +#define SENINF_CSI2_CH3_CTRL 0x006c +#define RG_CSI2_CH3_GRP_MODE_SHIFT 0 +#define RG_CSI2_CH3_GRP_MODE_MASK (0x1 << 0) +#define RG_CSI2_CH3_VSYNC_BYPASS_SHIFT 1 +#define RG_CSI2_CH3_VSYNC_BYPASS_MASK (0x1 << 1) +#define RG_CSI2_CH3_S0_GRP_EN_SHIFT 8 +#define RG_CSI2_CH3_S0_GRP_EN_MASK (0x1 << 8) +#define RG_CSI2_CH3_S1_GRP_EN_SHIFT 9 +#define RG_CSI2_CH3_S1_GRP_EN_MASK (0x1 << 9) +#define RG_CSI2_CH3_S2_GRP_EN_SHIFT 10 +#define RG_CSI2_CH3_S2_GRP_EN_MASK (0x1 << 10) +#define RG_CSI2_CH3_S3_GRP_EN_SHIFT 11 +#define RG_CSI2_CH3_S3_GRP_EN_MASK (0x1 << 11) +#define RG_CSI2_CH3_S4_GRP_EN_SHIFT 12 +#define RG_CSI2_CH3_S4_GRP_EN_MASK (0x1 << 12) +#define RG_CSI2_CH3_S5_GRP_EN_SHIFT 13 +#define RG_CSI2_CH3_S5_GRP_EN_MASK (0x1 << 13) +#define RG_CSI2_CH3_S6_GRP_EN_SHIFT 14 +#define RG_CSI2_CH3_S6_GRP_EN_MASK (0x1 << 14) +#define RG_CSI2_CH3_S7_GRP_EN_SHIFT 15 +#define RG_CSI2_CH3_S7_GRP_EN_MASK (0x1 << 15) + +#define SENINF_CSI2_IRQ_EN 0x00c0 +#define RG_CSI2_ERR_FRAME_SYNC_IRQ_EN_SHIFT 0 +#define RG_CSI2_ERR_FRAME_SYNC_IRQ_EN_MASK (0x1 << 0) +#define RG_CSI2_ERR_ID_IRQ_EN_SHIFT 1 +#define RG_CSI2_ERR_ID_IRQ_EN_MASK (0x1 << 1) +#define RG_CSI2_ECC_ERR_UNDETECTED_IRQ_EN_SHIFT 2 +#define RG_CSI2_ECC_ERR_UNDETECTED_IRQ_EN_MASK (0x1 << 2) +#define RG_CSI2_ECC_ERR_CORRECTED_IRQ_EN_SHIFT 3 +#define RG_CSI2_ECC_ERR_CORRECTED_IRQ_EN_MASK (0x1 << 3) +#define RG_CSI2_ECC_ERR_DOUBLE_IRQ_EN_SHIFT 4 +#define RG_CSI2_ECC_ERR_DOUBLE_IRQ_EN_MASK (0x1 << 4) +#define RG_CSI2_CRC_CORRECT_IRQ_EN_SHIFT 5 +#define RG_CSI2_CRC_CORRECT_IRQ_EN_MASK (0x1 << 5) +#define RG_CSI2_CRC_ERR_IRQ_EN_SHIFT 6 +#define RG_CSI2_CRC_ERR_IRQ_EN_MASK (0x1 << 6) +#define RG_CSI2_ERR_MULTI_LANE_SYNC_IRQ_EN_SHIFT 7 +#define RG_CSI2_ERR_MULTI_LANE_SYNC_IRQ_EN_MASK (0x1 << 7) +#define RG_CSI2_FS_RECEIVE_IRQ_EN_SHIFT 8 +#define RG_CSI2_FS_RECEIVE_IRQ_EN_MASK (0x1 << 8) +#define RG_CSI2_FE_RECEIVE_IRQ_EN_SHIFT 9 +#define RG_CSI2_FE_RECEIVE_IRQ_EN_MASK (0x1 << 9) +#define RG_CSI2_LS_RECEIVE_IRQ_EN_SHIFT 10 +#define RG_CSI2_LS_RECEIVE_IRQ_EN_MASK (0x1 << 10) +#define RG_CSI2_LE_RECEIVE_IRQ_EN_SHIFT 11 +#define RG_CSI2_LE_RECEIVE_IRQ_EN_MASK (0x1 << 11) +#define RG_CSI2_GS_RECEIVE_IRQ_EN_SHIFT 12 +#define RG_CSI2_GS_RECEIVE_IRQ_EN_MASK (0x1 << 12) +#define RG_CSI2_ERR_LANE_RESYNC_IRQ_EN_SHIFT 13 +#define RG_CSI2_ERR_LANE_RESYNC_IRQ_EN_MASK (0x1 << 13) +#define RG_CSI2_LANE_MERGE_FIFO_AF_IRQ_EN_SHIFT 14 +#define RG_CSI2_LANE_MERGE_FIFO_AF_IRQ_EN_MASK (0x1 << 14) +#define RG_CSI2_ERR_FRAME_SYNC_S0_IRQ_EN_SHIFT 16 +#define RG_CSI2_ERR_FRAME_SYNC_S0_IRQ_EN_MASK (0x1 << 16) +#define RG_CSI2_ERR_FRAME_SYNC_S1_IRQ_EN_SHIFT 17 +#define RG_CSI2_ERR_FRAME_SYNC_S1_IRQ_EN_MASK (0x1 << 17) +#define RG_CSI2_ERR_FRAME_SYNC_S2_IRQ_EN_SHIFT 18 +#define RG_CSI2_ERR_FRAME_SYNC_S2_IRQ_EN_MASK (0x1 << 18) +#define RG_CSI2_ERR_FRAME_SYNC_S3_IRQ_EN_SHIFT 19 +#define RG_CSI2_ERR_FRAME_SYNC_S3_IRQ_EN_MASK (0x1 << 19) +#define RG_CSI2_ERR_FRAME_SYNC_S4_IRQ_EN_SHIFT 20 +#define RG_CSI2_ERR_FRAME_SYNC_S4_IRQ_EN_MASK (0x1 << 20) +#define RG_CSI2_ERR_FRAME_SYNC_S5_IRQ_EN_SHIFT 21 +#define RG_CSI2_ERR_FRAME_SYNC_S5_IRQ_EN_MASK (0x1 << 21) +#define RG_CSI2_ERR_FRAME_SYNC_S6_IRQ_EN_SHIFT 22 +#define RG_CSI2_ERR_FRAME_SYNC_S6_IRQ_EN_MASK (0x1 << 22) +#define RG_CSI2_ERR_FRAME_SYNC_S7_IRQ_EN_SHIFT 23 +#define RG_CSI2_ERR_FRAME_SYNC_S7_IRQ_EN_MASK (0x1 << 23) +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ_EN_SHIFT 24 +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ_EN_MASK (0x1 << 24) +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ_EN_SHIFT 25 +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ_EN_MASK (0x1 << 25) +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ_EN_SHIFT 26 +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ_EN_MASK (0x1 << 26) +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ_EN_SHIFT 27 +#define RG_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ_EN_MASK (0x1 << 27) +#define RG_CSI2_ASYNC_FIFO_OVERRUN_IRQ_EN_SHIFT 28 +#define RG_CSI2_ASYNC_FIFO_OVERRUN_IRQ_EN_MASK (0x1 << 28) +#define RG_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_EN_SHIFT 29 +#define RG_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_EN_MASK (0x1 << 29) +#define RG_CSI2_IRQ_CLR_MODE_SHIFT 31 +#define RG_CSI2_IRQ_CLR_MODE_MASK (0x1 << 31) + +#define SENINF_CSI2_IRQ_STATUS 0x00c8 +#define RO_CSI2_ERR_FRAME_SYNC_IRQ_SHIFT 0 +#define RO_CSI2_ERR_FRAME_SYNC_IRQ_MASK (0x1 << 0) +#define RO_CSI2_ERR_ID_IRQ_SHIFT 1 +#define RO_CSI2_ERR_ID_IRQ_MASK (0x1 << 1) +#define RO_CSI2_ECC_ERR_UNDETECTED_IRQ_SHIFT 2 +#define RO_CSI2_ECC_ERR_UNDETECTED_IRQ_MASK (0x1 << 2) +#define RO_CSI2_ECC_ERR_CORRECTED_IRQ_SHIFT 3 +#define RO_CSI2_ECC_ERR_CORRECTED_IRQ_MASK (0x1 << 3) +#define RO_CSI2_ECC_ERR_DOUBLE_IRQ_SHIFT 4 +#define RO_CSI2_ECC_ERR_DOUBLE_IRQ_MASK (0x1 << 4) +#define RO_CSI2_CRC_CORRECT_IRQ_SHIFT 5 +#define RO_CSI2_CRC_CORRECT_IRQ_MASK (0x1 << 5) +#define RO_CSI2_CRC_ERR_IRQ_SHIFT 6 +#define RO_CSI2_CRC_ERR_IRQ_MASK (0x1 << 6) +#define RO_CSI2_ERR_MULTI_LANE_SYNC_IRQ_SHIFT 7 +#define RO_CSI2_ERR_MULTI_LANE_SYNC_IRQ_MASK (0x1 << 7) +#define RO_CSI2_FS_RECEIVE_IRQ_SHIFT 8 +#define RO_CSI2_FS_RECEIVE_IRQ_MASK (0x1 << 8) +#define RO_CSI2_FE_RECEIVE_IRQ_SHIFT 9 +#define RO_CSI2_FE_RECEIVE_IRQ_MASK (0x1 << 9) +#define RO_CSI2_LS_RECEIVE_IRQ_SHIFT 10 +#define RO_CSI2_LS_RECEIVE_IRQ_MASK (0x1 << 10) +#define RO_CSI2_LE_RECEIVE_IRQ_SHIFT 11 +#define RO_CSI2_LE_RECEIVE_IRQ_MASK (0x1 << 11) +#define RO_CSI2_GS_RECEIVE_IRQ_SHIFT 12 +#define RO_CSI2_GS_RECEIVE_IRQ_MASK (0x1 << 12) +#define RO_CSI2_ERR_LANE_RESYNC_IRQ_SHIFT 13 +#define RO_CSI2_ERR_LANE_RESYNC_IRQ_MASK (0x1 << 13) +#define RO_CSI2_LANE_MERGE_FIFO_AF_IRQ_SHIFT 14 +#define RO_CSI2_LANE_MERGE_FIFO_AF_IRQ_MASK (0x1 << 14) +#define RO_CSI2_ERR_FRAME_SYNC_S0_IRQ_SHIFT 16 +#define RO_CSI2_ERR_FRAME_SYNC_S0_IRQ_MASK (0x1 << 16) +#define RO_CSI2_ERR_FRAME_SYNC_S1_IRQ_SHIFT 17 +#define RO_CSI2_ERR_FRAME_SYNC_S1_IRQ_MASK (0x1 << 17) +#define RO_CSI2_ERR_FRAME_SYNC_S2_IRQ_SHIFT 18 +#define RO_CSI2_ERR_FRAME_SYNC_S2_IRQ_MASK (0x1 << 18) +#define RO_CSI2_ERR_FRAME_SYNC_S3_IRQ_SHIFT 19 +#define RO_CSI2_ERR_FRAME_SYNC_S3_IRQ_MASK (0x1 << 19) +#define RO_CSI2_ERR_FRAME_SYNC_S4_IRQ_SHIFT 20 +#define RO_CSI2_ERR_FRAME_SYNC_S4_IRQ_MASK (0x1 << 20) +#define RO_CSI2_ERR_FRAME_SYNC_S5_IRQ_SHIFT 21 +#define RO_CSI2_ERR_FRAME_SYNC_S5_IRQ_MASK (0x1 << 21) +#define RO_CSI2_ERR_FRAME_SYNC_S6_IRQ_SHIFT 22 +#define RO_CSI2_ERR_FRAME_SYNC_S6_IRQ_MASK (0x1 << 22) +#define RO_CSI2_ERR_FRAME_SYNC_S7_IRQ_SHIFT 23 +#define RO_CSI2_ERR_FRAME_SYNC_S7_IRQ_MASK (0x1 << 23) +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ_SHIFT 24 +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L0_IRQ_MASK (0x1 << 24) +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ_SHIFT 25 +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L1_IRQ_MASK (0x1 << 25) +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ_SHIFT 26 +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L2_IRQ_MASK (0x1 << 26) +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ_SHIFT 27 +#define RO_CSI2_RESYNC_FIFO_OVERFLOW_L3_IRQ_MASK (0x1 << 27) +#define RO_CSI2_ASYNC_FIFO_OVERRUN_IRQ_SHIFT 28 +#define RO_CSI2_ASYNC_FIFO_OVERRUN_IRQ_MASK (0x1 << 28) +#define RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_SHIFT 29 +#define RO_CSI2_RECEIVE_DATA_NOT_ENOUGH_IRQ_MASK (0x1 << 29) + +#define SENINF_CSI2_LINE_FRAME_NUM 0x00d0 +#define RO_CSI2_LINE_NUM_SHIFT 0 +#define RO_CSI2_LINE_NUM_MASK (0xffff << 0) +#define RO_CSI2_FRAME_NUM_SHIFT 16 +#define RO_CSI2_FRAME_NUM_MASK (0xffff << 16) + +#define SENINF_CSI2_PACKET_STATUS 0x00d4 +#define RO_CSI2_PACKET_DT_SHIFT 0 +#define RO_CSI2_PACKET_DT_MASK (0x3f << 0) +#define RO_CSI2_PACKET_VC_SHIFT 8 +#define RO_CSI2_PACKET_VC_MASK (0x1f << 8) +#define RO_CSI2_PACKET_WC_SHIFT 16 +#define RO_CSI2_PACKET_WC_MASK (0xffff << 16) + +#define SENINF_CSI2_GEN_SHORT_PACKET_STATUS 0x00d8 +#define RO_CSI2_GENERIC_SHORT_PACKET_DT_SHIFT 0 +#define RO_CSI2_GENERIC_SHORT_PACKET_DT_MASK (0x3f << 0) +#define RO_CSI2_GENERIC_SHORT_PACKET_WC_SHIFT 16 +#define RO_CSI2_GENERIC_SHORT_PACKET_WC_MASK (0xffff << 16) + +#define SENINF_CSI2_PACKET_CNT_STATUS 0x00dc +#define RO_CSI2_PACKET_CNT_SHIFT 0 +#define RO_CSI2_PACKET_CNT_MASK (0xffff << 0) +#define RO_CSI2_PACKET_CNT_BUF_SHIFT 16 +#define RO_CSI2_PACKET_CNT_BUF_MASK (0xffff << 16) + +#define SENINF_CSI2_DBG_CTRL 0x00e0 +#define RG_CSI2_DBG_SEL_SHIFT 0 +#define RG_CSI2_DBG_SEL_MASK (0xff << 0) +#define RG_CSI2_DBG_EN_SHIFT 16 +#define RG_CSI2_DBG_EN_MASK (0x1 << 16) +#define RG_CSI2_DBG_PACKET_CNT_EN_SHIFT 17 +#define RG_CSI2_DBG_PACKET_CNT_EN_MASK (0x1 << 17) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h new file mode 100644 index 000000000000..696b39dc6c9a --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1-mux.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF1_MUX_H__ +#define __SENINF1_MUX_H__ + +#define SENINF_MUX_CTRL_0 0x0000 +#define SENINF_MUX_EN_SHIFT 0 +#define SENINF_MUX_EN_MASK (0x1 << 0) +#define SENINF_MUX_IRQ_SW_RST_SHIFT 1 +#define SENINF_MUX_IRQ_SW_RST_MASK (0x1 << 1) +#define SENINF_MUX_SW_RST_SHIFT 2 +#define SENINF_MUX_SW_RST_MASK (0x1 << 2) + +#define SENINF_MUX_CTRL_1 0x0004 +#define RG_SENINF_MUX_SRC_SEL_SHIFT 0 +#define RG_SENINF_MUX_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_MUX_PIX_MODE_SEL_SHIFT 8 +#define RG_SENINF_MUX_PIX_MODE_SEL_MASK (0x3 << 8) +#define RG_SENINF_MUX_FIFO_PUSH_EN_SHIFT 16 +#define RG_SENINF_MUX_FIFO_PUSH_EN_MASK (0x3f << 16) +#define RG_SENINF_MUX_RDY_FORCE_MODE_EN_SHIFT 24 +#define RG_SENINF_MUX_RDY_FORCE_MODE_EN_MASK (0x1 << 24) +#define RG_SENINF_MUX_RDY_FORCE_MODE_VAL_SHIFT 25 +#define RG_SENINF_MUX_RDY_FORCE_MODE_VAL_MASK (0x1 << 25) +#define RG_SENINF_MUX_CROP_EN_SHIFT 28 +#define RG_SENINF_MUX_CROP_EN_MASK (0x1 << 28) + +#define SENINF_MUX_OPT 0x0008 +#define RG_SENINF_MUX_CNT_INIT_OPT_SHIFT 0 +#define RG_SENINF_MUX_CNT_INIT_OPT_MASK (0x3 << 0) +#define RG_SENINF_MUX_FIFO_FULL_OUTPUT_OPT_SHIFT 8 +#define RG_SENINF_MUX_FIFO_FULL_OUTPUT_OPT_MASK (0x3 << 8) +#define RG_SENINF_MUX_FIFO_FULL_WR_MODE_SHIFT 10 +#define RG_SENINF_MUX_FIFO_FULL_WR_MODE_MASK (0x3 << 10) +#define RG_SENINF_MUX_FIFO_OVERRUN_RST_EN_SHIFT 12 +#define RG_SENINF_MUX_FIFO_OVERRUN_RST_EN_MASK (0x1 << 12) +#define RG_SENINF_MUX_HSYNC_POL_SHIFT 16 +#define RG_SENINF_MUX_HSYNC_POL_MASK (0x1 << 16) +#define RG_SENINF_MUX_VSYNC_POL_SHIFT 17 +#define RG_SENINF_MUX_VSYNC_POL_MASK (0x1 << 17) + +#define SENINF_MUX_IRQ_EN 0x0010 +#define RG_SENINF_MUX_FIFO_OVERRUN_IRQ_EN_SHIFT 0 +#define RG_SENINF_MUX_FIFO_OVERRUN_IRQ_EN_MASK (0x1 << 0) +#define RG_SENINF_MUX_FSM_ERR_IRQ_EN_SHIFT 1 +#define RG_SENINF_MUX_FSM_ERR_IRQ_EN_MASK (0x1 << 1) +#define RG_SENINF_MUX_HSIZE_ERR_IRQ_EN_SHIFT 2 +#define RG_SENINF_MUX_HSIZE_ERR_IRQ_EN_MASK (0x1 << 2) +#define RG_SENINF_MUX_VSIZE_ERR_IRQ_EN_SHIFT 3 +#define RG_SENINF_MUX_VSIZE_ERR_IRQ_EN_MASK (0x1 << 3) +#define RG_SENINF_MUX_IRQ_CLR_MODE_SHIFT 31 +#define RG_SENINF_MUX_IRQ_CLR_MODE_MASK (0x1 << 31) + +#define SENINF_MUX_IRQ_STATUS 0x0018 +#define RO_SENINF_MUX_FIFO_OVERRUN_IRQ_SHIFT 0 +#define RO_SENINF_MUX_FIFO_OVERRUN_IRQ_MASK (0x1 << 0) +#define RO_SENINF_MUX_FSM_ERR_IRQ_SHIFT 1 +#define RO_SENINF_MUX_FSM_ERR_IRQ_MASK (0x1 << 1) +#define RO_SENINF_MUX_HSIZE_ERR_IRQ_SHIFT 2 +#define RO_SENINF_MUX_HSIZE_ERR_IRQ_MASK (0x1 << 2) +#define RO_SENINF_MUX_VSIZE_ERR_IRQ_SHIFT 3 +#define RO_SENINF_MUX_VSIZE_ERR_IRQ_MASK (0x1 << 3) + +#define SENINF_MUX_IMG_SIZE 0x0020 +#define RG_SENINF_MUX_EXPECT_HSIZE_SHIFT 0 +#define RG_SENINF_MUX_EXPECT_HSIZE_MASK (0xffff << 0) +#define RG_SENINF_MUX_EXPECT_VSIZE_SHIFT 16 +#define RG_SENINF_MUX_EXPECT_VSIZE_MASK (0xffff << 16) + +#define SENINF_MUX_CROP_PIX_CTRL 0x0028 +#define RG_SENINF_MUX_CROP_START_8PIX_CNT_SHIFT 0 +#define RG_SENINF_MUX_CROP_START_8PIX_CNT_MASK (0xfff << 0) +#define RG_SENINF_MUX_CROP_END_8PIX_CNT_SHIFT 16 +#define RG_SENINF_MUX_CROP_END_8PIX_CNT_MASK (0xfff << 16) + +#define SENINF_MUX_SIZE 0x0030 +#define RO_SENINF_MUX_RCV_HSIZE_SHIFT 0 +#define RO_SENINF_MUX_RCV_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_MUX_RCV_VSIZE_SHIFT 16 +#define RO_SENINF_MUX_RCV_VSIZE_MASK (0xffff << 16) + +#define SENINF_MUX_ERR_SIZE 0x0034 +#define RO_SENINF_MUX_RCV_ERR_HSIZE_SHIFT 0 +#define RO_SENINF_MUX_RCV_ERR_HSIZE_MASK (0xffff << 0) +#define RO_SENINF_MUX_RCV_ERR_VSIZE_SHIFT 16 +#define RO_SENINF_MUX_RCV_ERR_VSIZE_MASK (0xffff << 16) + +#define SENINF_MUX_FIFO_STATUS 0x0040 +#define RO_SENINF_MUX_FIFO_WA_SHIFT 0 +#define RO_SENINF_MUX_FIFO_WA_MASK (0x1ff << 0) +#define RO_SENINF_MUX_FIFO_WCS_SHIFT 12 +#define RO_SENINF_MUX_FIFO_WCS_MASK (0x1 << 12) +#define RO_SENINF_MUX_FIFO_RA_SHIFT 16 +#define RO_SENINF_MUX_FIFO_RA_MASK (0x1ff << 16) +#define RO_SENINF_MUX_FIFO_RCS_SHIFT 28 +#define RO_SENINF_MUX_FIFO_RCS_MASK (0x1 << 28) + +#define SENINF_MUX_DBG_CTRL 0x0080 +#define RG_SENINF_MUX_DBG_EN_SHIFT 0 +#define RG_SENINF_MUX_DBG_EN_MASK (0x1 << 0) +#define RG_SENINF_MUX_DBG_SEL_SHIFT 8 +#define RG_SENINF_MUX_DBG_SEL_MASK (0xff << 8) + +#define SENINF_MUX_DBG_OUT 0x0088 +#define RO_SENINF_MUX_DBG_OUT_SHIFT 0 +#define RO_SENINF_MUX_DBG_OUT_MASK (0xffffffff << 0) + +#define SENINF_MUX_CAM_MON 0x00a0 +#define RO_SENINF_MUX_CAM_MON_0_SHIFT 0 +#define RO_SENINF_MUX_CAM_MON_0_MASK (0xffff << 0) +#define RO_SENINF_MUX_CAM_MON_1_SHIFT 16 +#define RO_SENINF_MUX_CAM_MON_1_MASK (0xffff << 16) + +#define SENINF_MUX_PIX_CNT 0x00a4 +#define RO_SENINF_MUX_PIX_CNT_SHIFT 0 +#define RO_SENINF_MUX_PIX_CNT_MASK (0xffffffff << 0) + +#define SENINF_MUX_FRAME_SIZE_MON_CTRL 0x00a8 +#define RG_SENINF_MUX_FRAME_SIZE_MON_EN_SHIFT 0 +#define RG_SENINF_MUX_FRAME_SIZE_MON_EN_MASK (0x1 << 0) + +#define SENINF_MUX_FRAME_SIZE_MON_H_VALID 0x00b0 +#define RO_SENINF_MUX_FRAME_H_VALID_SHIFT 0 +#define RO_SENINF_MUX_FRAME_H_VALID_MASK (0xffffffff << 0) + +#define SENINF_MUX_FRAME_SIZE_MON_H_BLANK 0x00b4 +#define RO_SENINF_MUX_FRAME_H_BLANK_SHIFT 0 +#define RO_SENINF_MUX_FRAME_H_BLANK_MASK (0xffffffff << 0) + +#define SENINF_MUX_FRAME_SIZE_MON_V_VALID 0x00b8 +#define RO_SENINF_MUX_FRAME_V_VALID_SHIFT 0 +#define RO_SENINF_MUX_FRAME_V_VALID_MASK (0xffffffff << 0) + +#define SENINF_MUX_FRAME_SIZE_MON_V_BLANK 0x00bc +#define RO_SENINF_MUX_FRAME_V_BLANK_SHIFT 0 +#define RO_SENINF_MUX_FRAME_V_BLANK_MASK (0xffffffff << 0) + +#define SENINF_MUX_SPARE 0x00f0 +#define RG_SENINF_MUX_SPARE_0_SHIFT 0 +#define RG_SENINF_MUX_SPARE_0_MASK (0xff << 0) +#define RG_SENINF_MUX_SPARE_1_SHIFT 16 +#define RG_SENINF_MUX_SPARE_1_MASK (0xff << 16) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h new file mode 100644 index 000000000000..4d021906ba07 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-seninf1.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF1_H__ +#define __SENINF1_H__ + +#define SENINF_CTRL 0x0000 +#define SENINF_EN_SHIFT 0 +#define SENINF_EN_MASK (0x1 << 0) + +#define SENINF_DBG 0x0004 +#define RG_SENINF_DBG_SEL_SHIFT 0 +#define RG_SENINF_DBG_SEL_MASK (0xf << 0) + +#define SENINF_CSI2_CTRL 0x0010 +#define RG_SENINF_CSI2_EN_SHIFT 0 +#define RG_SENINF_CSI2_EN_MASK (0x1 << 0) +#define SENINF_CSI2_SW_RST_SHIFT 4 +#define SENINF_CSI2_SW_RST_MASK (0x1 << 4) + +#define SENINF_TESTMDL_CTRL 0x0020 +#define RG_SENINF_TESTMDL_EN_SHIFT 0 +#define RG_SENINF_TESTMDL_EN_MASK (0x1 << 0) +#define SENINF_TESTMDL_SW_RST_SHIFT 4 +#define SENINF_TESTMDL_SW_RST_MASK (0x1 << 4) + +#define SENINF_TG_CTRL 0x0030 +#define SENINF_TG_SW_RST_SHIFT 4 +#define SENINF_TG_SW_RST_MASK (0x1 << 4) + +#define SENINF_SCAM_CTRL 0x0040 +#define RG_SENINF_SCAM_EN_SHIFT 0 +#define RG_SENINF_SCAM_EN_MASK (0x1 << 0) +#define SENINF_SCAM_SW_RST_SHIFT 4 +#define SENINF_SCAM_SW_RST_MASK (0x1 << 4) + +#define SENINF_PCAM_CTRL 0x0050 +#define RG_SENINF_PCAM_DATA_SEL_SHIFT 0 +#define RG_SENINF_PCAM_DATA_SEL_MASK (0x7 << 0) + +#define SENINF_CCIR_CTRL 0x0060 +#define SENINF_CCIR_SW_RST_SHIFT 4 +#define SENINF_CCIR_SW_RST_MASK (0x1 << 4) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h new file mode 100644 index 000000000000..3bd0d4a5b42e --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-tg1.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF_TG1_H__ +#define __SENINF_TG1_H__ + +#define TM_CTL 0x0008 +#define TM_EN_SHIFT 0 +#define TM_EN_MASK (0x1 << 0) +#define TM_RST_SHIFT 1 +#define TM_RST_MASK (0x1 << 1) +#define TM_FMT_SHIFT 2 +#define TM_FMT_MASK (0x1 << 2) +#define TM_BIN_IMG_SWITCH_EN_SHIFT 3 +#define TM_BIN_IMG_SWITCH_EN_MASK (0x1 << 3) +#define TM_PAT_SHIFT 4 +#define TM_PAT_MASK (0x1f << 4) + +#define TM_SIZE 0x000c +#define TM_PXL_SHIFT 0 +#define TM_PXL_MASK (0xffff << 0) +#define TM_LINE_SHIFT 16 +#define TM_LINE_MASK (0xffff << 16) + +#define TM_CLK 0x0010 +#define TM_CLK_CNT_SHIFT 0 +#define TM_CLK_CNT_MASK (0xff << 0) +#define TM_CLRBAR_OFT_SHIFT 8 +#define TM_CLRBAR_OFT_MASK (0x1fff << 8) +#define TM_CLRBAR_IDX_SHIFT 28 +#define TM_CLRBAR_IDX_MASK (0x7 << 28) + +#define TM_DUM 0x0018 +#define TM_DUMMYPXL_SHIFT 0 +#define TM_DUMMYPXL_MASK (0xffff << 0) +#define TM_VSYNC_SHIFT 16 +#define TM_VSYNC_MASK (0xffff << 16) + +#define TM_RAND_SEED 0x001c +#define TM_SEED_SHIFT 0 +#define TM_SEED_MASK (0xffffffff << 0) + +#define TM_RAND_CTL 0x0020 +#define TM_DIFF_FRM_SHIFT 0 +#define TM_DIFF_FRM_MASK (0x1 << 0) + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h new file mode 100644 index 000000000000..eeb7e06a20e3 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_csi_phy_2_0/mtk_cam-seninf-top-ctrl.h @@ -0,0 +1,99 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __SENINF_TOP_H__ +#define __SENINF_TOP_H__ + +#define SENINF_TOP_CTRL 0x0000 +#define SENINF_TOP_SW_RST_SHIFT 0 +#define SENINF_TOP_SW_RST_MASK (0x1 << 0) +#define SENINF_TOP_N3D_SW_RST_SHIFT 4 +#define SENINF_TOP_N3D_SW_RST_MASK (0x1 << 4) +#define RG_SENINF1_PCAM_PCLK_SEL_SHIFT 8 +#define RG_SENINF1_PCAM_PCLK_SEL_MASK (0x1 << 8) +#define RG_SENINF2_PCAM_PCLK_SEL_SHIFT 9 +#define RG_SENINF2_PCAM_PCLK_SEL_MASK (0x1 << 9) +#define RG_SENINF1_PCAM_PCLK_EN_SHIFT 12 +#define RG_SENINF1_PCAM_PCLK_EN_MASK (0x1 << 12) +#define RG_SENINF2_PCAM_PCLK_EN_SHIFT 13 +#define RG_SENINF2_PCAM_PCLK_EN_MASK (0x1 << 13) +#define RG_SLICE_FIFO_FULL_OPT_SHIFT 16 +#define RG_SLICE_FIFO_FULL_OPT_MASK (0x1 << 16) + +#define SENINF_TOP_MUX_CTRL_0 0x0010 +#define RG_SENINF_MUX1_SRC_SEL_SHIFT 0 +#define RG_SENINF_MUX1_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_MUX2_SRC_SEL_SHIFT 8 +#define RG_SENINF_MUX2_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_MUX3_SRC_SEL_SHIFT 16 +#define RG_SENINF_MUX3_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_MUX4_SRC_SEL_SHIFT 24 +#define RG_SENINF_MUX4_SRC_SEL_MASK (0xf << 24) + +#define SENINF_TOP_MUX_CTRL_1 0x0014 +#define RG_SENINF_MUX5_SRC_SEL_SHIFT 0 +#define RG_SENINF_MUX5_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_MUX6_SRC_SEL_SHIFT 8 +#define RG_SENINF_MUX6_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_MUX7_SRC_SEL_SHIFT 16 +#define RG_SENINF_MUX7_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_MUX8_SRC_SEL_SHIFT 24 +#define RG_SENINF_MUX8_SRC_SEL_MASK (0xf << 24) + +#define SENINF_TOP_MUX_CTRL_2 0x0018 +#define RG_SENINF_MUX9_SRC_SEL_SHIFT 0 +#define RG_SENINF_MUX9_SRC_SEL_MASK (0xf << 0) +#define RG_SENINF_MUX10_SRC_SEL_SHIFT 8 +#define RG_SENINF_MUX10_SRC_SEL_MASK (0xf << 8) +#define RG_SENINF_MUX11_SRC_SEL_SHIFT 16 +#define RG_SENINF_MUX11_SRC_SEL_MASK (0xf << 16) +#define RG_SENINF_MUX12_SRC_SEL_SHIFT 24 +#define RG_SENINF_MUX12_SRC_SEL_MASK (0xf << 24) + +#define SENINF_TOP_MUX_CTRL_3 0x001c +#define RG_SENINF_MUX13_SRC_SEL_SHIFT 0 +#define RG_SENINF_MUX13_SRC_SEL_MASK (0xf << 0) + +#define SENINF_TOP_PHY_CTRL_CSI0 0x0060 +#define PHY_SENINF_MUX0_DPHY_EN_SHIFT 0 +#define PHY_SENINF_MUX0_DPHY_EN_MASK (0x1 << 0) +#define PHY_SENINF_MUX0_CPHY_EN_SHIFT 1 +#define PHY_SENINF_MUX0_CPHY_EN_MASK (0x1 << 1) +#define RG_PHY_SENINF_MUX0_CPHY_MODE_SHIFT 8 +#define RG_PHY_SENINF_MUX0_CPHY_MODE_MASK (0x3 << 8) + +#define SENINF_TOP_PHY_CTRL_CSI1 0x0064 +#define PHY_SENINF_MUX1_DPHY_EN_SHIFT 0 +#define PHY_SENINF_MUX1_DPHY_EN_MASK (0x1 << 0) +#define PHY_SENINF_MUX1_CPHY_EN_SHIFT 1 +#define PHY_SENINF_MUX1_CPHY_EN_MASK (0x1 << 1) +#define RG_PHY_SENINF_MUX1_CPHY_MODE_SHIFT 8 +#define RG_PHY_SENINF_MUX1_CPHY_MODE_MASK (0x3 << 8) + +#define SENINF_TOP_PHY_CTRL_CSI2 0x0068 +#define PHY_SENINF_MUX2_DPHY_EN_SHIFT 0 +#define PHY_SENINF_MUX2_DPHY_EN_MASK (0x1 << 0) +#define PHY_SENINF_MUX2_CPHY_EN_SHIFT 1 +#define PHY_SENINF_MUX2_CPHY_EN_MASK (0x1 << 1) +#define RG_PHY_SENINF_MUX2_CPHY_MODE_SHIFT 8 +#define RG_PHY_SENINF_MUX2_CPHY_MODE_MASK (0x3 << 8) + +#define SENINF_TOP_PHY_CTRL_CSI3 0x006c +#define PHY_SENINF_MUX3_DPHY_EN_SHIFT 0 +#define PHY_SENINF_MUX3_DPHY_EN_MASK (0x1 << 0) +#define PHY_SENINF_MUX3_CPHY_EN_SHIFT 1 +#define PHY_SENINF_MUX3_CPHY_EN_MASK (0x1 << 1) +#define RG_PHY_SENINF_MUX3_CPHY_MODE_SHIFT 8 +#define RG_PHY_SENINF_MUX3_CPHY_MODE_MASK (0x3 << 8) + +#define SENINF_TOP_PHY_CTRL_CSI4 0x0070 +#define PHY_SENINF_MUX4_DPHY_EN_SHIFT 0 +#define PHY_SENINF_MUX4_DPHY_EN_MASK (0x1 << 0) +#define PHY_SENINF_MUX4_CPHY_EN_SHIFT 1 +#define PHY_SENINF_MUX4_CPHY_EN_MASK (0x1 << 1) +#define RG_PHY_SENINF_MUX4_CPHY_MODE_SHIFT 8 +#define RG_PHY_SENINF_MUX4_CPHY_MODE_MASK (0x3 << 8) + +#endif 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: 13828181 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 62D7DCF0453 for ; Wed, 9 Oct 2024 11:20:21 +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=guZquk3/nA27S5LLhoh5k/N/6m v4CVwcrpp9GHrro2f75ZWtUPpoEytgy9W3pBakO+kkSmiPAWc19/RicV1sX1jeii+YkIVnBjQkwsk 5v1WdX1XGLVAlq6WLQRxiUn9fylWf54iWI6r7atN+lLzDdXsNPnpS95tXY7me5yGPN1qk15NevNlO X+hl8L/KhfI4UlaLsco7nEpNFOhqC4WLYQI+qizdqEhC6GoJYD5GOw6zrwdnKkSrypp74eALxnd1P +vqpr27K8mACDuqCwZQHBvAPioOLzTFa1ZTpO1W6QHgcpVZH7QjbF8t/jnVxXx4xQks4Z2NU/2XDa mK8/eoyw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUjs-000000091ym-1Dlh; Wed, 09 Oct 2024 11:20:20 +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-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=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:45 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: 13828185 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 3BBB5CF0458 for ; Wed, 9 Oct 2024 11:21:45 +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=ue8XDJwDfmMjuG2089nzMq4aQHQbiXCtmqGQ1mS+Lv8=; b=CRv1SIkfnjWOmd8t8QU/omhI6j WfgvA0/kCl+qwkKMSIaUF62yPAGyfvvKfqkjbKnOIx3uP84lb13Hp4s7h27B4DCOa1Wl8cyzDIOy/ 5MMbuuCUwPGtvb53v+pI7/8AldO/ospsxGCNovN34Df7F9+8Cg8CLlgsGD5SoPN3EPFQ8A1GSlPeR Gh8ZFkeIeTfNT5NXlT3VnooJtLKnxERhXHZplBK0v3wejqPYWjeJP8bKkKviChAOteudTFr9w/GQk 9gsQ2arLZDocZGlEvrbBW+R1LeZSA8Nt7kxEFLdiiqxAmHdjbv/wUT9FmE4+cPNVZj3qbb1QEzKWl AyUL/r0w==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUlD-000000092Nb-3TUn; Wed, 09 Oct 2024 11:21:43 +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 1syUgL-000000091Nv-0cqI; Wed, 09 Oct 2024 11:16:41 +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=ue8XDJwDfmMjuG2089nzMq4aQHQbiXCtmqGQ1mS+Lv8=; b=qbYS0yuqRVfUTBuc07gPPBMCKq feB5H1FFLhAGGxDTgImX7MuzZfIxbzvrU3YQ1d1ddoyRUdcvckJGw/Q3nFewGaYSTGS2mTIxNHB/D 3trxtsudCIZH4E7F/cSwCrLo97D79eat7qaFNXtEq+pa5qw7vzXlx5BYpCcHet592URfM8SCsfLdj 0Hn1hURLVpjlMBQ0aMB8rLY9oBAmZ9PYdoNhtHZt9yzHc4qPooEe+0D/Gav8YurAoVXi8ogNOSKwq mI+9TwLV0nYqBUbEGw/I4Qe8OmPY42QeN40GMUUg13LgpC6uzcUp/z3LMKdEdpbCOAzaOx+UtKYPC uuM6guWQ==; Received: from mailgw02.mediatek.com ([216.200.240.185]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgF-00000004v7n-2gJd; Wed, 09 Oct 2024 11:16:39 +0000 X-UUID: e35a2a64862f11efba0aef63c0775dbf-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=ue8XDJwDfmMjuG2089nzMq4aQHQbiXCtmqGQ1mS+Lv8=; b=PbyDjTqMuAeiLywROXsh6T3k0Ds+3H7Cm63mOgiNwNAIVRh+WanEQ0FIWL7Sa6Wzv7VIKFnR7jz+mkyaeYy8A8stLU0MQA47F83jsC38729EdtukKZmmMldbP7oBYBdev69Mpip1rnaALFqUsKTGC2m6IF7/R8MzK2jaQJ/E900=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:388f2254-4356-44e7-9cf1-e247ec2b4987,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:348a0041-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|NGT X-CID-BAS: 2,OSH|NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e35a2a64862f11efba0aef63c0775dbf-20241009 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw02.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 444245477; Wed, 09 Oct 2024 04:16:10 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by mtkmbs10n2.mediatek.inc (172.21.101.183) 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:07 +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: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 04/10] media: platform: mediatek: add isp_7x cam-raw unit Date: Wed, 9 Oct 2024 19:15:45 +0800 Message-ID: <20241009111551.27052-5-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--15.012200-8.000000 X-TMASE-MatchedRID: 1aMQdI+MeNA83pgwlPkMJspQKjU7fBXVkbYh2bSF9Gc2/UwdvFG5Ih8+ XHETeZCzpPfp/tMmq7gXy25Jwx1ee6lRmTVyFuWlA9lly13c/gEraL2mh8ZVK7uqk4cq52pzBpN qUzwLvvfC9TF0oEZxDPwSlgkyMvou28kC8Kr7Ask0JY9d6s3vaV67veYUroY0CqIJhrrDy2/5r/ N0c4ndaRTXlwIdja91D/M6mxTF6eBDeuA2fujoFUhwlOfYeSqxpfVcx39Kq+7JYIv7y0tu9qIDs C/90PKdFq2u6QNXsALnTzjd3LX3p00EdmgNIMCz4bl1FkKDELc7r2Gtb9iBYS8zQZ2rR/Op8bf3 35SL+13V0LJ64h8KJ0gY1PPRRF1Dbai8Vf7R1/2GuzokAQvW7jfwU1OWX2USYe1mzp7dkwd3AzN R49E9zHs1twvT4bomFCOLNe0Jd9Mz2nUKzTJ7O0dAWPMBu8kQIaLR+2xKRDIifM7JMNHW64Jj0L b9Fi4gLLFAZa5Y3vBWTSOlTfbnwNllERdS6V4uLIRqQbCuh+6E6lq+K7jth/zaSz3Z/4aayU7Xg Ts6W4L08oBdFnGk1pUmPFGykXeX4TagRwcBQLNtqNUBzYMqpu8lj2kHOCDUv8D7QPW2jo/j0EH9 v7XWEHGdZVe1+//wXFj1pvfElLE+Os0u1LkxvULEoH0ynuZVfV3o8v8dH+qxVl52+frW/74Sh0C 0yopsbkYOoCs8hbi8RK4gKVk64Q+ypzJ6Fr8f7/U7JmMpiiH54F/2i/DwjU8vg1FXaj1oLOxC6s uyQ8bYnodwiC5M0gB5duhc76YnrGqzbR7VPHmeAiCmPx4NwGmRqNBHmBveg6X7YSXnSlqZv9WvR V/RbgtuKBGekqUpOlxBO2IcOBaUTGVAhB5EbQ== X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--15.012200-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 575EF3F5F0FB6DD011CE9D49D932254230CE95611793BD4C531DC54249DD67322000:8 X-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Introduces the ISP pipeline driver for the MediaTek ISP raw and yuv modules. Key functionalities include data processing, V4L2 integration, resource management, debug support, and various control operations. Additionally, IRQ handling, platform device management, and MediaTek ISP DMA format support are also included. Signed-off-by: Shu-hsiang Yang --- .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.c | 5359 +++++++++++++++++ .../mediatek/isp/isp_7x/camsys/mtk_cam-raw.h | 325 + .../isp/isp_7x/camsys/mtk_cam-raw_debug.c | 403 ++ .../isp/isp_7x/camsys/mtk_cam-raw_debug.h | 39 + .../isp_7x/camsys/mtk_camera-v4l2-controls.h | 65 + 5 files changed, 6191 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c new file mode 100644 index 000000000000..c025f53c952d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.c @@ -0,0 +1,5359 @@ +// 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 "mtk_cam.h" +#include "mtk_cam-feature.h" +#include "mtk_cam-raw.h" + +#include "mtk_cam-regs-mt8188.h" + +#include "mtk_cam-video.h" +#include "mtk_cam-seninf-if.h" +#include "mtk_camera-v4l2-controls.h" + +#include "mtk_cam-dmadbg.h" +#include "mtk_cam-raw_debug.h" + +static unsigned int debug_raw; +module_param(debug_raw, uint, 0644); +MODULE_PARM_DESC(debug_raw, "activates debug info"); + +static int debug_raw_num = -1; +module_param(debug_raw_num, int, 0644); +MODULE_PARM_DESC(debug_raw_num, "debug: num of used raw devices"); + +static int debug_pixel_mode = -1; +module_param(debug_pixel_mode, int, 0644); +MODULE_PARM_DESC(debug_pixel_mode, "debug: pixel mode"); + +static int debug_clk_idx = -1; +module_param(debug_clk_idx, int, 0644); +MODULE_PARM_DESC(debug_clk_idx, "debug: clk idx"); + +static int debug_dump_fbc; +module_param(debug_dump_fbc, int, 0644); +MODULE_PARM_DESC(debug_dump_fbc, "debug: dump fbc"); + +#define MTK_RAW_STOP_HW_TIMEOUT (33) + +#define MTK_CAMSYS_RES_IDXMASK 0xF0 +#define MTK_CAMSYS_RES_BIN_TAG 0x10 +#define MTK_CAMSYS_RES_FRZ_TAG 0x20 +#define MTK_CAMSYS_RES_HWN_TAG 0x30 +#define MTK_CAMSYS_RES_CLK_TAG 0x40 + +#define MTK_CAMSYS_RES_PLAN_NUM 10 +#define FRZ_PXLMODE_THRES 71 +#define MHz 1000000 + +/* ISP7_1 */ +#define TGO_MAX_PXLMODE 1 +#define MTK_CAMSYS_PROC_DEFAULT_PIXELMODE 1 +#define sizeof_u32(__struct__) ((sizeof(__struct__) + sizeof(u32) - 1) / \ + sizeof(u32)) + +enum MTK_CAMSYS_RES_STEP { + E_RES_BASIC, + E_RES_BIN_S = MTK_CAMSYS_RES_BIN_TAG, + E_RES_BIN0 = E_RES_BIN_S, + E_RES_BIN1, + E_RES_BIN_E, + E_RES_FRZ_S = MTK_CAMSYS_RES_FRZ_TAG, + E_RES_FRZ0 = E_RES_FRZ_S, + E_RES_FRZ1, + E_RES_FRZ_E, + E_RES_HWN_S = MTK_CAMSYS_RES_HWN_TAG, + E_RES_HWN0 = E_RES_HWN_S, + E_RES_HWN1, + E_RES_HWN2, + E_RES_HWN_E, + E_RES_CLK_S = MTK_CAMSYS_RES_CLK_TAG, + E_RES_CLK0 = E_RES_CLK_S, + E_RES_CLK1, + E_RES_CLK2, + E_RES_CLK3, + E_RES_CLK_E, +}; + +enum MTK_CAMSYS_MAXLB_CHECK_RESULT { + LB_CHECK_OK = 0, + LB_CHECK_CBN, + LB_CHECK_QBN, + LB_CHECK_BIN, + LB_CHECK_FRZ, + LB_CHECK_TWIN, + LB_CHECK_RAW, +}; + +#define CAM_RAW_PROCESS_MAX_LINE_BUFFER (6632) +#define CAM_RAW_FRZ_MAX_LINE_BUFFER (6632) +#define CAM_RAW_BIN_MAX_LINE_BUFFER (12000) +#define CAM_RAW_QBND_MAX_LINE_BUFFER (16000) +#define CAM_RAW_CBN_MAX_LINE_BUFFER (18472) +#define CAM_TWIN_PROCESS_MAX_LINE_BUFFER (12400) + +struct cam_resource_plan { + int cam_resource[MTK_CAMSYS_RES_STEP_NUM]; +}; + +enum resource_strategy_id { + RESOURCE_STRATEGY_QPR = 0, + RESOURCE_STRATEGY_PQR, + RESOURCE_STRATEGY_RPQ, + RESOURCE_STRATEGY_QRP, + RESOURCE_STRATEGY_NUMBER +}; + +static const struct cam_resource_plan raw_resource_strategy_plan[] = { + [RESOURCE_STRATEGY_QPR] = { + .cam_resource = { + E_RES_BASIC, E_RES_HWN1, E_RES_CLK1, E_RES_CLK2, + E_RES_CLK3, E_RES_FRZ1, E_RES_BIN1, E_RES_HWN2} }, + [RESOURCE_STRATEGY_PQR] = { + .cam_resource = { + E_RES_BASIC, E_RES_HWN1, E_RES_HWN2, E_RES_FRZ1, + E_RES_BIN1, E_RES_CLK1, E_RES_CLK2, E_RES_CLK3} }, + [RESOURCE_STRATEGY_RPQ] = { + .cam_resource = { + E_RES_BASIC, E_RES_FRZ1, E_RES_BIN1, E_RES_CLK1, + E_RES_CLK2, E_RES_CLK3, E_RES_HWN1, E_RES_HWN2} }, + [RESOURCE_STRATEGY_QRP] = { + .cam_resource = { + E_RES_BASIC, E_RES_CLK1, E_RES_CLK2, E_RES_CLK3, + E_RES_HWN1, E_RES_HWN2, E_RES_FRZ1, E_RES_BIN1} }, +}; + +static const struct v4l2_mbus_framefmt mfmt_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 bool mtk_cam_raw_resource_calc(struct mtk_cam_device *cam, + struct mtk_cam_resource_config *res, + s64 pixel_rate, int res_plan, int in_w, + int in_h, int *out_w, int *out_h); + +static int mtk_cam_raw_res_copy_fmt_from_user(struct mtk_raw_pipeline *pipeline, + struct mtk_cam_resource *res_user, + struct v4l2_mbus_framefmt *dest) +{ + long bytes; + struct device *dev = pipeline->raw->devs[pipeline->id]; + + if (!res_user->sink_fmt) { + dev_err(dev, + "%s:pipe(%d): sink_fmt can't be NULL for res ctrl\n", + __func__, pipeline->id); + + return -EINVAL; + } + + bytes = copy_from_user(dest, (void __user *)res_user->sink_fmt, + sizeof(*dest)); + if (bytes) { + dev_err(dev, + "%s:pipe(%d): copy_from_user on sink_fmt failed (%ld)\n", + __func__, pipeline->id, bytes); + return -EINVAL; + } + + return 0; +} + +static int mtk_cam_raw_res_copy_fmt_to_user(struct mtk_raw_pipeline *pipeline, + struct mtk_cam_resource *res_user, + struct v4l2_mbus_framefmt *src) +{ + long bytes; + struct device *dev = pipeline->raw->devs[pipeline->id]; + + /* return the fmt to the users */ + bytes = copy_to_user((void __user *)res_user->sink_fmt, src, sizeof(*src)); + if (bytes) { + dev_err(dev, + "%s:pipe(%d): copy_to_user on sink_fmt failed (%ld)\n", + __func__, pipeline->id, bytes); + + return -EINVAL; + } + + return 0; +} + +static int mtk_cam_raw_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_cam_resource *user_res; + struct mtk_raw_pipeline *pipeline; + struct device *dev; + int ret = 0; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + dev = pipeline->raw->devs[pipeline->id]; + + if (ctrl->id == V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC) { + user_res = (struct mtk_cam_resource *)ctrl->p_new.p; + user_res->sensor_res = pipeline->user_res.sensor_res; + user_res->raw_res = pipeline->user_res.raw_res; + if (user_res->sink_fmt) + ret = mtk_cam_raw_res_copy_fmt_to_user(pipeline, + user_res, + (struct v4l2_mbus_framefmt *) + pipeline->user_res.sink_fmt); + } else if (ctrl->id == V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE) { + ctrl->val = pipeline->sensor_mode_update; + dev_info(dev, + "%s:pipe(%d): V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: %d\n", + __func__, pipeline->id, pipeline->sensor_mode_update); + } else if (ctrl->id >= V4L2_CID_MTK_CAM_USED_ENGINE_TRY && + ctrl->id <= V4L2_CID_MTK_CAM_FRZ_TRY) { + /** + * Read the determined resource for the "try" format + * negotiation result + */ + mutex_lock(&pipeline->try_res_config.resource_lock); + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_USED_ENGINE_TRY: + ctrl->val = pipeline->try_res_config.raw_num_used; + break; + case V4L2_CID_MTK_CAM_BIN_TRY: + ctrl->val = pipeline->try_res_config.bin_enable; + break; + case V4L2_CID_MTK_CAM_FRZ_TRY: + ctrl->val = pipeline->try_res_config.frz_enable ? + pipeline->try_res_config.frz_ratio : 100; + break; + default: + dev_info(dev, + "%s:pipe(%d): unknown resource CID: %d\n", + __func__, pipeline->id, ctrl->id); + break; + } + mutex_unlock(&pipeline->try_res_config.resource_lock); + } else if (ctrl->id == V4L2_CID_MTK_CAM_SYNC_ID) { + mutex_lock(&pipeline->res_config.resource_lock); + *ctrl->p_new.p_s64 = pipeline->sync_id; + mutex_unlock(&pipeline->res_config.resource_lock); + } else { + /** + * Read the determined resource for the "set" format + * negotiations result + */ + mutex_lock(&pipeline->res_config.resource_lock); + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_USED_ENGINE: + ctrl->val = pipeline->res_config.raw_num_used; + break; + case V4L2_CID_MTK_CAM_BIN_LIMIT: + ctrl->val = pipeline->res_config.bin_limit; + break; + case V4L2_CID_MTK_CAM_BIN: + ctrl->val = pipeline->res_config.bin_enable; + break; + case V4L2_CID_MTK_CAM_FRZ: + ctrl->val = pipeline->res_config.frz_enable ? + pipeline->res_config.frz_ratio : 100; + break; + default: + dev_info(dev, + "%s:pipe(%d): unknown try resource CID: %d\n", + __func__, pipeline->id, ctrl->id); + break; + } + mutex_unlock(&pipeline->res_config.resource_lock); + } + + dev_dbg(dev, "%s:pipe(%d):id(%s) val(%d)\n", + __func__, pipeline->id, ctrl->name, ctrl->val); + return ret; +} + +static int mtk_cam_raw_res_store(struct mtk_raw_pipeline *pipeline, + struct mtk_cam_resource *res_user) +{ + struct device *dev = pipeline->raw->devs[pipeline->id]; + + dev_info(dev, + "%s:pipe(%d): from user: sensor:%d/%d/%lld/%lld/%d/%d, raw:%lld/%d/%d/%d/%d/%d/%d/%d/%lld\n", + __func__, pipeline->id, + res_user->sensor_res.hblank, res_user->sensor_res.vblank, + res_user->sensor_res.pixel_rate, + res_user->sensor_res.cust_pixel_rate, + res_user->sensor_res.interval.denominator, + res_user->sensor_res.interval.numerator, + res_user->raw_res.feature, res_user->raw_res.bin, + res_user->raw_res.path_sel, res_user->raw_res.raw_max, + res_user->raw_res.raw_min, res_user->raw_res.raw_used, + res_user->raw_res.strategy, res_user->raw_res.pixel_mode, + res_user->raw_res.throughput); + + /* check user value of sensor input parameters */ + if (!mtk_cam_feature_is_pure_m2m(res_user->raw_res.feature) && + (!res_user->sensor_res.pixel_rate || !res_user->sensor_res.hblank || + !res_user->sensor_res.vblank || + !res_user->sensor_res.interval.denominator || + !res_user->sensor_res.interval.numerator)) { + dev_info(dev, + "%s:pipe(%d): sensor info MUST be provided (TEST_PATTERN case)\n", + __func__, pipeline->id); + /*test pattern case resource default copy*/ + pipeline->res_config.raw_num_used = 1; + pipeline->res_config.bin_enable = 0; + pipeline->res_config.tgo_pxl_mode = 1; + pipeline->res_config.raw_path = 0; + pipeline->res_config.hwn_limit_min = 1; + pipeline->res_config.raw_feature = res_user->raw_res.feature; + pipeline->feature_pending = res_user->raw_res.feature; + pipeline->feature_active = res_user->raw_res.feature; + } + + /* check user value of raw input parameters */ + if (res_user->raw_res.feature == 0xFFFFFFFF) + res_user->raw_res.feature = 0; + + if (res_user->raw_res.bin == 0xFF) + res_user->raw_res.bin = 0; + + if (res_user->raw_res.strategy == 0xFFFF) + res_user->raw_res.strategy = RESOURCE_STRATEGY_QRP; + + if (res_user->raw_res.raw_max == 0xFF) + res_user->raw_res.raw_max = 2; + + if (res_user->raw_res.raw_min == 0xFF) + res_user->raw_res.raw_min = 1; + + if (res_user->raw_res.raw_min > 1) + res_user->raw_res.strategy = RESOURCE_STRATEGY_QPR; + + if (res_user->raw_res.path_sel == 0xFF) + res_user->raw_res.path_sel = 0; + + dev_info(dev, + "%s:pipe(%d): driver adjusted: raw:%lld/%d/%d/%d/%d/%d/%d/%d/%lld\n", + __func__, pipeline->id, + res_user->raw_res.feature, res_user->raw_res.bin, + res_user->raw_res.path_sel, res_user->raw_res.raw_max, + res_user->raw_res.raw_min, res_user->raw_res.raw_used, + res_user->raw_res.strategy, res_user->raw_res.pixel_mode, + res_user->raw_res.throughput); + + return 0; +} + +static s64 mtk_cam_calc_pure_m2m_pixelrate(s64 width, s64 height, + struct v4l2_fract *interval) +{ + /* process + r/wdma margin = (1 + 5%) x (1 + 10%) */ + #define PURE_M2M_PROCESS_MARGIN_N 11550 + #define PURE_M2M_PROCESS_MARGIN_D 10000 + u64 prate = 0; + int fps_n = interval->numerator; + int fps_d = interval->denominator; + + prate = width * height * fps_d * PURE_M2M_PROCESS_MARGIN_N; + do_div(prate, fps_n * PURE_M2M_PROCESS_MARGIN_D); + + pr_info("%s:width:%lld height:%lld interval:%d/%d prate:%llu\n", + __func__, width, height, fps_n, fps_d, prate); + return prate; +} + +static int mtk_cam_raw_try_res_ctrl(struct mtk_raw_pipeline *pipeline, + struct mtk_cam_resource *res_user, + struct mtk_cam_resource_config *res_cfg, + struct v4l2_mbus_framefmt *sink_fmt) +{ + s64 prate = 0; + int width, height; + struct device *dev = pipeline->raw->devs[pipeline->id]; + + res_cfg->bin_limit = res_user->raw_res.bin; /* 1: force bin on */ + res_cfg->frz_limit = 0; + res_cfg->hwn_limit_max = res_user->raw_res.raw_max; + res_cfg->hwn_limit_min = res_user->raw_res.raw_min; + res_cfg->hblank = res_user->sensor_res.hblank; + res_cfg->vblank = res_user->sensor_res.vblank; + res_cfg->sensor_pixel_rate = res_user->sensor_res.pixel_rate; + res_cfg->res_plan = res_user->raw_res.strategy; + res_cfg->raw_feature = res_user->raw_res.feature; + res_cfg->raw_path = res_user->raw_res.path_sel; + + if (res_user->sensor_res.cust_pixel_rate) + prate = res_user->sensor_res.cust_pixel_rate; + else if (mtk_cam_feature_is_pure_m2m(res_cfg->raw_feature)) + prate = mtk_cam_calc_pure_m2m_pixelrate(sink_fmt->width, + sink_fmt->height, + &res_cfg->interval); + else + prate = mtk_cam_seninf_calc_pixelrate(pipeline->raw->cam_dev, + sink_fmt->width, + sink_fmt->height, + res_user->sensor_res.hblank, + res_user->sensor_res.vblank, + res_user->sensor_res.interval.denominator, + res_user->sensor_res.interval.numerator, + res_user->sensor_res.pixel_rate); + + mtk_cam_raw_resource_calc(dev_get_drvdata(pipeline->raw->cam_dev), + res_cfg, prate, res_cfg->res_plan, + sink_fmt->width, sink_fmt->height, + &width, &height); + + if (res_user->raw_res.bin && !res_cfg->bin_enable) { + dev_err(dev, + "%s:pipe(%d): res calc failed on fource bin: user(%d)/bin_enable(%d)\n", + __func__, pipeline->id, res_user->raw_res.bin, + res_cfg->bin_enable); + return -EINVAL; + } + + if (res_cfg->raw_num_used > res_user->raw_res.raw_max || + res_cfg->raw_num_used < res_user->raw_res.raw_min) { + dev_err(dev, + "%s:pipe(%d): res calc failed on raw used: user(%d/%d)/raw_num_used(%d)\n", + __func__, pipeline->id, res_user->raw_res.raw_max, + res_user->raw_res.raw_min, res_cfg->raw_num_used); + } + + res_user->raw_res.pixel_mode = res_cfg->tgo_pxl_mode; + res_user->raw_res.raw_used = res_cfg->raw_num_used; + if (res_cfg->bin_limit == BIN_AUTO) + res_user->raw_res.bin = res_cfg->bin_enable; + else + res_user->raw_res.bin = res_cfg->bin_limit; + + dev_info(dev, + "%s:pipe(%d): res calc result: raw_used(%d)/bin(%d)/pixelmode(%d)/strategy(%d)\n", + __func__, pipeline->id, res_user->raw_res.raw_used, + res_user->raw_res.bin, res_user->raw_res.pixel_mode, + res_user->raw_res.strategy); + + /** + * Other output not reveal to user: + * res_cfg->res_strategy[MTK_CAMSYS_RES_STEP_NUM]; + * res_cfg->clk_target; + * res_cfg->frz_enable; + * res_cfg->frz_ratio; + * res_cfg->tgo_pxl_mode; + */ + if (width != sink_fmt->width || height != sink_fmt->height) { + dev_info(dev, + "%s:pipe(%d): size adjust info: raw: sink(%d,%d) res:(%d,%d)\n", + __func__, pipeline->id, sink_fmt->width, + sink_fmt->height, width, height); + } + + return 0; +} + +static int mtk_cam_raw_set_res_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_raw_pipeline *pipeline; + struct mtk_cam_resource *res_user; + struct v4l2_mbus_framefmt sink_fmt; + struct device *dev; + int ret = 0; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + dev = pipeline->raw->devs[pipeline->id]; + res_user = (struct mtk_cam_resource *)ctrl->p_new.p; + + ret = mtk_cam_raw_res_store(pipeline, res_user); + pipeline->user_res = *res_user; + if (media_entity_is_streaming(&pipeline->subdev.entity)) { + /* If the pipeline is streaming, pending the change */ + dev_dbg(dev, + "%s:pipe(%d): pending res calc has not been supported except bin\n", + __func__, pipeline->id); + return ret; + } + + dev_dbg(dev, + "%s:pipe(%d):streaming(%d), feature_pending(0x%llx), raw_res.feature(0x%llx), feature_active(0x%llx)\n", + __func__, pipeline->id, + media_entity_is_streaming(&pipeline->subdev.entity), + pipeline->feature_pending, pipeline->user_res.raw_res.feature, + pipeline->feature_active); + + ret = mtk_cam_raw_res_copy_fmt_from_user(pipeline, res_user, &sink_fmt); + if (ret) + return ret; + + pipeline->res_config.sink_fmt = sink_fmt; + ret = mtk_cam_raw_try_res_ctrl(pipeline, res_user, + &pipeline->res_config, &sink_fmt); + + if (ret) + return -EINVAL; + + return ret; +} + +static int mtk_raw_set_res_ctrl(struct device *dev, struct v4l2_ctrl *ctrl, + struct mtk_cam_resource_config *res_cfg, + int pipe_id) +{ + int ret = 0; + struct mtk_raw_pipeline *pipeline; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + + if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64) + dev_dbg(dev, "%s:pipe(%d):(name:%s, val:%lld)\n", __func__, + pipe_id, ctrl->name, *ctrl->p_new.p_s64); + else + dev_dbg(dev, "%s:pipe(%d):(name:%s, val:%d)\n", __func__, + pipe_id, ctrl->name, ctrl->val); + + mutex_lock(&res_cfg->resource_lock); + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT: + res_cfg->hwn_limit_max = ctrl->val; + break; + case V4L2_CID_MTK_CAM_BIN_LIMIT: + res_cfg->bin_limit = ctrl->val; + break; + case V4L2_CID_MTK_CAM_FRZ_LIMIT: + res_cfg->frz_limit = ctrl->val; + break; + case V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY: + res_cfg->res_plan = ctrl->val; + break; + case V4L2_CID_MTK_CAM_RAW_PATH_SELECT: + res_cfg->raw_path = ctrl->val; + break; + case V4L2_CID_HBLANK: + res_cfg->hblank = ctrl->val; + break; + case V4L2_CID_VBLANK: + res_cfg->vblank = ctrl->val; + break; + case V4L2_CID_MTK_CAM_PIXEL_RATE: + res_cfg->sensor_pixel_rate = *ctrl->p_new.p_s64; + break; + case V4L2_CID_MTK_CAM_SYNC_ID: + pipeline->sync_id = *ctrl->p_new.p_s64; + break; + default: + dev_info(dev, + "%s:pipe(%d):ctrl(id:0x%x,val:%d) not handled\n", + __func__, pipe_id, ctrl->id, ctrl->val); + ret = -EINVAL; + break; + } + mutex_unlock(&res_cfg->resource_lock); + + return ret; +} + +static int mtk_cam_raw_try_ctrl(struct v4l2_ctrl *ctrl) +{ + struct device *dev; + struct mtk_raw_pipeline *pipeline; + struct mtk_cam_resource *res_user; + struct mtk_cam_resource_config res_cfg = { + .interval = { + .numerator = 1, + .denominator = 30 + }, + }; + int ret = 0; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + dev = pipeline->raw->devs[pipeline->id]; + + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC: + res_user = (struct mtk_cam_resource *)ctrl->p_new.p; + ret = mtk_cam_raw_res_store(pipeline, res_user); + if (ret) + break; + + ret = mtk_cam_raw_res_copy_fmt_from_user(pipeline, res_user, + &res_cfg.sink_fmt); + if (ret) { + ret = 0; + /* only corret the user's input, it may be request-based try and set fmt */ + dev_dbg(dev, + "%s:pipe(%d): no sink_fmt from user, not calc res\n", + __func__, pipeline->id); + break; + } + + dev_dbg(dev, "%s:pipe(%d): res ctrl start\n", + __func__, pipeline->id); + ret = mtk_cam_raw_try_res_ctrl(pipeline, res_user, &res_cfg, + &res_cfg.sink_fmt); + if (ret) + break; + + dev_dbg(dev, + "%s:pipe(%d):streaming(%d), feature_pending(0x%llx), feature_active(0x%llx)\n", + __func__, pipeline->id, + media_entity_is_streaming(&pipeline->subdev.entity), + pipeline->feature_pending, pipeline->feature_active); + + dev_dbg(dev, "%s:pipe(%d): res ctrl end\n", + __func__, pipeline->id); + break; + case V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: + dev_info(dev, + "%s:pipe(%d): skip V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: %d\n", + __func__, pipeline->id, ctrl->val); + ret = 0; /* no support */ + break; + /* skip control value checks */ + case V4L2_CID_MTK_CAM_FEATURE: + case V4L2_CID_MTK_CAM_CAMSYS_HW_MODE: + ret = 0; + break; + default: + ret = mtk_raw_set_res_ctrl(pipeline->raw->devs[pipeline->id], + ctrl, &pipeline->try_res_config, + pipeline->id); + break; + } + + return ret; +} + +static int mtk_cam_raw_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct device *dev; + struct mtk_raw_pipeline *pipeline; + int ret = 0; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + dev = pipeline->raw->devs[pipeline->id]; + + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC: + /** + * It also updates V4L2_CID_MTK_CAM_FEATURE and + * V4L2_CID_MTK_CAM_RAW_PATH_SELECT to device + */ + ret = mtk_cam_raw_set_res_ctrl(ctrl); + break; + case V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE: + /** + * sensor_mode_update should be reset by driver after the completion + * of resource updating (seamless switch) + */ + pipeline->sensor_mode_update = ctrl->val; + dev_info(dev, + "%s:pipe(%d):streaming(%d), sensor_mode_update(%d)\n", + __func__, pipeline->id, + media_entity_is_streaming(&pipeline->subdev.entity), + pipeline->sensor_mode_update); + break; + case V4L2_CID_MTK_CAM_FEATURE: + pipeline->feature_pending = *ctrl->p_new.p_s64; + dev_dbg(dev, + "%s:pipe(%d):streaming(%d), feature_pending(0x%llx), feature_active(0x%llx)\n", + __func__, pipeline->id, + media_entity_is_streaming(&pipeline->subdev.entity), + pipeline->feature_pending, pipeline->feature_active); + ret = 0; + break; + case V4L2_CID_MTK_CAM_CAMSYS_HW_MODE: + pipeline->hw_mode = *ctrl->p_new.p_s64; + dev_dbg(dev, + "%s:pipe(%d):streaming(%d), hw_mode(0x%llx)\n", + __func__, pipeline->id, + media_entity_is_streaming(&pipeline->subdev.entity), + pipeline->hw_mode); + + ret = 0; + break; + default: + ret = mtk_raw_set_res_ctrl(pipeline->raw->devs[pipeline->id], + ctrl, &pipeline->res_config, + pipeline->id); + break; + } + + return ret; +} + +static const struct v4l2_ctrl_ops cam_ctrl_ops = { + .g_volatile_ctrl = mtk_cam_raw_get_ctrl, + .s_ctrl = mtk_cam_raw_set_ctrl, + .try_ctrl = mtk_cam_raw_try_ctrl, +}; + +static int mtk_raw_pde_get_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_raw_pipeline *pipeline; + struct mtk_raw_pde_config *pde_cfg; + struct mtk_cam_pde_info *pde_info_p; + struct device *dev; + int ret = 0; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + pde_cfg = &pipeline->pde_config; + pde_info_p = ctrl->p_new.p; + dev = pipeline->raw->devs[pipeline->id]; + + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_PDE_INFO: + pde_info_p->pdo_max_size = pde_cfg->pde_info.pdo_max_size; + pde_info_p->pdi_max_size = pde_cfg->pde_info.pdi_max_size; + pde_info_p->pd_table_offset = pde_cfg->pde_info.pd_table_offset; + break; + default: + dev_info(dev, "%s(id:0x%x,val:%d) is not handled\n", + __func__, ctrl->id, ctrl->val); + ret = -EINVAL; + } + + return ret; +} + +static int mtk_raw_pde_set_ctrl(struct v4l2_ctrl *ctrl) +{ + struct mtk_raw_pipeline *pipeline; + struct mtk_raw_pde_config *pde_cfg; + struct mtk_cam_pde_info *pde_info_p; + struct device *dev; + int ret = 0; + struct mtk_cam_video_device *node; + struct mtk_cam_dev_node_desc *desc; + const struct v4l2_format *default_fmt; + + pipeline = mtk_cam_ctrl_handler_to_raw_pipeline(ctrl->handler); + pde_cfg = &pipeline->pde_config; + pde_info_p = ctrl->p_new.p; + dev = pipeline->raw->devs[pipeline->id]; + + node = &pipeline->vdev_nodes[MTK_RAW_META_IN - MTK_RAW_SINK_NUM]; + desc = &node->desc; + default_fmt = &desc->fmts[desc->default_fmt_idx].vfmt; + + switch (ctrl->id) { + case V4L2_CID_MTK_CAM_PDE_INFO: + if (!pde_info_p->pdo_max_size || !pde_info_p->pdi_max_size) { + dev_info(dev, + "%s:pdo_max_sz(%d)/pdi_max_sz(%d) cannot be 0\n", + __func__, pde_info_p->pdo_max_size, + pde_info_p->pdi_max_size); + ret = -EINVAL; + break; + } + + pde_cfg->pde_info.pdo_max_size = pde_info_p->pdo_max_size; + pde_cfg->pde_info.pdi_max_size = pde_info_p->pdi_max_size; + pde_cfg->pde_info.pd_table_offset = + default_fmt->fmt.meta.buffersize; + break; + default: + dev_info(dev, "%s(id:0x%x,val:%d) is not handled\n", + __func__, ctrl->id, ctrl->val); + ret = -EINVAL; + } + + return ret; +} + +static const struct v4l2_ctrl_ops cam_pde_ctrl_ops = { + .g_volatile_ctrl = mtk_raw_pde_get_ctrl, + .s_ctrl = mtk_raw_pde_set_ctrl, + .try_ctrl = mtk_raw_pde_set_ctrl, +}; + +static const struct v4l2_ctrl_config hwn_limit = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_USED_ENGINE_LIMIT, + .name = "Engine resource limitation", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 2, + .step = 1, + .def = 2, +}; + +static const struct v4l2_ctrl_config bin_limit = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_BIN_LIMIT, + .name = "Binning limitation", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xfff, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config frz_limit = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_FRZ_LIMIT, + .name = "Resizer limitation", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 70, + .max = 100, + .step = 1, + .def = 100, +}; + +static const struct v4l2_ctrl_config hwn = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_USED_ENGINE, + .name = "Engine resource", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 2, + .step = 1, + .def = 2, +}; + +static const struct v4l2_ctrl_config bin = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_BIN, + .name = "Binning", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config frz = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_FRZ, + .name = "Resizer", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 70, + .max = 100, + .step = 1, + .def = 100, +}; + +static const struct v4l2_ctrl_config raw_path = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_RAW_PATH_SELECT, + .name = "Raw Path", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config hwn_try = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_USED_ENGINE_TRY, + .name = "Engine resource", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 1, + .max = 2, + .step = 1, + .def = 2, +}; + +static const struct v4l2_ctrl_config bin_try = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_BIN_TRY, + .name = "Binning", + .type = V4L2_CTRL_TYPE_BOOLEAN, + .min = 0, + .max = 1, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config frz_try = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_FRZ_TRY, + .name = "Resizer", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 70, + .max = 100, + .step = 1, + .def = 100, +}; + +static const struct v4l2_ctrl_config res_plan_policy = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_RESOURCE_PLAN_POLICY, + .name = "Resource planning policy", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 10, + .step = 1, + .def = 1, +}; + +static const struct v4l2_ctrl_config res_pixel_rate = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_PIXEL_RATE, + .name = "Resource pixel rate", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = 0, + .max = 0xFFFFFFFF, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config frame_sync_id = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_SYNC_ID, + .name = "Frame sync id", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = -1, + .max = 0x7FFFFFFF, + .step = 1, + .def = -1, +}; + +static const struct v4l2_ctrl_config mtk_feature = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_FEATURE, + .name = "mediatek camsys feature", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = 0, + .max = RAW_FUNCTION_END, + .step = 1, + .def = 0, +}; + +static struct v4l2_ctrl_config cfg_res_ctrl = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC, + .name = "resource ctrl", + .type = V4L2_CTRL_COMPOUND_TYPES, /* V4L2_CTRL_TYPE_U32,*/ + .flags = V4L2_CTRL_FLAG_EXECUTE_ON_WRITE, + .max = 0xffffffff, + .step = 1, + .dims = {sizeof(struct mtk_cam_resource)}, +}; + +static struct v4l2_ctrl_config cfg_res_update = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_RAW_RESOURCE_UPDATE, + .name = "resource update", + .type = V4L2_CTRL_TYPE_INTEGER, + .min = 0, + .max = 0xf, + .step = 1, + .def = 0, +}; + +static const struct v4l2_ctrl_config cfg_pde_info = { + .ops = &cam_pde_ctrl_ops, + .id = V4L2_CID_MTK_CAM_PDE_INFO, + .name = "pde information", + .type = V4L2_CTRL_TYPE_INTEGER, + .flags = V4L2_CTRL_FLAG_VOLATILE, + .min = 0, + .max = 0x1fffffff, + .step = 1, + .def = 0, + .dims = {sizeof_u32(struct mtk_cam_pde_info)}, +}; + +static const struct v4l2_ctrl_config mtk_camsys_hw_mode = { + .ops = &cam_ctrl_ops, + .id = V4L2_CID_MTK_CAM_CAMSYS_HW_MODE, + .name = "mediatek camsys hardware mode", + .type = V4L2_CTRL_TYPE_INTEGER64, + .min = 0, + .max = 0x7FFFFFFF, + .step = 1, + .def = DEFAULT, +}; + +static void mtk_cam_raw_toggle_db(struct mtk_raw_device *dev) +{ + int value; + u32 val_cfg, val_dcif_ctl, val_sen; + + value = readl_relaxed(dev->base + REG_CTL_MISC); + val_cfg = readl_relaxed(dev->base_inner + REG_TG_PATH_CFG); + val_dcif_ctl = readl_relaxed(dev->base_inner + REG_TG_DCIF_CTL); + val_sen = readl_relaxed(dev->base_inner + REG_TG_SEN_MODE); + writel_relaxed(value & ~CTL_DB_EN, dev->base + REG_CTL_MISC); + wmb(); /* make sure committed */ + writel_relaxed(value | CTL_DB_EN, dev->base + REG_CTL_MISC); + wmb(); /* make sure committed */ + dev_info(dev->dev, + "%s, read inner AsIs->ToBe TG_PATH_CFG:0x%x->0x%x, TG_DCIF:0x%x->0x%x, TG_SEN:0x%x->0x%x\n", + __func__, val_cfg, + readl_relaxed(dev->base_inner + REG_TG_PATH_CFG), val_dcif_ctl, + readl_relaxed(dev->base_inner + REG_TG_DCIF_CTL), val_sen, + readl_relaxed(dev->base_inner + REG_TG_SEN_MODE)); +} + +void mtk_cam_raw_trigger_rawi(struct mtk_raw_device *dev, + struct mtk_cam_ctx *ctx, signed int hw_scene) +{ + #define TRIGGER_RAWI_R6 0x10 + #define TRIGGER_RAWI_R2 0x01 + u32 cmd = TRIGGER_RAWI_R2; + + writel_relaxed(cmd, dev->base + REG_CTL_RAWI_TRIG); + wmb(); /* make sure committed */ +} + +void mtk_cam_raw_apply_cq(struct mtk_raw_device *dev, dma_addr_t cq_addr, + unsigned int cq_size, unsigned int cq_offset, + unsigned int sub_cq_size, unsigned int sub_cq_offset) +{ + dma_addr_t main, sub; + + dev_dbg(dev->dev, + "apply raw%d cq - addr:0x%pad,size:%d/%d,offset:%d\n", + dev->id, &cq_addr, cq_size, sub_cq_size, sub_cq_offset); + + main = cq_addr + cq_offset; + sub = cq_addr + sub_cq_offset; + + writel_relaxed(dmaaddr_lsb(main), + dev->base + REG_CQ_THR0_BASEADDR); + writel_relaxed(dmaaddr_msb(main), + dev->base + REG_CQ_THR0_BASEADDR_MSB); + writel_relaxed(cq_size, + dev->base + REG_CQ_THR0_DESC_SIZE); + writel_relaxed(dmaaddr_lsb(sub), + dev->base + REG_CQ_SUB_THR0_BASEADDR_2); + writel_relaxed(dmaaddr_msb(sub), + dev->base + REG_CQ_SUB_THR0_BASEADDR_MSB_2); + writel_relaxed(sub_cq_size, + dev->base + REG_CQ_SUB_THR0_DESC_SIZE_2); + + /* USINGSCQ and always trigger now */ + writel_relaxed(CAMCTL_CQ_THR0_DONE_ST, + dev->base + REG_CTL_RAW_INT6_EN); + writel_relaxed(CAMCTL_CQ_THRSUB_DONE_EN, + dev->base + REG_CTL_RAW_INT7_EN); + writel(CTL_CQ_THR0_START, dev->base + REG_CTL_START); + + wmb(); /* make sure committed */ +} + +/* sw check again for rawi dcif case */ +static bool mtk_cam_raw_is_dma_idle(struct mtk_raw_device *dev) +{ + bool ret = false; + int chasing_stat; + int raw_rst_stat = readl(dev->base + REG_DMA_SOFT_RST_STAT); + int raw_rst_stat2 = readl(dev->base + REG_DMA_SOFT_RST_STAT2); + int yuv_rst_stat = readl(dev->yuv_base + REG_DMA_SOFT_RST_STAT); + + if (raw_rst_stat2 != 0x7 || yuv_rst_stat != 0xfffffff) + return false; + + /* check beside rawi_r2/r3/r5 */ + if (~raw_rst_stat & 0x7fffffda) + return false; + + if (~raw_rst_stat & RST_STAT_RAWI_R2) { /* RAWI_R2 */ + chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS); + ret = ((chasing_stat & RAWI_R2_SMI_REQ_ST) == 0 && + (readl(dev->base + REG_RAWI_R2_BASE + DMA_OFFSET_SPECIAL_DCIF) + & DC_CAMSV_STAGER_EN) && + (readl(dev->base + REG_CTL_MOD6_EN) & 0x1)) + ? true : false; + dev_info(dev->dev, "%s: chasing_stat: 0x%x ret=%d\n", + __func__, chasing_stat, ret); + } + + if (~raw_rst_stat & RST_STAT_RAWI_R3) { + chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS); + ret = ((chasing_stat & RAWI_R3_SMI_REQ_ST) == 0 && + (readl(dev->base + REG_RAWI_R3_BASE + DMA_OFFSET_SPECIAL_DCIF) + & DC_CAMSV_STAGER_EN) && + (readl(dev->base + REG_CTL_MOD6_EN) & 0x80)) + ? true : false; + dev_info(dev->dev, "%s: chasing_stat: 0x%x, ret=%d\n", + __func__, chasing_stat, ret); + } + + if (~raw_rst_stat & RST_STAT_RAWI_R5) { + chasing_stat = readl(dev->base + REG_DMA_DBG_CHASING_STATUS2); + ret = ((chasing_stat & RAWI_R5_SMI_REQ_ST) == 0 && + (readl(dev->base + REG_RAWI_R5_BASE + DMA_OFFSET_SPECIAL_DCIF) + & DC_CAMSV_STAGER_EN) && + (readl(dev->base + REG_CTL_MOD6_EN) & 0x1000)) + ? true : false; + dev_info(dev->dev, "%s: chasing_stat: 0x%x, ret=%d\n", + __func__, chasing_stat, ret); + } + + return ret; +} + +void mtk_cam_raw_reset(struct mtk_raw_device *dev) +{ + int sw_ctl; + int ret; + + dev_dbg(dev->dev, "camsys | trigger %s\n", __func__); + + /* Disable all DMA DCM before reset */ + writel(0x00000fff, dev->base + REG_CTL_RAW_MOD5_DCM_DIS); + writel(0x0007ffff, dev->base + REG_CTL_RAW_MOD6_DCM_DIS); + writel(0xffffffff, dev->yuv_base + REG_CTL_RAW_MOD5_DCM_DIS); + + /* Enable CQI_R1 ~ R4 before reset and make sure loaded */ + writel(readl(dev->base + REG_CTL_MOD6_EN) | 0x78000, + dev->base + REG_CTL_MOD6_EN); + mtk_cam_raw_toggle_db(dev); + + writel(0, dev->base + REG_CTL_SW_CTL); + writel(1, dev->base + REG_CTL_SW_CTL); + wmb(); /* make sure committed */ + + ret = readx_poll_timeout(readl, dev->base + REG_CTL_SW_CTL, sw_ctl, + sw_ctl & 0x2, + 1 /* delay, us */, 5000 /* timeout, us */); + + if (ret < 0 && !mtk_cam_raw_is_dma_idle(dev)) { + dev_info(dev->dev, + "%s: timeout: tg_sen_mode: 0x%x, ctl_en: 0x%x, mod6_en: 0x%x, ctl_sw_ctl:0x%x, frame_no:0x%x,rst_stat:0x%x,rst_stat2:0x%x,yuv_rst_stat:0x%x\n", + __func__, + readl(dev->base + REG_TG_SEN_MODE), + readl(dev->base + REG_CTL_EN), + readl(dev->base + REG_CTL_MOD6_EN), + readl(dev->base + REG_CTL_SW_CTL), + readl(dev->base + REG_FRAME_SEQ_NUM), + readl(dev->base + REG_DMA_SOFT_RST_STAT), + readl(dev->base + REG_DMA_SOFT_RST_STAT2), + readl(dev->yuv_base + REG_DMA_SOFT_RST_STAT)); + + goto RESET_FAILURE; + } + + /* do hw rst */ + writel(4, dev->base + REG_CTL_SW_CTL); + writel(0, dev->base + REG_CTL_SW_CTL); + +RESET_FAILURE: + /* Enable all DMA DCM back */ + writel(0x0, dev->base + REG_CTL_RAW_MOD5_DCM_DIS); + writel(0x0, dev->base + REG_CTL_RAW_MOD6_DCM_DIS); + writel(0x0, dev->yuv_base + REG_CTL_RAW_MOD5_DCM_DIS); + + wmb(); /* make sure committed */ +} + +static void mtk_cam_raw_reset_reg(struct mtk_raw_device *dev) +{ + int cq_en, sw_done; + + dev_dbg(dev->dev, + "[%s++] CQ_EN/SW_SUB_CTL/SW_DONE [in] 0x%x/0x%x/0x%x [out] 0x%x/0x%x/0x%x\n", + __func__, + readl_relaxed(dev->base_inner + REG_CQ_EN), + readl_relaxed(dev->base_inner + REG_CTL_SW_SUB_CTL), + readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE), + readl_relaxed(dev->base + REG_CQ_EN), + readl_relaxed(dev->base + REG_CTL_SW_SUB_CTL), + readl_relaxed(dev->base + REG_CTL_SW_PASS1_DONE)); + + cq_en = readl_relaxed(dev->base_inner + REG_CQ_EN); + sw_done = readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE); + + cq_en = cq_en & (~SCQ_SUBSAMPLE_EN) & (~SCQ_STAGGER_MODE); + writel(cq_en, dev->base_inner + REG_CQ_EN); + writel(cq_en, dev->base + REG_CQ_EN); + + dev_dbg(dev->dev, "[--] try to disable SCQ_STAGGER_MODE: CQ_EN(0x%x)\n", + cq_en); + + writel(sw_done & (~SW_DONE_SAMPLE_EN), dev->base_inner + REG_CTL_SW_PASS1_DONE); + writel(sw_done & (~SW_DONE_SAMPLE_EN), dev->base + REG_CTL_SW_PASS1_DONE); + + writel(0, dev->base_inner + REG_CTL_SW_SUB_CTL); + writel(0, dev->base + REG_CTL_SW_SUB_CTL); + + wmb(); /* make sure committed */ + + dev_dbg(dev->dev, + "[%s--] CQ_EN/SW_SUB_CTL/SW_DONE [in] 0x%x/0x%x/0x%x [out] 0x%x/0x%x/0x%x\n", + __func__, readl_relaxed(dev->base_inner + REG_CQ_EN), + readl_relaxed(dev->base_inner + REG_CTL_SW_SUB_CTL), + readl_relaxed(dev->base_inner + REG_CTL_SW_PASS1_DONE), + readl_relaxed(dev->base + REG_CQ_EN), + readl_relaxed(dev->base + REG_CTL_SW_SUB_CTL), + readl_relaxed(dev->base + REG_CTL_SW_PASS1_DONE)); +} + +void mtk_cam_raw_dump_aa_info(struct mtk_cam_ctx *ctx, + struct mtk_ae_debug_data *ae_info) +{ + struct mtk_raw_device *raw_dev = NULL; + struct mtk_raw_pipeline *pipe = ctx->pipe; + int i; + + for (i = 0; i < ctx->cam->num_raw_devices; i++) { + if (pipe->enabled_raw & (1 << i)) { + struct device *dev = ctx->cam->raw.devs[i]; + + raw_dev = dev_get_drvdata(dev); + ae_info->obc_r1_sum[0] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R1_R_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R1_R_SUM_L); + ae_info->obc_r2_sum[0] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R2_R_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R2_R_SUM_L); + ae_info->obc_r3_sum[0] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R3_R_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R3_R_SUM_L); + ae_info->ltm_sum[0] += + ((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_R_MSB) << 32) | + readl(raw_dev->base + REG_LTM_AE_DEBUG_R_LSB); + ae_info->aa_sum[0] += + ((u64)readl(raw_dev->base + REG_AA_R_SUM_H) << 32) | + readl(raw_dev->base + REG_AA_R_SUM_L); + + ae_info->obc_r1_sum[1] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R1_B_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R1_B_SUM_L); + ae_info->obc_r2_sum[1] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R2_B_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R2_B_SUM_L); + ae_info->obc_r3_sum[1] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R3_B_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R3_B_SUM_L); + ae_info->ltm_sum[1] += + ((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_B_MSB) << 32) | + readl(raw_dev->base + REG_LTM_AE_DEBUG_B_LSB); + ae_info->aa_sum[1] += + ((u64)readl(raw_dev->base + REG_AA_B_SUM_H) << 32) | + readl(raw_dev->base + REG_AA_B_SUM_L); + + ae_info->obc_r1_sum[2] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R1_GR_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R1_GR_SUM_L); + ae_info->obc_r2_sum[2] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R2_GR_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R2_GR_SUM_L); + ae_info->obc_r3_sum[2] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R3_GR_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R3_GR_SUM_L); + ae_info->ltm_sum[2] += + ((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_GR_MSB) << 32) | + readl(raw_dev->base + REG_LTM_AE_DEBUG_GR_LSB); + ae_info->aa_sum[2] += + ((u64)readl(raw_dev->base + REG_AA_GR_SUM_H) << 32) | + readl(raw_dev->base + REG_AA_GR_SUM_L); + + ae_info->obc_r1_sum[3] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R1_GB_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R1_GB_SUM_L); + ae_info->obc_r2_sum[3] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R2_GB_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R2_GB_SUM_L); + ae_info->obc_r3_sum[3] += + ((u64)readl(raw_dev->base + OFFSET_OBC_R3_GB_SUM_H) << 32) | + readl(raw_dev->base + OFFSET_OBC_R3_GB_SUM_L); + ae_info->ltm_sum[3] += + ((u64)readl(raw_dev->base + REG_LTM_AE_DEBUG_GB_MSB) << 32) | + readl(raw_dev->base + REG_LTM_AE_DEBUG_GB_LSB); + ae_info->aa_sum[3] += + ((u64)readl(raw_dev->base + REG_AA_GB_SUM_H) << 32) | + readl(raw_dev->base + REG_AA_GB_SUM_L); + } + } +} + +static int reset_msgfifo(struct mtk_raw_device *dev) +{ + atomic_set(&dev->is_fifo_overflow, 0); + return kfifo_init(&dev->msg_fifo, dev->msg_buffer, dev->fifo_size); +} + +static int push_msgfifo(struct mtk_raw_device *dev, + struct mtk_camsys_irq_info *info) +{ + int len; + + if (unlikely(kfifo_avail(&dev->msg_fifo) < sizeof(*info))) { + atomic_set(&dev->is_fifo_overflow, 1); + return -1; + } + + len = kfifo_in(&dev->msg_fifo, info, sizeof(*info)); + WARN_ON(len != sizeof(*info)); + + return 0; +} + +static void set_fifo_size(void __iomem *dma_base, int fifo_size) +{ + writel_relaxed((0x1 << 28) | (fifo_size & 0xFFF), + dma_base + DMA_OFFSET_CON0); +} + +static void set_fifo_threshold(void __iomem *dma_base) +{ + u32 fifo_size = 0; + + fifo_size = readl_relaxed(dma_base + DMA_OFFSET_CON0) & 0xFFF; + writel_relaxed((0x1 << 28) | + ((fifo_size * 1 / 4) & 0xFFF) << 16 | + ((fifo_size * 1 / 8) & 0xFFF), + dma_base + DMA_OFFSET_CON1); + writel_relaxed((0x1 << 28) | + ((fifo_size * 1 / 2) & 0xFFF) << 16 | + ((fifo_size * 3 / 8) & 0xFFF), + dma_base + DMA_OFFSET_CON2); + writel_relaxed((0x1 << 31) | + ((fifo_size * 2 / 3) & 0xFFF) << 16 | + ((fifo_size * 13 / 24) & 0xFFF), + dma_base + DMA_OFFSET_CON3); + writel_relaxed((0x1 << 31) | + ((fifo_size * 3 / 8) & 0xFFF) << 16 | + ((fifo_size * 1 / 4) & 0xFFF), + dma_base + DMA_OFFSET_CON4); +} + +static void init_dma_threshold(struct mtk_raw_device *dev) +{ + struct mtk_cam_device *cam_dev; + + cam_dev = dev->cam; + + /* Set mt8188 default fifo size */ + set_fifo_size(dev->base + REG_IMGO_R1_BASE, 0x3C0); + set_fifo_size(dev->yuv_base + REG_YUVCO_R1_BASE, 0x200); + set_fifo_size(dev->yuv_base + REG_YUVDO_R1_BASE, 0x80); + set_fifo_size(dev->yuv_base + REG_YUVO_R3_BASE, 0xc0); + set_fifo_size(dev->yuv_base + REG_YUVBO_R3_BASE, 0x60); + set_fifo_size(dev->yuv_base + REG_YUVCO_R3_BASE, 0x40); + set_fifo_size(dev->yuv_base + REG_YUVO_R2_BASE, 0x80); + set_fifo_size(dev->yuv_base + REG_YUVBO_R2_BASE, 0x40); + set_fifo_size(dev->yuv_base + REG_YUVO_R4_BASE, 0x40); + set_fifo_size(dev->yuv_base + REG_YUVBO_R4_BASE, 0x40); + set_fifo_size(dev->yuv_base + REG_YUVO_R5_BASE, 0x40); + set_fifo_threshold(dev->base + REG_IMGO_R1_BASE); + set_fifo_threshold(dev->base + REG_FHO_R1_BASE); + set_fifo_threshold(dev->base + REG_AAHO_R1_BASE); + set_fifo_threshold(dev->base + REG_PDO_R1_BASE); + set_fifo_threshold(dev->base + REG_AAO_R1_BASE); + set_fifo_threshold(dev->base + REG_AFO_R1_BASE); + set_fifo_threshold(dev->base + REG_PDO_R1_BASE); + + set_fifo_threshold(dev->yuv_base + REG_YUVO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVBO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVCO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVDO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVBO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVCO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_LTMSO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TSFSO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TSFSO_R2_BASE); + set_fifo_threshold(dev->yuv_base + REG_FLKO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_UFEO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVO_R2_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVBO_R2_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVO_R4_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVBO_R4_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVO_R5_BASE); + set_fifo_threshold(dev->yuv_base + REG_YUVBO_R5_BASE); + set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_RZH1N2TBO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R2_BASE); + set_fifo_threshold(dev->yuv_base + REG_RZH1N2TO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_RZH1N2TBO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R2_BASE); + set_fifo_threshold(dev->yuv_base + REG_DRZS4NO_R3_BASE); + set_fifo_threshold(dev->yuv_base + REG_ACTSO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TNCSO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TNCSBO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TNCSHO_R1_BASE); + set_fifo_threshold(dev->yuv_base + REG_TNCSYO_R1_BASE); + + set_fifo_threshold(dev->base + REG_RAWI_R2_BASE); + set_fifo_threshold(dev->base + REG_UFDI_R2_BASE); + set_fifo_threshold(dev->base + REG_RAWI_R3_BASE); + set_fifo_threshold(dev->base + REG_UFDI_R3_BASE); + set_fifo_threshold(dev->base + REG_CQI_R1_BASE); + set_fifo_threshold(dev->base + REG_CQI_R2_BASE); + set_fifo_threshold(dev->base + REG_CQI_R3_BASE); + set_fifo_threshold(dev->base + REG_CQI_R4_BASE); + set_fifo_threshold(dev->base + REG_LSCI_R1_BASE); + set_fifo_threshold(dev->base + REG_BPCI_R1_BASE); + set_fifo_threshold(dev->base + REG_BPCI_R2_BASE); + set_fifo_threshold(dev->base + REG_BPCI_R3_BASE); + set_fifo_threshold(dev->base + REG_PDI_R1_BASE); + set_fifo_threshold(dev->base + REG_AAI_R1_BASE); + set_fifo_threshold(dev->base + REG_CACI_R1_BASE); + set_fifo_threshold(dev->base + REG_RAWI_R6_BASE); + + writel_relaxed(0x1, cam_dev->base + REG_HALT1_EN); + writel_relaxed(0x1, cam_dev->base + REG_HALT2_EN); + writel_relaxed(0x1, cam_dev->base + REG_HALT3_EN); + writel_relaxed(0x1, cam_dev->base + REG_HALT4_EN); + writel_relaxed(0x1, cam_dev->base + REG_HALT5_EN); + writel_relaxed(0x1, cam_dev->base + REG_HALT6_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT1_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT2_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT3_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT4_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT5_EN); + writel_relaxed(0x1, cam_dev->base + REG_ULTRA_HALT6_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT1_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT2_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT3_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT4_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT5_EN); + writel_relaxed(0x1, cam_dev->base + REG_PREULTRA_HALT6_EN); +} + +static int get_fps_ratio(struct mtk_raw_device *dev) +{ + int fps = (dev->pipeline->res_config.interval.numerator > 0) ? + (dev->pipeline->res_config.interval.denominator / + dev->pipeline->res_config.interval.numerator) : 0; + + if (fps <= 30) + return 1; + else if (fps <= 60) + return 2; + else + return 1; +} + +void mtk_cam_raw_initialize(struct mtk_raw_device *dev, int is_sub) +{ + u32 val; + + /* USINGSCQ */ + val = readl_relaxed(dev->base + REG_CQ_EN); + writel_relaxed(val | SCQ_EN, dev->base + REG_CQ_EN); + writel_relaxed(0xffffffff, dev->base + REG_SCQ_START_PERIOD); + + writel_relaxed(CQ_THR0_MODE_IMMEDIATE | CQ_THR0_EN, + dev->base + REG_CQ_THR0_CTL); + writel_relaxed(CQ_THR0_MODE_IMMEDIATE | CQ_THR0_EN, + dev->base + REG_CQ_SUB_THR0_CTL); + writel_relaxed(CAMCTL_CQ_THR0_DONE_ST, + dev->base + REG_CTL_RAW_INT6_EN); + writel_relaxed(CAMCTL_CQ_THRSUB_DONE_EN, + dev->base + REG_CTL_RAW_INT7_EN); + + dev->is_sub = is_sub; + dev->sof_count = 0; + dev->vsync_count = 0; + atomic_set(&dev->vf_en, 0); + reset_msgfifo(dev); + + init_dma_threshold(dev); + + writel_relaxed(0xFFFE0000, + dev->base + REG_FLKO_R1_BASE + DMA_OFFSET_ERR_STAT); + + dev_dbg(dev->dev, "%s - REG_CQ_EN:0x%x ,REG_CQ_THR0_CTL:0x%8x\n", + __func__, + readl_relaxed(dev->base + REG_CQ_EN), + readl_relaxed(dev->base + REG_CQ_THR0_CTL)); +} + +void mtk_cam_raw_stream_on(struct mtk_raw_device *dev, int on) +{ + u32 val; + u32 chk_val; + u32 cfg_val; + u32 fps_ratio = 1; + struct mtk_cam_ctx *ctx; + + dev_info(dev->dev, "raw %d %s %d\n", dev->id, __func__, on); + ctx = mtk_cam_find_ctx(dev->cam, &dev->pipeline->subdev.entity); + if (!ctx) { + dev_info(dev->dev, "%s: cannot find ctx\n", __func__); + return; + } + + if (on) { + /* USINGSCQ */ + val = readl_relaxed(dev->base + REG_TG_TIME_STAMP_CNT); + val = (val == 0) ? 1 : val; + fps_ratio = get_fps_ratio(dev); + dev_info(dev->dev, + "VF on - REG_TG_TIME_STAMP_CNT val:%d fps(30x):%d\n", + val, fps_ratio); + writel_relaxed(SCQ_DEADLINE_MS * 1000 * SCQ_DEFAULT_CLK_RATE / + (val * 2) / fps_ratio, + dev->base + REG_SCQ_START_PERIOD); + + mtk_cam_set_topdebug_rdyreq(dev->dev, dev->base, dev->yuv_base, + TG_OVERRUN); + dev->overrun_debug_dump_cnt = 0; + if (mtk_cam_is_m2m(ctx)) { + dev_info(dev->dev, "[%s] M2M view finder disable\n", __func__); + } else { + val = readl_relaxed(dev->base + REG_TG_VF_CON); + val |= TG_VFDATA_EN; + writel_relaxed(val, dev->base + REG_TG_VF_CON); + wmb(); /* make sure committed */ + } + atomic_set(&dev->vf_en, 1); + dev_info(dev->dev, + "%s - CQ_EN:0x%x, CQ_THR0_CTL:0x%8x, TG_VF_CON:0x%8x, SCQ_START_PERIOD:%d\n", + __func__, + readl_relaxed(dev->base + REG_CQ_EN), + readl_relaxed(dev->base + REG_CQ_THR0_CTL), + readl_relaxed(dev->base + REG_TG_VF_CON), + readl_relaxed(dev->base + REG_SCQ_START_PERIOD)); + } else { + dev_info(dev->dev, "VF off\n"); + atomic_set(&dev->vf_en, 0); + + writel_relaxed((u32)~CQ_THR0_EN, dev->base + REG_CQ_THR0_CTL); + wmb(); /* make sure committed */ + + cfg_val = readl_relaxed(dev->base + REG_TG_PATH_CFG); + cfg_val |= 0x100; + writel(cfg_val, dev->base + REG_TG_PATH_CFG); + + val = readl_relaxed(dev->base + REG_TG_VF_CON); + val &= ~TG_VFDATA_EN; + writel(val, dev->base + REG_TG_VF_CON); + + cfg_val = readl_relaxed(dev->base + REG_TG_PATH_CFG); + cfg_val &= ~0x100; + writel(cfg_val, dev->base + REG_TG_PATH_CFG); + + wmb(); /* make sure committed */ + /* reset hw after vf off */ + if (readx_poll_timeout(readl, dev->base_inner + REG_TG_VF_CON, + chk_val, chk_val == val, 1 /* sleep us */, + 33000 /* timeout us */) < 0) { + dev_info(dev->dev, + "%s: wait vf off timeout: TG_VF_CON 0x%x\n", + __func__, chk_val); + } + + mtk_cam_raw_reset_reg(dev); + } +} + +static int mtk_raw_linebuf_chk(bool b_twin, bool b_bin, bool b_frz, bool b_qbn, + bool b_cbn, int tg_x, int *frz_ratio) +{ + int input_x = tg_x; + /* max line buffer check for frontal binning and resizer */ + if (b_twin) { + if (input_x > CAM_TWIN_PROCESS_MAX_LINE_BUFFER) + return LB_CHECK_TWIN; + input_x = input_x >> 1; + } + if (b_cbn) { + if (input_x > CAM_RAW_CBN_MAX_LINE_BUFFER) + return LB_CHECK_CBN; + input_x = input_x >> 1; + } + if (b_qbn) { + if (input_x > CAM_RAW_QBND_MAX_LINE_BUFFER) + return LB_CHECK_QBN; + input_x = input_x >> 1; + } + if (b_bin) { + if (input_x > CAM_RAW_BIN_MAX_LINE_BUFFER) + return LB_CHECK_BIN; + input_x = input_x >> 1; + } + if (input_x <= CAM_RAW_PROCESS_MAX_LINE_BUFFER) { + return LB_CHECK_OK; + } else if (b_frz) { + if (input_x > CAM_RAW_FRZ_MAX_LINE_BUFFER) + return LB_CHECK_FRZ; + + *frz_ratio = input_x * 100 / CAM_RAW_PROCESS_MAX_LINE_BUFFER; + return LB_CHECK_OK; + } else { + return LB_CHECK_RAW; + } +} + +static int mtk_raw_pixelmode_calc(int rawpxl, int b_twin, bool b_bin, + bool b_frz, int min_ratio) +{ + int pixelmode = rawpxl; + + pixelmode = (b_twin == 2) ? pixelmode << 2 : pixelmode; + pixelmode = (b_twin == 1) ? pixelmode << 1 : pixelmode; + pixelmode = b_bin ? pixelmode << 1 : pixelmode; + pixelmode = (b_frz && (min_ratio < FRZ_PXLMODE_THRES)) ? + pixelmode << 1 : pixelmode; + pixelmode = (pixelmode > TGO_MAX_PXLMODE) ? + TGO_MAX_PXLMODE : pixelmode; + + return pixelmode; +} + +static void mtk_raw_update_debug_param(struct mtk_cam_device *cam, + struct mtk_cam_resource_config *res, + int *clk_idx) +{ + /* skip if debug is not enabled */ + if (!debug_raw) + return; + + dev_dbg(cam->dev, + "%s:before:BIN/FRZ/HWN/CLK/pxl=%d/%d(%d)/%d/%d/%d, clk:%d\n", + __func__, res->bin_enable, res->frz_enable, res->frz_ratio, + res->raw_num_used, *clk_idx, res->tgo_pxl_mode, + res->clk_target); + + if (debug_raw_num > 0) { + dev_info(cam->dev, "DEBUG: force raw_num_used: %d\n", + debug_raw_num); + res->raw_num_used = debug_raw_num; + } + + if (debug_pixel_mode >= 0) { + dev_info(cam->dev, "DEBUG: force debug_pixel_mode (log2): %d\n", + debug_pixel_mode); + res->tgo_pxl_mode = debug_pixel_mode; + } + + if (debug_clk_idx >= 0) { + dev_info(cam->dev, "DEBUG: force debug_clk_idx: %d\n", + debug_clk_idx); + *clk_idx = debug_clk_idx; + } + + dev_dbg(cam->dev, + "%s:after:BIN/FRZ/HWN/CLK/pxl=%d/%d(%d)/%d/%d/%d, clk:%d\n", + __func__, res->bin_enable, res->frz_enable, res->frz_ratio, + res->raw_num_used, *clk_idx, res->tgo_pxl_mode, + res->clk_target); +} + +static bool is_cbn_en(int bin_flag) +{ + switch (bin_flag) { + case CBN_2X2_ON: + case CBN_3X3_ON: + case CBN_4X4_ON: + return true; + default: + return false; + } +} + +static bool mtk_cam_raw_resource_calc(struct mtk_cam_device *cam, + struct mtk_cam_resource_config *res, + s64 pixel_rate, int res_plan, + int in_w, int in_h, int *out_w, int *out_h) +{ + int res_step_type = 0; + int tgo_pxl_mode = 1; + int pixel_mode[MTK_CAMSYS_RES_STEP_NUM] = {0}; + int bin_temp = 0, frz_temp = 0, hwn_temp = 0; + int bin_en = 0, frz_en = 0, twin_en = 0, clk_cur = 0; + int idx = 0, clk_res = 0, idx_res = 0; + bool res_found = false; + int lb_chk_res = -1; + int frz_ratio = 100; + int p; + + res->res_plan = res_plan; + res->pixel_rate = pixel_rate; + /* test pattern */ + if (res->pixel_rate == 0) + res->pixel_rate = 450 * MHz; + dev_dbg(cam->dev, + "[Res] PR = %lld, w/h=%d/%d HWN(%d)/BIN(%d)/FRZ(%d),Plan:%d\n", + res->pixel_rate, in_w, in_h, + res->hwn_limit_max, res->bin_limit, res->frz_limit, res->res_plan); + + memcpy(res->res_strategy, raw_resource_strategy_plan + res->res_plan, + MTK_CAMSYS_RES_STEP_NUM * sizeof(int)); + res->bin_enable = 0; + res->raw_num_used = 1; + res->frz_enable = 0; + res->frz_ratio = frz_ratio; + for (idx = 0; idx < MTK_CAMSYS_RES_STEP_NUM ; idx++) { + res_step_type = res->res_strategy[idx] & MTK_CAMSYS_RES_IDXMASK; + switch (res_step_type) { + case MTK_CAMSYS_RES_BIN_TAG: + bin_temp = res->res_strategy[idx] - E_RES_BIN_S; + if (bin_temp <= res->bin_limit) + bin_en = bin_temp; + if (bin_en && frz_en) + frz_en = 0; + break; + case MTK_CAMSYS_RES_FRZ_TAG: + frz_temp = res->res_strategy[idx] - E_RES_FRZ_S; + if (res->frz_limit < 100) + frz_en = frz_temp; + break; + case MTK_CAMSYS_RES_HWN_TAG: + hwn_temp = res->res_strategy[idx] - E_RES_HWN_S; + if (hwn_temp + 1 <= res->hwn_limit_max) + twin_en = hwn_temp; + break; + case MTK_CAMSYS_RES_CLK_TAG: + clk_cur = res->res_strategy[idx] - E_RES_CLK_S; + break; + default: + break; + } + + /* 1 for force bin on */ + if (res->bin_limit >= 1) + bin_en = 1; + + if (res->hwn_limit_min > 1) + twin_en = 1; + + /* max line buffer check*/ + lb_chk_res = mtk_raw_linebuf_chk(twin_en, res->bin_limit & BIN_ON, + frz_en, res->bin_limit & QBND_ON, + is_cbn_en(res->bin_limit), + in_w, &frz_ratio); + /* frz ratio*/ + if (res_step_type == MTK_CAMSYS_RES_FRZ_TAG) { + res->frz_ratio = res->frz_limit < FRZ_PXLMODE_THRES ? + res->frz_limit : FRZ_PXLMODE_THRES; + } + /*try 1-pixel mode first*/ + for (p = 1; p <= MTK_CAMSYS_PROC_DEFAULT_PIXELMODE; p++) { + tgo_pxl_mode = mtk_raw_pixelmode_calc(p, twin_en, + bin_en, frz_en, + res->frz_ratio); + /** + * isp throughput along resource strategy + * (compared with pixel rate) + */ + pixel_mode[idx] = tgo_pxl_mode; + + /* only support 1-pixel mode */ + if (p == 1 && lb_chk_res == LB_CHECK_OK) { + if (!res_found) { + res->bin_enable = bin_en; + res->frz_enable = frz_en; + res->raw_num_used = twin_en + 1; + clk_res = clk_cur; + idx_res = idx; + res_found = true; + break; + } + } + } + dev_dbg(cam->dev, + "Res-%d B/F/H/C=%d/%d/%d/%d -> %d/%d/%d/%d (%d)(%d)\n", + idx, bin_temp, frz_temp, hwn_temp, clk_cur, bin_en, + frz_en, twin_en, clk_cur, lb_chk_res, pixel_mode[idx]); + } + + tgo_pxl_mode = pixel_mode[idx_res]; + switch (tgo_pxl_mode) { + case 1: + res->tgo_pxl_mode = 0; + break; + case 2: + res->tgo_pxl_mode = 1; + break; + case 4: + res->tgo_pxl_mode = 2; + break; + case 8: + res->tgo_pxl_mode = 3; + break; + default: + break; + } + + mtk_raw_update_debug_param(cam, res, &clk_res); + + if (res_found) { + dev_info(cam->dev, + "Res-end:%d BIN/FRZ/HWN/CLK/pxl=%d/%d(%d)/%d/%d/%d, clk:%d\n", + idx_res, res->bin_enable, res->frz_enable, res->frz_ratio, + res->raw_num_used, clk_res, res->tgo_pxl_mode, + res->clk_target); + } else { + dev_dbg(cam->dev, "[%s] Error resource result\n", __func__); + } + if (res->bin_enable) { + *out_w = in_w >> 1; + *out_h = in_h >> 1; + } else if (res->frz_enable) { + *out_w = in_w * res->frz_ratio / 100; + *out_h = in_h * res->frz_ratio / 100; + } else { + *out_w = in_w; + *out_h = in_h; + } + + return res_found; +} + +static void raw_irq_handle_tg_grab_err(struct mtk_raw_device *raw_dev, + int dequeued_frame_seq_no); +static void raw_irq_handle_dma_err(struct mtk_raw_device *raw_dev); +static void raw_irq_handle_tg_overrun_err(struct mtk_raw_device *raw_dev, + int dequeued_frame_seq_no); + +static void raw_handle_error(struct mtk_raw_device *raw_dev, + struct mtk_camsys_irq_info *data) +{ + int err_status = data->e.err_status; + int frame_idx_inner = data->frame_idx_inner; + + /* Show DMA errors in detail */ + if (err_status & DMA_ERR_ST) + raw_irq_handle_dma_err(raw_dev); + + /* Show TG register for more error detail*/ + if (err_status & TG_GBERR_ST) + raw_irq_handle_tg_grab_err(raw_dev, frame_idx_inner); + + if (err_status & TG_OVRUN_ST) { + if (raw_dev->overrun_debug_dump_cnt < 4) { + mtk_cam_dump_topdebug_rdyreq(raw_dev->dev, + raw_dev->base, + raw_dev->yuv_base); + raw_dev->overrun_debug_dump_cnt++; + } else { + dev_dbg(raw_dev->dev, + "%s: TG_OVRUN_ST repeated skip dump raw_id:%d\n", + __func__, raw_dev->id); + } + raw_irq_handle_tg_overrun_err(raw_dev, frame_idx_inner); + } +} + +static inline unsigned int mtk_raw_get_err_status(unsigned int irq_status) +{ + return irq_status & INT_ST_MASK_CAM_ERR; +} + +static irqreturn_t mtk_irq_raw(int irq, void *data) +{ + struct mtk_raw_device *raw_dev = (struct mtk_raw_device *)data; + struct device *dev = raw_dev->dev; + struct mtk_camsys_irq_info irq_info; + unsigned int frame_idx, frame_idx_inner, fbc_fho_ctl2; + unsigned int irq_status, err_status, dmao_done_status, dmai_done_status; + unsigned int drop_status, dma_ofl_status, cq_done_status, cq2_done_status; + bool wake_thread = 0; + + irq_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT_STAT); + dmao_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT2_STAT); + dmai_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT3_STAT); + drop_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT4_STAT); + dma_ofl_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT5_STAT); + cq_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT6_STAT); + cq2_done_status = readl_relaxed(raw_dev->base + REG_CTL_RAW_INT7_STAT); + + frame_idx = readl_relaxed(raw_dev->base + REG_FRAME_SEQ_NUM); + frame_idx_inner = readl_relaxed(raw_dev->base_inner + REG_FRAME_SEQ_NUM); + + fbc_fho_ctl2 = + readl_relaxed(REG_FBC_CTL2(raw_dev->base + FBC_R1A_BASE, 1)); + + err_status = mtk_raw_get_err_status(irq_status); + if (unlikely(debug_raw)) + dev_dbg(dev, + "INT:0x%x(err:0x%x) 2~7 0x%x/0x%x/0x%x/0x%x/0x%x/0x%x (in:%d)\n", + irq_status, err_status, + dmao_done_status, dmai_done_status, drop_status, + dma_ofl_status, cq_done_status, cq2_done_status, + frame_idx_inner); + + if (unlikely(!raw_dev->pipeline || !raw_dev->pipeline->enabled_raw)) { + dev_dbg(dev, "%s: %i: raw pipeline is disabled\n", + __func__, raw_dev->id); + goto ctx_not_found; + } + + irq_info.irq_type = 0; + irq_info.ts_ns = ktime_get_boottime_ns(); + irq_info.frame_idx = frame_idx; + irq_info.frame_idx_inner = frame_idx_inner; + + /* CQ done */ + if (cq_done_status & CAMCTL_CQ_THR0_DONE_ST) + irq_info.irq_type |= 1 << CAMSYS_IRQ_SETTING_DONE; + /* DMAO done, only for AFO */ + if (dmao_done_status & AFO_DONE_ST) + irq_info.irq_type |= 1 << CAMSYS_IRQ_AFO_DONE; + /* enable AFO_DONE_EN at backend manually */ + + /* Frame done */ + if (irq_status & SW_PASS1_DON_ST) { + irq_info.irq_type |= 1 << CAMSYS_IRQ_FRAME_DONE; + raw_dev->overrun_debug_dump_cnt = 0; + } + /* Frame start */ + if (irq_status & SOF_INT_ST) { + irq_info.irq_type |= 1 << CAMSYS_IRQ_FRAME_START; + + raw_dev->sof_count++; + irq_info.write_cnt = ((fbc_fho_ctl2 & WCNT_BIT_MASK) >> 8) - 1; + irq_info.fbc_cnt = (fbc_fho_ctl2 & CNT_BIT_MASK) >> 16; + } + /* Vsync interrupt */ + if (irq_status & VS_INT_ST) + raw_dev->vsync_count++; + + if (irq_info.irq_type && !raw_dev->is_sub) { + if (push_msgfifo(raw_dev, &irq_info) == 0) + wake_thread = 1; + } + + /* Check ISP error status */ + if (unlikely(err_status)) { + struct mtk_camsys_irq_info err_info; + + err_info.irq_type = 1 << CAMSYS_IRQ_ERROR; + err_info.ts_ns = irq_info.ts_ns; + err_info.frame_idx = irq_info.frame_idx; + err_info.frame_idx_inner = irq_info.frame_idx_inner; + err_info.e.err_status = err_status; + + if (push_msgfifo(raw_dev, &err_info) == 0) + wake_thread = 1; + } + + /* enable to debug fbc related */ + if (debug_raw && debug_dump_fbc && (irq_status & SOF_INT_ST)) + mtk_cam_raw_dump_fbc(raw_dev->dev, raw_dev->base, raw_dev->yuv_base); + +ctx_not_found: + return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED; +} + +static irqreturn_t mtk_thread_irq_raw(int irq, void *data) +{ + struct mtk_raw_device *raw_dev = (struct mtk_raw_device *)data; + struct mtk_camsys_irq_info irq_info; + + if (unlikely(atomic_cmpxchg(&raw_dev->is_fifo_overflow, 1, 0))) + dev_info(raw_dev->dev, "msg fifo overflow\n"); + + while (kfifo_len(&raw_dev->msg_fifo) >= sizeof(irq_info)) { + int len = kfifo_out(&raw_dev->msg_fifo, &irq_info, sizeof(irq_info)); + + WARN_ON(len != sizeof(irq_info)); + + dev_dbg(raw_dev->dev, "ts=%llu irq_type %d, req:%d/%d\n", + irq_info.ts_ns, irq_info.irq_type, + irq_info.frame_idx_inner, irq_info.frame_idx); + + /* error case */ + if (unlikely(irq_info.irq_type == (1 << CAMSYS_IRQ_ERROR))) { + raw_handle_error(raw_dev, &irq_info); + continue; + } + + /* normal case */ + /* inform interrupt information to camsys controller */ + mtk_camsys_isr_event(raw_dev->cam, CAMSYS_ENGINE_RAW, + raw_dev->id, &irq_info); + } + + return IRQ_HANDLED; +} + +void raw_irq_handle_tg_grab_err(struct mtk_raw_device *raw_dev, + int dequeued_frame_seq_no) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_request_stream_data *s_data; + int val, val2; + unsigned int inner_val, tg_full_sel; + + val = readl_relaxed(raw_dev->base + REG_TG_PATH_CFG); + inner_val = readl_relaxed(raw_dev->base_inner + REG_TG_PATH_CFG); + val = val | TG_TG_FULL_SEL; + writel_relaxed(val, raw_dev->base + REG_TG_PATH_CFG); + writel_relaxed(val, raw_dev->base_inner + REG_TG_PATH_CFG); + wmb(); /* make sure committed */ + val2 = readl_relaxed(raw_dev->base + REG_TG_SEN_MODE); + val2 = val2 | TG_CMOS_RDY_SEL; + writel_relaxed(val2, raw_dev->base + REG_TG_SEN_MODE); + wmb(); /* make sure committed */ + + dev_info_ratelimited(raw_dev->dev, + "%d Grab_Err [Outter] TG PATHCFG/SENMODE FRMSIZE/R GRABPXL/LIN:%x/%x %x/%x %x/%x\n", + dequeued_frame_seq_no, + readl_relaxed(raw_dev->base + REG_TG_PATH_CFG), + readl_relaxed(raw_dev->base + REG_TG_SEN_MODE), + readl_relaxed(raw_dev->base + REG_TG_FRMSIZE_ST), + readl_relaxed(raw_dev->base + REG_TG_FRMSIZE_ST_R), + readl_relaxed(raw_dev->base + REG_TG_SEN_GRAB_PXL), + readl_relaxed(raw_dev->base + REG_TG_SEN_GRAB_LIN)); + dev_info_ratelimited(raw_dev->dev, + "%d Grab_Err [Inner] TG PATHCFG/SENMODE FRMSIZE/R GRABPXL/LIN:%x/%x %x/%x %x/%x\n", + dequeued_frame_seq_no, + readl_relaxed(raw_dev->base_inner + REG_TG_PATH_CFG), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_MODE), + readl_relaxed(raw_dev->base_inner + REG_TG_FRMSIZE_ST), + readl_relaxed(raw_dev->base_inner + REG_TG_FRMSIZE_ST_R), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_GRAB_PXL), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_GRAB_LIN)); + + ctx = mtk_cam_find_ctx(raw_dev->cam, &raw_dev->pipeline->subdev.entity); + if (!ctx) { + dev_info(raw_dev->dev, "%s: cannot find ctx\n", __func__); + return; + } + + s_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, dequeued_frame_seq_no); + if (s_data) { + mtk_cam_debug_seninf_dump(s_data); + tg_full_sel = ((inner_val & TG_FULLSEL_BIT_MASK) >> 15); + + if (tg_full_sel == 1) + mtk_cam_req_dump(s_data, MTK_CAM_REQ_DUMP_CHK_DEQUEUE_FAILED, + "TG Grab Err", false); + else + dev_info(raw_dev->dev, "%s: tg_full_sel 0x%x\n", + __func__, tg_full_sel); + } else { + dev_info(raw_dev->dev, + "%s: req(%d) can't be found for seninf dump\n", + __func__, dequeued_frame_seq_no); + } +} + +void raw_irq_handle_dma_err(struct mtk_raw_device *raw_dev) +{ + mtk_cam_raw_dump_dma_err_st(raw_dev->dev, raw_dev->base); + mtk_cam_yuv_dump_dma_err_st(raw_dev->dev, raw_dev->yuv_base); + + if (raw_dev->pipeline->feature_active) + mtk_cam_dump_dma_debug(raw_dev->dev, raw_dev->base + CAMDMATOP_BASE, + "RAWI_R2", dbg_RAWI_R2, ARRAY_SIZE(dbg_RAWI_R2)); + + if (raw_dev->pipeline->pde_config.pde_info.pd_table_offset) { + dev_dbg_ratelimited(raw_dev->dev, + "DMA_ERR:%x,PDI_R1:%x,PDO_R1:%x\n", + readl_relaxed(raw_dev->base + 0x4060), + readl_relaxed(raw_dev->base + + REG_PDI_R1_BASE + + DMA_OFFSET_ERR_STAT), + readl_relaxed(raw_dev->base + + REG_PDO_R1_BASE + + DMA_OFFSET_ERR_STAT)); + dev_dbg_ratelimited(raw_dev->dev, + "TG_FRMSIZE_ST:%x,TG_FRMSIZE_ST_R:%x\n", + readl_relaxed(raw_dev->base + 0x0738), + readl_relaxed(raw_dev->base + 0x076c)); + mtk_cam_dump_dma_debug(raw_dev->dev, raw_dev->base + CAMDMATOP_BASE, + "PDO_R1", dbg_PDO_R1, ARRAY_SIZE(dbg_PDO_R1)); + mtk_cam_dump_dma_debug(raw_dev->dev, raw_dev->base + CAMDMATOP_BASE, + "PDI_R1", dbg_PDI_R1, ARRAY_SIZE(dbg_PDI_R1)); + } +} + +static void raw_irq_handle_tg_overrun_err(struct mtk_raw_device *raw_dev, + int dequeued_frame_seq_no) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_request_stream_data *s_data; + int val, val2; + unsigned int inner_val, tg_full_sel; + + val = readl_relaxed(raw_dev->base + REG_TG_PATH_CFG); + inner_val = readl_relaxed(raw_dev->base_inner + REG_TG_PATH_CFG); + val = val | TG_TG_FULL_SEL; + writel_relaxed(val, raw_dev->base + REG_TG_PATH_CFG); + writel_relaxed(val, raw_dev->base_inner + REG_TG_PATH_CFG); + wmb(); /* for dbg dump register */ + + val2 = readl_relaxed(raw_dev->base + REG_TG_SEN_MODE); + val2 = val2 | TG_CMOS_RDY_SEL; + writel_relaxed(val2, raw_dev->base + REG_TG_SEN_MODE); + wmb(); /* for dbg dump register */ + + dev_info(raw_dev->dev, + "%d Overrun_Err [Outter] TG PATHCFG/SENMODE FRMSIZE/R GRABPXL/LIN:%x/%x %x/%x %x/%x\n", + dequeued_frame_seq_no, + readl_relaxed(raw_dev->base + REG_TG_PATH_CFG), + readl_relaxed(raw_dev->base + REG_TG_SEN_MODE), + readl_relaxed(raw_dev->base + REG_TG_FRMSIZE_ST), + readl_relaxed(raw_dev->base + REG_TG_FRMSIZE_ST_R), + readl_relaxed(raw_dev->base + REG_TG_SEN_GRAB_PXL), + readl_relaxed(raw_dev->base + REG_TG_SEN_GRAB_LIN)); + dev_info(raw_dev->dev, + "%d Overrun_Err [Inner] TG PATHCFG/SENMODE FRMSIZE/R GRABPXL/LIN:%x/%x %x/%x %x/%x\n", + dequeued_frame_seq_no, + readl_relaxed(raw_dev->base_inner + REG_TG_PATH_CFG), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_MODE), + readl_relaxed(raw_dev->base_inner + REG_TG_FRMSIZE_ST), + readl_relaxed(raw_dev->base_inner + REG_TG_FRMSIZE_ST_R), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_GRAB_PXL), + readl_relaxed(raw_dev->base_inner + REG_TG_SEN_GRAB_LIN)); + dev_info(raw_dev->dev, + "REQ RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD5_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD6_REQ_STAT)); + dev_info(raw_dev->dev, + "RDY RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD5_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD6_RDY_STAT)); + dev_info(raw_dev->dev, + "REQ YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD4_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD5_REQ_STAT)); + dev_info(raw_dev->dev, + "RDY YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD4_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD5_RDY_STAT)); + + ctx = mtk_cam_find_ctx(raw_dev->cam, &raw_dev->pipeline->subdev.entity); + if (!ctx) { + dev_info(raw_dev->dev, "%s: cannot find ctx\n", __func__); + return; + } + + s_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, dequeued_frame_seq_no); + if (s_data) { + /** + * Enable the dump manually if needed. + * mtk_cam_req_dump() already call mtk_cam_seninf_dump() + * in a delayed work if no P1 done comes. + */ + if (0 && raw_dev->sof_count > 3) + mtk_cam_debug_seninf_dump(s_data); + + tg_full_sel = ((inner_val & TG_FULLSEL_BIT_MASK) >> 15); + if (tg_full_sel == 1) + mtk_cam_req_dump(s_data, MTK_CAM_REQ_DUMP_CHK_DEQUEUE_FAILED, + "TG Overrun Err", true); + else + dev_info(raw_dev->dev, "%s: tg_full_sel 0x%x:\n", + __func__, tg_full_sel); + } else { + dev_info(raw_dev->dev, "%s: req(%d) can't be found for dump\n", + __func__, dequeued_frame_seq_no); + + if (0 && raw_dev->sof_count > 3 && ctx->seninf) + mtk_cam_seninf_dump(ctx->seninf); + } +} + +static int mtk_raw_pm_suspend_prepare(struct mtk_raw_device *dev) +{ + u32 val; + int ret; + + dev_dbg(dev->dev, "- %s\n", __func__); + + if (pm_runtime_suspended(dev->dev)) + return 0; + + /* Disable ISP's view finder and wait for TG idle */ + dev_dbg(dev->dev, "cam suspend, disable VF\n"); + val = readl(dev->base + REG_TG_VF_CON); + writel(val & (~TG_VFDATA_EN), dev->base + REG_TG_VF_CON); + ret = readl_poll_timeout_atomic(dev->base + REG_TG_INTER_ST, val, + (val & TG_CAM_CS_MASK) == TG_IDLE_ST, + USEC_PER_MSEC, MTK_RAW_STOP_HW_TIMEOUT); + if (ret) + dev_dbg(dev->dev, "can't stop HW:%d:0x%x\n", ret, val); + + /* Disable CMOS */ + val = readl(dev->base + REG_TG_SEN_MODE); + writel(val & (~TG_SEN_MODE_CMOS_EN), dev->base + REG_TG_SEN_MODE); + + /* Force ISP HW to idle */ + ret = pm_runtime_force_suspend(dev->dev); + return ret; +} + +static int mtk_raw_pm_post_suspend(struct mtk_raw_device *dev) +{ + u32 val; + int ret; + + dev_dbg(dev->dev, "- %s\n", __func__); + + if (pm_runtime_suspended(dev->dev)) + return 0; + + /* Force ISP HW to resume */ + ret = pm_runtime_force_resume(dev->dev); + if (ret) + return ret; + + /* Enable CMOS */ + dev_dbg(dev->dev, "cam resume, enable CMOS/VF\n"); + val = readl(dev->base + REG_TG_SEN_MODE); + writel(val | TG_SEN_MODE_CMOS_EN, dev->base + REG_TG_SEN_MODE); + + /* Enable VF */ + val = readl(dev->base + REG_TG_VF_CON); + writel(val | TG_VFDATA_EN, dev->base + REG_TG_VF_CON); + + return 0; +} + +static int raw_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct mtk_raw_device *raw_dev = + container_of(nb, struct mtk_raw_device, pm_notifier); + + switch (action) { + case PM_SUSPEND_PREPARE: + mtk_raw_pm_suspend_prepare(raw_dev); + break; + case PM_POST_SUSPEND: + mtk_raw_pm_post_suspend(raw_dev); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static int mtk_raw_of_probe(struct platform_device *pdev, + struct mtk_raw_device *raw) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + int n_clks; + + ret = of_property_read_u32(dev->of_node, "mediatek,cam-id", &raw->id); + if (ret) { + dev_dbg(dev, "missing camid property\n"); + return ret; + } + + if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) { + dev_err(dev, "%s: No suitable DMA available\n", __func__); + return -EIO; + } + + if (!dev->dma_parms) { + dev->dma_parms = + devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + + dma_set_max_seg_size(dev, UINT_MAX); + + /* base outer register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base"); + if (!res) { + dev_err(dev, "failed to get mem\n"); + return -ENODEV; + } + + raw->base = devm_ioremap_resource(dev, res); + if (IS_ERR(raw->base)) { + dev_err(dev, "failed to map register base\n"); + return PTR_ERR(raw->base); + } + + /* base inner register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "inner_base"); + if (!res) { + dev_err(dev, "failed to get mem\n"); + return -ENODEV; + } + + raw->base_inner = devm_ioremap_resource(dev, res); + if (IS_ERR(raw->base_inner)) { + dev_err(dev, "failed to map register inner base\n"); + return PTR_ERR(raw->base_inner); + } + + /* will be assigned later */ + raw->yuv_base = NULL; + + raw->irq = platform_get_irq(pdev, 0); + if (raw->irq < 0) { + dev_err(dev, "failed to get irq\n"); + return -ENODEV; + } + + ret = devm_request_threaded_irq(dev, raw->irq, + mtk_irq_raw, mtk_thread_irq_raw, + 0, dev_name(dev), raw); + if (ret) { + dev_err(dev, "failed to request irq=%d\n", raw->irq); + return ret; + } + dev_dbg(dev, "registered irq=%d\n", raw->irq); + + disable_irq(raw->irq); + + n_clks = devm_clk_bulk_get_all(dev, &raw->clk_b); + if (n_clks < 0) { + dev_err(dev, "failed to devm_clk_bulk_get_all=%d\n", n_clks); + return n_clks; + } + + raw->num_clks = n_clks; + dev_info(dev, "clk_num:%d\n", raw->num_clks); + +#ifdef CONFIG_PM_SLEEP + raw->pm_notifier.notifier_call = raw_pm_notifier; + ret = register_pm_notifier(&raw->pm_notifier); + if (ret) { + dev_info(dev, "failed to register notifier block.\n"); + return ret; + } +#endif + return 0; +} + +static int mtk_raw_sd_subscribe_event(struct v4l2_subdev *subdev, + struct v4l2_fh *fh, + struct v4l2_event_subscription *sub) +{ + switch (sub->type) { + case V4L2_EVENT_FRAME_SYNC: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_REQUEST_DRAINED: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_EOS: + return v4l2_event_subscribe(fh, sub, 0, NULL); + case V4L2_EVENT_REQUEST_DUMPED: + return v4l2_event_subscribe(fh, sub, 0, NULL); + default: + return -EINVAL; + } +} + +static int mtk_raw_available_resource(struct mtk_raw *raw) +{ + struct device *dev = raw->cam_dev; + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + int res_status = 0; + int i, j; + + for (i = 0; i < cam_dev->num_raw_devices; i++) { + struct mtk_raw_pipeline *pipe = raw->pipelines + i; + + for (j = 0; j < ARRAY_SIZE(raw->devs); j++) { + if (pipe->enabled_raw & 1 << j) + res_status |= 1 << j; + } + } + dev_dbg(raw->cam_dev, + "%s raw_status:0x%x Available Engine:A/B/C:%d/%d/%d\n", + __func__, res_status, + !(res_status & (1 << MTKCAM_SUBDEV_RAW_0)), + !(res_status & (1 << MTKCAM_SUBDEV_RAW_1)), + !(res_status & (1 << MTKCAM_SUBDEV_RAW_2))); + + return res_status; +} + +int mtk_cam_s_data_raw_select(struct mtk_cam_request_stream_data *s_data, + struct mtkcam_ipi_input_param *cfg_in_param) +{ + struct mtk_cam_ctx *ctx; + struct mtk_raw_pipeline *pipe; + int raw_status = 0; + bool selected = false; + + ctx = mtk_cam_s_data_get_ctx(s_data); + pipe = ctx->pipe; + raw_status = mtk_raw_available_resource(pipe->raw); + raw_status &= ~pipe->enabled_raw; + + mtk_raw_available_resource(pipe->raw); + + if (!selected) + return -EINVAL; + + return 0; +} + +int mtk_cam_raw_select(struct mtk_cam_ctx *ctx, + struct mtkcam_ipi_input_param *cfg_in_param) +{ + struct mtk_raw_pipeline *pipe = ctx->pipe; + int raw_status = 0; + int mask = 0x0; + bool selected = false; + int m; + + pipe->enabled_raw = 0; + raw_status = mtk_raw_available_resource(pipe->raw); + if (pipe->res_config.raw_num_used == 3) { + mask = 1 << MTKCAM_SUBDEV_RAW_0 + | 1 << MTKCAM_SUBDEV_RAW_1 | 1 << MTKCAM_SUBDEV_RAW_2; + if (!(raw_status & mask)) { + pipe->enabled_raw |= mask; + selected = true; + } + } else if (pipe->res_config.raw_num_used == 2) { + for (m = MTKCAM_SUBDEV_RAW_0; m >= MTKCAM_SUBDEV_RAW_0; m--) { + mask = (1 << m) | (1 << (m + 1)); + if (!(raw_status & mask)) { + pipe->enabled_raw |= mask; + selected = true; + break; + } + } + } else { + for (m = MTKCAM_SUBDEV_RAW_0; m < ARRAY_SIZE(pipe->raw->devs); m++) { + mask = 1 << m; + if (!(raw_status & mask)) { + pipe->enabled_raw |= mask; + selected = true; + break; + } + } + } + mtk_raw_available_resource(pipe->raw); + if (!selected) + return -EINVAL; + + return 0; +} + +static int mtk_raw_sd_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct mtk_raw_pipeline *pipe; + struct mtk_raw *raw; + struct mtk_cam_device *cam; + struct mtk_cam_ctx *ctx; + unsigned int i; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + raw = pipe->raw; + if (!raw) + return -1; + cam = dev_get_drvdata(raw->cam_dev); + ctx = mtk_cam_find_ctx(cam, &sd->entity); + + if (WARN_ON(!ctx)) + return -EINVAL; + + if (enable) { + pipe->feature_active = pipe->user_res.raw_res.feature; + pipe->enabled_dmas = 0; + ctx->pipe = pipe; + ctx->used_raw_num++; + pipe->feature_active = pipe->user_res.raw_res.feature; + for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++) { + if (!pipe->vdev_nodes[i].enabled) + continue; + pipe->enabled_dmas |= + (1ULL << pipe->vdev_nodes[i].desc.dma_port); + } + } else { + for (i = 0; i < ARRAY_SIZE(raw->devs); i++) { + if (pipe->enabled_raw & 1 << i) { + dev_info(raw->cam_dev, "%s: power off raw (%d)\n", + __func__, i); + pm_runtime_put_sync(raw->devs[i]); + } + } + } + + dev_info(raw->cam_dev, "%s:raw-%d: en %d, dev 0x%x dmas 0x%lx\n", + __func__, pipe->id, enable, pipe->enabled_raw, + pipe->enabled_dmas); + + return 0; +} + +static int mtk_raw_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state) +{ + struct v4l2_mbus_framefmt *mf; + unsigned int i; + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + + for (i = 0; i < sd->entity.num_pads; i++) { + mf = v4l2_subdev_state_get_format(sd_state, i); + *mf = mfmt_default; + + dev_dbg(raw->cam_dev, "%s init pad:%d format:0x%x\n", + sd->name, i, mf->code); + } + + return 0; +} + +static bool mtk_raw_try_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_format *fmt) +{ + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + unsigned int user_fmt = mtk_cam_get_sensor_fmt(fmt->format.code); + + dev_dbg(raw->cam_dev, "%s:s_fmt: check format 0x%x, w:%d, h:%d field:%d\n", + sd->name, fmt->format.code, fmt->format.width, + fmt->format.height, fmt->format.field); + + /* check sensor format */ + if (fmt->pad == MTK_RAW_SINK) { + user_fmt = mtk_cam_get_sensor_fmt(fmt->format.code); + if (user_fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN) + return false; + } + + return true; +} + +static struct v4l2_mbus_framefmt * +mtk_raw_pipeline_get_fmt(struct mtk_raw_pipeline *pipe, + struct v4l2_subdev_state *sd_state, u32 padid, + int which) +{ + struct mtk_raw *raw = pipe->raw; + + if (padid >= MTK_RAW_PIPELINE_PADS_NUM) { + dev_err(raw->cam_dev, "Wrong pad id:%d\n", padid); + return NULL; + } + /* format invalid and return default format */ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_state_get_format(sd_state, padid); + + if (WARN_ON(padid >= pipe->subdev.entity.num_pads)) + return &pipe->cfg[0].mbus_fmt; + + return &pipe->cfg[padid].mbus_fmt; +} + +static struct v4l2_rect * +mtk_raw_pipeline_get_selection(struct mtk_raw_pipeline *pipe, + struct v4l2_subdev_state *sd_state, u32 pad, + int which) +{ + struct mtk_raw *raw = pipe->raw; + + if (pad >= MTK_RAW_PIPELINE_PADS_NUM) { + dev_err(raw->cam_dev, "Wrong pad id:%d\n", pad); + return NULL; + } + /* format invalid and return default format */ + if (which == V4L2_SUBDEV_FORMAT_TRY) + return v4l2_subdev_state_get_crop(sd_state, pad); + + if (WARN_ON(pad >= pipe->subdev.entity.num_pads)) + return &pipe->cfg[0].crop; + + return &pipe->cfg[pad].crop; +} + +static void propagate_fmt(struct v4l2_mbus_framefmt *sink_mf, + struct v4l2_mbus_framefmt *source_mf, int w, int h) +{ + source_mf->code = sink_mf->code; + source_mf->colorspace = sink_mf->colorspace; + source_mf->field = sink_mf->field; + source_mf->width = w; + source_mf->height = h; +} + +static bool mtk_raw_fmt_get_res(struct v4l2_subdev *sd, + struct v4l2_subdev_format *fmt, + struct mtk_cam_resource *res) +{ + void *user_ptr; + u64 addr; + + addr = ((u64)fmt->reserved[1] << 32) | fmt->reserved[2]; + user_ptr = (void *)addr; + if (!user_ptr) { + dev_info(sd->v4l2_dev->dev, "%s: mtk_cam_resource is null\n", + __func__); + return false; + } + + if (copy_from_user(res, (void __user *)user_ptr, sizeof(*res))) { + dev_info(sd->v4l2_dev->dev, + "%s: copy_from_user failedm user_ptr:%p\n", + __func__, user_ptr); + return false; + } + + dev_dbg(sd->v4l2_dev->dev, + "%s:sensor:%d/%d/%lld/%d/%d, raw:%lld/%d/%d/%d/%d/%d/%d/%d/%lld\n", + __func__, + res->sensor_res.hblank, res->sensor_res.vblank, + res->sensor_res.pixel_rate, res->sensor_res.interval.denominator, + res->sensor_res.interval.numerator, + res->raw_res.feature, res->raw_res.bin, res->raw_res.path_sel, + res->raw_res.raw_max, res->raw_res.raw_min, res->raw_res.raw_used, + res->raw_res.strategy, res->raw_res.pixel_mode, + res->raw_res.throughput); + + return res; +} + +static int mtk_raw_set_src_pad_selection_default(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) +{ + struct v4l2_rect *source_sel; + struct mtk_raw_pipeline *pipe; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + source_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which); + if (source_sel->width > sink_fmt->width) + source_sel->width = sink_fmt->width; + + if (source_sel->height > sink_fmt->height) + source_sel->height = sink_fmt->height; + + return 0; +} + +static int mtk_raw_set_src_pad_selection_yuv(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) +{ + int i; + struct v4l2_rect *prev_yuv = NULL, *source_sel, *tmp_sel; + struct v4l2_mbus_framefmt *framefmt; + struct mtk_raw_pipeline *pipe; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + mtk_raw_set_src_pad_selection_default(sd, sd_state, sink_fmt, res, pad, which); + source_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which); + + for (i = MTK_RAW_YUVO_1_OUT; i < pad; i++) { + framefmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which); + tmp_sel = mtk_raw_pipeline_get_selection(pipe, sd_state, pad, which); + + /* Skip disabled YUV pad */ + if (!mtk_cam_is_pad_fmt_enable(framefmt)) + continue; + + prev_yuv = tmp_sel; + } + + if (prev_yuv) { + if (source_sel->width != prev_yuv->width) { + source_sel->width = prev_yuv->width; + dev_dbg(sd->v4l2_dev->dev, "%s: prev width:%d", + __func__, source_sel->width); + } + + if (source_sel->height != prev_yuv->height) { + source_sel->height = prev_yuv->height; + dev_dbg(sd->v4l2_dev->dev, "%s: prev height:%d", + __func__, source_sel->height); + } + } + + return 0; +} + +static struct v4l2_mbus_framefmt * +mtk_raw_get_sink_pad_framefmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, int which) +{ + struct v4l2_mbus_framefmt *sink_fmt = NULL, *tmp_fmt; + struct mtk_raw_pipeline *pipe; + int i; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + for (i = MTK_RAW_SINK; i < MTK_RAW_SOURCE_BEGIN; i++) { + tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, i, which); + if (i != MTK_RAW_META_IN && mtk_cam_is_pad_fmt_enable(tmp_fmt)) { + sink_fmt = tmp_fmt; + break; + } + } + + return sink_fmt; +} + +static int mtk_raw_set_pad_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + struct v4l2_mbus_framefmt *sink_fmt; + struct mtk_raw_pipeline *pipe; + struct mtk_cam_video_device *node; + struct mtk_cam_resource *res = NULL; + struct v4l2_rect *crop; + int ret; + + if (sel->pad < MTK_RAW_MAIN_STREAM_OUT || + sel->pad >= MTK_RAW_META_OUT_BEGIN) + return -EINVAL; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + + /* The crop rectangle can't be changed while streaming. */ + if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && + !media_entity_is_streaming(&sd->entity)) + return -EBUSY; + + /* + * Find the sink pad fmt, there must be one eanbled sink pad at least + */ + sink_fmt = mtk_raw_get_sink_pad_framefmt(sd, sd_state, sel->which); + if (!sink_fmt) + return -EINVAL; + + node = &pipe->vdev_nodes[sel->pad - MTK_RAW_SINK_NUM]; + crop = mtk_raw_pipeline_get_selection(pipe, sd_state, sel->pad, sel->which); + if (!crop) + return -EINVAL; + + *crop = sel->r; + ret = node->desc.pad_ops->set_pad_selection(sd, sd_state, sink_fmt, + res, sel->pad, sel->which); + if (ret) + return -EINVAL; + + sel->r = *crop; + + return 0; +} + +static int mtk_raw_get_pad_selection(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_selection *sel) +{ + struct mtk_raw_pipeline *pipe; + struct v4l2_rect *crop; + + if (sel->pad < MTK_RAW_MAIN_STREAM_OUT || + sel->pad >= MTK_RAW_META_OUT_BEGIN) + return -EINVAL; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + crop = mtk_raw_pipeline_get_selection(pipe, sd_state, sel->pad, sel->which); + if (!crop) + return -EINVAL; + + sel->r = *crop; + + return 0; +} + +static int mtk_raw_set_sink_pad_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct device *dev; + struct mtk_cam_video_device *node; + const char *node_str; + const struct mtk_cam_format_desc *fmt_desc; + struct mtk_raw_pipeline *pipe; + int i; + int ipi_fmt; + struct v4l2_mbus_framefmt *framefmt, *source_fmt = NULL, *tmp_fmt; + + /* Do nothing for pad to meta video device */ + if (fmt->pad == MTK_RAW_META_IN) + return 0; + + dev = sd->v4l2_dev->dev; + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + framefmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which); + + /* If data from sensor, we check the size with max imgo size*/ + if (fmt->pad < MTK_RAW_SINK_NUM) { + /* from sensor */ + node = &pipe->vdev_nodes[MTK_RAW_MAIN_STREAM_OUT - MTK_RAW_SINK_NUM]; + node_str = "sink"; + } else { + /* from memory */ + node = &pipe->vdev_nodes[fmt->pad - MTK_RAW_SINK_NUM]; + node_str = node->desc.name; + } + + ipi_fmt = mtk_cam_get_sensor_fmt(framefmt->code); + if (ipi_fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN) { + /** + * Set imgo's default fmt, the user must check + * if the pad sink format is the same as the + * source format of the link before stream on. + */ + fmt_desc = &node->desc.fmts[node->desc.default_fmt_idx]; + framefmt->code = fmt_desc->pfmt.code; + dev_info(dev, + "%s(%d): Adjust unaccept fmt code on sink pad:%d, 0x%x->0x%x\n", + __func__, fmt->which, fmt->pad, fmt->format.code, framefmt->code); + } + + /* Reset pads' enable state*/ + for (i = MTK_RAW_SINK; i < MTK_RAW_META_OUT_BEGIN; i++) { + if (i == MTK_RAW_META_IN) + continue; + tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, i, fmt->which); + mtk_cam_pad_fmt_disable(tmp_fmt); + } + + *framefmt = fmt->format; + if (framefmt->width > node->desc.frmsizes->stepwise.max_width) + framefmt->width = node->desc.frmsizes->stepwise.max_width; + + if (framefmt->height > node->desc.frmsizes->stepwise.max_height) + framefmt->height = node->desc.frmsizes->stepwise.max_height; + + mtk_cam_pad_fmt_enable(framefmt); + + dev_info(dev, + "%s(%d): Set fmt pad:%d(%s), code/w/h = 0x%x/%d/%d\n", + __func__, fmt->which, fmt->pad, node_str, + framefmt->code, framefmt->width, framefmt->height); + + /* Propagation inside subdev */ + for (i = MTK_RAW_SOURCE_BEGIN; i < MTK_RAW_META_OUT_BEGIN; i++) { + source_fmt = + mtk_raw_pipeline_get_fmt(pipe, sd_state, i, fmt->which); + + /* Get default format's desc for the pad */ + node = &pipe->vdev_nodes[i - MTK_RAW_SINK_NUM]; + + /** + * Propagate the size from sink pad to source pades, adjusted + * based on each pad's default format. + */ + if (source_fmt->width > node->desc.frmsizes->stepwise.max_width) + source_fmt->width = node->desc.frmsizes->stepwise.max_width; + else + source_fmt->width = framefmt->width; + + if (source_fmt->height > node->desc.frmsizes->stepwise.max_height) + source_fmt->height = node->desc.frmsizes->stepwise.max_height; + else + source_fmt->height = framefmt->height; + + dev_dbg(dev, + "%s(%d): Propagate to pad:%d(%s), (0x%x/%d/%d)\n", + __func__, fmt->which, fmt->pad, node->desc.name, + source_fmt->code, source_fmt->width, source_fmt->height); + } + + return 0; +} + +static int mtk_raw_set_src_pad_fmt_default(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) +{ + struct device *dev; + struct v4l2_mbus_framefmt *source_fmt; + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_cam_video_device *node; + + dev = sd->v4l2_dev->dev; + node = &pipe->vdev_nodes[pad - MTK_RAW_SINK_NUM]; + source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which); + if (source_fmt->width > sink_fmt->width) { + dev_info(dev, + "%s(%d): adjusted: width(%d) over sink (%d)\n", + __func__, which, source_fmt->width, sink_fmt->width); + source_fmt->width = sink_fmt->width; + } + + if (source_fmt->height > sink_fmt->height) { + dev_info(dev, + "%s(%d): adjusted: width(%d) over sink (%d)\n", + __func__, which, source_fmt->height, sink_fmt->height); + source_fmt->height = sink_fmt->height; + } + + if (source_fmt->width > node->desc.frmsizes->stepwise.max_width) { + dev_info(dev, + "%s(%d): adjusted: width(%d) over max (%d)\n", + __func__, which, source_fmt->width, + node->desc.frmsizes->stepwise.max_width); + source_fmt->width = node->desc.frmsizes->stepwise.max_width; + } + + if (source_fmt->height > node->desc.frmsizes->stepwise.max_height) { + dev_info(dev, + "%s(%d): adjusted: height(%d) over max (%d)\n", + __func__, which, source_fmt->height, + node->desc.frmsizes->stepwise.max_height); + } + + return 0; +} + +static int mtk_raw_set_src_pad_fmt_rzh1n2(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) +{ + struct device *dev; + struct v4l2_mbus_framefmt *source_fmt; + struct v4l2_mbus_framefmt *tmp_fmt; + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + + dev = sd->v4l2_dev->dev; + mtk_raw_set_src_pad_fmt_default(sd, sd_state, sink_fmt, res, pad, which); + source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, pad, which); + + /* rzh1n2to_r1 and rzh1n2to_r3 size must be the same */ + if (pad == MTK_RAW_RZH1N2TO_3_OUT) { + tmp_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, + MTK_RAW_RZH1N2TO_1_OUT, which); + if (mtk_cam_is_pad_fmt_enable(tmp_fmt) && + source_fmt->height != tmp_fmt->height && + source_fmt->width != tmp_fmt->width) { + dev_info(dev, + "%s(%d): adjusted: rzh1n2to_r3(%d,%d) and rzh1n2to_r1(%d,%d) must have the same sz\n", + __func__, which, + source_fmt->width, source_fmt->height, + tmp_fmt->width, tmp_fmt->height); + + source_fmt->width = tmp_fmt->width; + source_fmt->height = tmp_fmt->height; + } + } + + return 0; +} + +static int mtk_raw_set_src_pad_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct device *dev; + struct mtk_cam_resource res; + struct mtk_cam_video_device *node; + struct mtk_raw_pipeline *pipe; + int ret = 0; + struct v4l2_mbus_framefmt *source_fmt, *sink_fmt; + + /* Do nothing for pad to meta video device */ + if (fmt->pad >= MTK_RAW_META_OUT_BEGIN) + return 0; + + pipe = container_of(sd, struct mtk_raw_pipeline, subdev); + dev = sd->v4l2_dev->dev; + node = &pipe->vdev_nodes[fmt->pad - MTK_RAW_SINK_NUM]; + + /* + * Find the sink pad fmt, there must be one eanbled sink pad at least + */ + sink_fmt = mtk_raw_get_sink_pad_framefmt(sd, sd_state, fmt->which); + if (!sink_fmt) { + dev_info(dev, + "%s(%d): Set fmt pad:%d(%s), no s_fmt on sink pad\n", + __func__, fmt->which, fmt->pad, node->desc.name); + return -EINVAL; + } + + if (!mtk_raw_fmt_get_res(sd, fmt, &res)) { + dev_info(dev, + "%s(%d): Set fmt pad:%d(%s), no mtk_cam_resource found\n", + __func__, fmt->which, fmt->pad, node->desc.name); + return -EINVAL; + } + + if (node->desc.pad_ops->set_pad_fmt) { + /* call source pad's set_pad_fmt op to adjust fmt by pad */ + source_fmt = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, + fmt->which); + + *source_fmt = fmt->format; + ret = node->desc.pad_ops->set_pad_fmt(sd, sd_state, sink_fmt, + &res, fmt->pad, fmt->which); + } + + if (ret) + return ret; + + if (!source_fmt) { + dev_info(dev, + "%s(%d): Set fmt pad:%d(%s), no s_fmt on source pad\n", + __func__, fmt->which, fmt->pad, node->desc.name); + return -EINVAL; + } + + dev_dbg(dev, + "%s(%d): s_fmt to pad:%d(%s), user(0x%x/%d/%d) driver(0x%x/%d/%d)\n", + __func__, fmt->which, fmt->pad, node->desc.name, + fmt->format.code, fmt->format.width, fmt->format.height, + source_fmt->code, source_fmt->width, source_fmt->height); + mtk_cam_pad_fmt_disable(source_fmt); + fmt->format = *source_fmt; + + return 0; +} + +static int mtk_raw_try_pad_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + if (fmt->pad >= MTK_RAW_SINK && fmt->pad < MTK_RAW_SOURCE_BEGIN) + mtk_raw_set_sink_pad_fmt(sd, sd_state, fmt); + else if (fmt->pad < MTK_RAW_PIPELINE_PADS_NUM) + mtk_raw_set_src_pad_fmt(sd, sd_state, fmt); + else + return -EINVAL; + + return 0; +} + +static int mtk_raw_call_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt, + bool streaming) +{ + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + struct v4l2_mbus_framefmt *mf; + + if (!sd || !fmt) { + dev_dbg(raw->cam_dev, "%s: Required sd(%p), fmt(%p)\n", + __func__, sd, fmt); + return -EINVAL; + } + + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY && !sd_state) { + dev_dbg(raw->cam_dev, + "%s: Required sd(%p), cfg(%p) for FORMAT_TRY\n", + __func__, sd, sd_state); + return -EINVAL; + } + + if (!mtk_raw_try_fmt(sd, fmt) && + !mtk_cam_feature_is_pure_m2m(pipe->feature_pending)) { + mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which); + fmt->format = *mf; + dev_info(raw->cam_dev, + "sd:%s pad:%d didn't apply and keep format w/h/code %d/%d/0x%x\n", + sd->name, fmt->pad, mf->width, mf->height, mf->code); + } else { + mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which); + *mf = fmt->format; + dev_dbg(raw->cam_dev, + "sd:%s pad:%d set format w/h/code %d/%d/0x%x\n", + sd->name, fmt->pad, mf->width, mf->height, mf->code); + } + + /*sink pad format propagate to source pad*/ + if (fmt->pad == MTK_RAW_SINK) { + struct v4l2_mbus_framefmt *source_mf; + + source_mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, + MTK_RAW_MAIN_STREAM_OUT, + fmt->which); + + if (streaming) { + propagate_fmt(mf, source_mf, mf->width, mf->height); + return 0; + } + + /** + * User will trigger resource calc + * with V4L2_CID_MTK_CAM_RAW_RESOURCE_CALC + * so we don't need to trigger it here anymore. + */ + propagate_fmt(mf, source_mf, mf->width, mf->height); + } + + return 0; +} + +static int mtk_raw_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) + return mtk_raw_try_pad_fmt(sd, sd_state, fmt); + + /* The format can't be changed while streaming. */ + if (!media_entity_is_streaming(&sd->entity)) + return mtk_raw_call_set_fmt(sd, sd_state, fmt, false); + + dev_info(sd->v4l2_dev->dev, + "Pipeline is streaming, cannot change format\n"); + return -EBUSY; +} + +static int mtk_raw_get_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *fmt) +{ + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + struct v4l2_mbus_framefmt *mf; + + mf = mtk_raw_pipeline_get_fmt(pipe, sd_state, fmt->pad, fmt->which); + fmt->format = *mf; + dev_dbg(raw->cam_dev, "sd:%s pad:%d get format w/h/code %d/%d/0x%x\n", + sd->name, fmt->pad, fmt->format.width, fmt->format.height, + fmt->format.code); + + return 0; +} + +static int mtk_cam_media_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct mtk_raw_pipeline *pipe = + container_of(entity, struct mtk_raw_pipeline, subdev.entity); + struct mtk_raw *raw = pipe->raw; + u32 pad = local->index; + + dev_dbg(raw->cam_dev, + "%s: raw %d: remote:%s:%d->local:%s:%d flags:0x%x\n", + __func__, pipe->id, remote->entity->name, remote->index, + local->entity->name, local->index, flags); + + if (pad < MTK_RAW_PIPELINE_PADS_NUM && pad != MTK_RAW_SINK) + pipe->vdev_nodes[pad - MTK_RAW_SINK_NUM].enabled = + !!(flags & MEDIA_LNK_FL_ENABLED); + + if (!media_entity_is_streaming(entity) && !(flags & MEDIA_LNK_FL_ENABLED)) + memset(pipe->cfg, 0, sizeof(pipe->cfg)); + + if (pad == MTK_RAW_SINK && flags & MEDIA_LNK_FL_ENABLED) + pipe->res_config.seninf = + media_entity_to_v4l2_subdev(remote->entity); + + return 0; +} + +static int mtk_raw_set_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval *fi) +{ + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + + dev_dbg(raw->cam_dev, "%s:pipe(%d):current res: fps = %d/%d", + __func__, pipe->id, + fi->interval.numerator, fi->interval.denominator); + pipe->res_config.interval = fi->interval; + + return 0; +} + +static int mtk_raw_get_frame_interval(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_frame_interval *fi) +{ + struct mtk_raw_pipeline *pipe = + container_of(sd, struct mtk_raw_pipeline, subdev); + struct mtk_raw *raw = pipe->raw; + + dev_dbg(raw->cam_dev, "%s:pipe(%d):current res: fps = %d/%d", + __func__, pipe->id, + fi->interval.numerator, fi->interval.denominator); + fi->interval = pipe->res_config.interval; + + return 0; +} + +static const struct v4l2_subdev_core_ops mtk_raw_subdev_core_ops = { + .subscribe_event = mtk_raw_sd_subscribe_event, + .unsubscribe_event = v4l2_event_subdev_unsubscribe, +}; + +static const struct v4l2_subdev_video_ops mtk_raw_subdev_video_ops = { + .s_stream = mtk_raw_sd_s_stream, +}; + +static const struct v4l2_subdev_pad_ops mtk_raw_subdev_pad_ops = { + .link_validate = mtk_cam_link_validate, + .set_fmt = mtk_raw_set_fmt, + .get_fmt = mtk_raw_get_fmt, + .set_selection = mtk_raw_set_pad_selection, + .get_selection = mtk_raw_get_pad_selection, + .set_frame_interval = mtk_raw_set_frame_interval, + .get_frame_interval = mtk_raw_get_frame_interval, +}; + +static const struct v4l2_subdev_internal_ops mtk_raw_subdev_internal_ops = { + .init_state = mtk_raw_init_state, +}; + +static const struct v4l2_subdev_ops mtk_raw_subdev_ops = { + .core = &mtk_raw_subdev_core_ops, + .video = &mtk_raw_subdev_video_ops, + .pad = &mtk_raw_subdev_pad_ops, +}; + +static const struct media_entity_operations mtk_cam_media_entity_ops = { + .link_setup = mtk_cam_media_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +static const struct v4l2_ioctl_ops mtk_cam_v4l2_vout_ioctl_ops = { + .vidioc_querycap = mtk_cam_vidioc_querycap, + .vidioc_enum_framesizes = mtk_cam_vidioc_enum_framesizes, + .vidioc_enum_fmt_vid_out = mtk_cam_vidioc_enum_fmt, + .vidioc_g_fmt_vid_out_mplane = mtk_cam_vidioc_g_fmt, + .vidioc_s_fmt_vid_out_mplane = mtk_cam_vidioc_s_fmt, + .vidioc_try_fmt_vid_out_mplane = mtk_cam_vidioc_try_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_ioctl_ops mtk_cam_v4l2_vcap_ioctl_ops = { + .vidioc_querycap = mtk_cam_vidioc_querycap, + .vidioc_enum_framesizes = mtk_cam_vidioc_enum_framesizes, + .vidioc_enum_fmt_vid_cap = mtk_cam_vidioc_enum_fmt, + .vidioc_g_fmt_vid_cap_mplane = mtk_cam_vidioc_g_fmt, + .vidioc_s_fmt_vid_cap_mplane = mtk_cam_vidioc_s_fmt, + .vidioc_try_fmt_vid_cap_mplane = mtk_cam_vidioc_try_fmt, + .vidioc_s_selection = mtk_cam_vidioc_s_selection, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, +}; + +static const struct v4l2_ioctl_ops mtk_cam_v4l2_meta_cap_ioctl_ops = { + .vidioc_querycap = mtk_cam_vidioc_querycap, + .vidioc_enum_fmt_meta_cap = mtk_cam_vidioc_meta_enum_fmt, + .vidioc_g_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt, + .vidioc_s_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt, + .vidioc_try_fmt_meta_cap = mtk_cam_vidioc_g_meta_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, +}; + +static const struct v4l2_ioctl_ops mtk_cam_v4l2_meta_out_ioctl_ops = { + .vidioc_querycap = mtk_cam_vidioc_querycap, + .vidioc_enum_fmt_meta_out = mtk_cam_vidioc_meta_enum_fmt, + .vidioc_g_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt, + .vidioc_s_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt, + .vidioc_try_fmt_meta_out = mtk_cam_vidioc_g_meta_fmt, + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_expbuf = vb2_ioctl_expbuf, +}; + +static const struct mtk_cam_format_desc stream_out_fmts[] = { + /* This is a default image format */ + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR8, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SBGGR10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SBGGR10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SBGGR10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SBGGR12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SBGGR12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SBGGR12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SBGGR14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SBGGR14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SBGGR14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG8, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGBRG10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGBRG10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGBRG10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGBRG12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGBRG12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGBRG12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGBRG14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGBRG14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGBRG14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG8, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGRBG10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRBG10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGRBG10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGRBG12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRBG12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGRBG12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGRBG14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRBG14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SGRBG14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB8, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SRGGB10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SRGGB10, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SRGGB10_1X10, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB10P, + }, + }, + + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SRGGB12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SRGGB12, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SRGGB12_1X12, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SRGGB14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SRGGB14, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_MTISP_SRGGB14_1X14, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SBGGR16, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SBGGR16_1X16, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGBRG16, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGBRG16_1X16, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SGRBG16, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SGRBG16_1X16, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_SRGGB16, + .num_planes = 1, + }, + .pfmt = { + .code = MEDIA_BUS_FMT_SRGGB16_1X16, + } + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_BAYER8_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_BAYER10_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_BAYER12_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = IMG_MAX_WIDTH, + .height = IMG_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_BAYER14_UFBC, + }, + }, +}; + +static const struct mtk_cam_format_desc yuv_out_group1_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12_12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21_12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_12P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_12P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUV420, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_10_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_10_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_12_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_12_UFBC, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRB8F, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRB10F, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP1_MAX_WIDTH, + .height = YUV_GROUP1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_SGRB12F, + }, + } +}; + +static const struct mtk_cam_format_desc yuv_out_group2_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12_12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21_12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_12P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = YUV_GROUP2_MAX_WIDTH, + .height = YUV_GROUP2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_12P, + }, + } +}; + +static const struct mtk_cam_format_desc rzh1n2to1_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO1_MAX_WIDTH, + .height = RZH1N2TO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO1_MAX_WIDTH, + .height = RZH1N2TO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO1_MAX_WIDTH, + .height = RZH1N2TO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV16, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO1_MAX_WIDTH, + .height = RZH1N2TO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV61, + }, + } +}; + +static const struct mtk_cam_format_desc rzh1n2to2_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO2_MAX_WIDTH, + .height = RZH1N2TO2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YUYV, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO2_MAX_WIDTH, + .height = RZH1N2TO2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_YVYU, + }, + } +}; + +static const struct mtk_cam_format_desc rzh1n2to3_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO3_MAX_WIDTH, + .height = RZH1N2TO3_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO3_MAX_WIDTH, + .height = RZH1N2TO3_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO3_MAX_WIDTH, + .height = RZH1N2TO3_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV16, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = RZH1N2TO3_MAX_WIDTH, + .height = RZH1N2TO3_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV61, + }, + } +}; + +static const struct mtk_cam_format_desc drzs4no1_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_GREY, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV16, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV61, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV16_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV61_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV16_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV61_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV12_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_NV21_10, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV12_10P, + }, + }, + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO1_MAX_WIDTH, + .height = DRZS4NO1_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_MTISP_NV21_10P, + }, + }, +}; + +static const struct mtk_cam_format_desc drzs4no2_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO2_MAX_WIDTH, + .height = DRZS4NO2_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_GREY, + }, + } +}; + +static const struct mtk_cam_format_desc drzs4no3_out_fmts[] = { + { + .vfmt.fmt.pix_mp = { + .width = DRZS4NO3_MAX_WIDTH, + .height = DRZS4NO3_MAX_HEIGHT, + .pixelformat = V4L2_PIX_FMT_GREY, + }, + } +}; + +#define MTK_RAW_TOTAL_OUTPUT_QUEUES 4 + +static const struct +mtk_cam_dev_node_desc output_queues[] = { + { + .id = MTK_RAW_META_IN, + .name = "meta input", + .cap = V4L2_CAP_META_OUTPUT, + .buf_type = V4L2_BUF_TYPE_META_OUTPUT, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = false, + .smem_alloc = true, + /* .need_cache_sync_on_prepare = true, */ + .dma_port = MTKCAM_IPI_RAW_META_STATS_CFG, + .default_fmt_idx = 0, + .max_buf_count = 16, + .ioctl_ops = &mtk_cam_v4l2_meta_out_ioctl_ops, + }, + { + .id = MTK_RAW_RAWI_2_IN, + .name = "rawi 2", + .cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RAWI_2, + .fmts = stream_out_fmts, + .num_fmts = ARRAY_SIZE(stream_out_fmts), + .default_fmt_idx = 0, + .ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = IMG_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = IMG_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_RAWI_3_IN, + .name = "rawi 3", + .cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .link_flags = 0, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RAWI_3, + .fmts = stream_out_fmts, + .num_fmts = ARRAY_SIZE(stream_out_fmts), + .default_fmt_idx = 0, + .ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = IMG_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = IMG_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_RAWI_4_IN, + .name = "rawi 4", + .cap = V4L2_CAP_VIDEO_OUTPUT_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, + .link_flags = 0, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RAWI_3, /* align backend RAWI_3 */ + .fmts = stream_out_fmts, + .num_fmts = ARRAY_SIZE(stream_out_fmts), + .default_fmt_idx = 0, + .ioctl_ops = &mtk_cam_v4l2_vout_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = IMG_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = IMG_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + } +}; + +static const +char *output_queue_names[RAW_PIPELINE_NUM][MTK_RAW_TOTAL_OUTPUT_QUEUES] = { + {"mtk-cam raw-0 meta-input", "mtk-cam raw-0 rawi-2", + "mtk-cam raw-0 rawi-3", "mtk-cam raw-0 rawi-4"}, + + {"mtk-cam raw-1 meta-input", "mtk-cam raw-1 rawi-2", + "mtk-cam raw-1 rawi-3", "mtk-cam raw-1 rawi-4"}, + + {"mtk-cam raw-2 meta-input", "mtk-cam raw-2 rawi-2", + "mtk-cam raw-2 rawi-3", "mtk-cam raw-2 rawi-4"}, +}; + +static struct mtk_cam_pad_ops source_pad_ops_default = { + .set_pad_fmt = mtk_raw_set_src_pad_fmt_default, + .set_pad_selection = mtk_raw_set_src_pad_selection_default, +}; + +static struct mtk_cam_pad_ops source_pad_ops_yuv = { + .set_pad_fmt = mtk_raw_set_src_pad_fmt_default, + .set_pad_selection = mtk_raw_set_src_pad_selection_yuv, +}; + +static struct mtk_cam_pad_ops source_pad_ops_drzs4no = { + .set_pad_fmt = mtk_raw_set_src_pad_fmt_default, + .set_pad_selection = mtk_raw_set_src_pad_selection_default, +}; + +static struct mtk_cam_pad_ops source_pad_ops_rzh1n2 = { + .set_pad_fmt = mtk_raw_set_src_pad_fmt_rzh1n2, + .set_pad_selection = mtk_raw_set_src_pad_selection_default, +}; + +#define MTK_RAW_TOTAL_CAPTURE_QUEUES 15 +static const struct +mtk_cam_dev_node_desc capture_queues[] = { + { + .id = MTK_RAW_MAIN_STREAM_OUT, + .name = "imgo", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_IMGO, + .fmts = stream_out_fmts, + .num_fmts = ARRAY_SIZE(stream_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_default, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = IMG_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = IMG_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_YUVO_1_OUT, + .name = "yuvo 1", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_YUVO_1, + .fmts = yuv_out_group1_fmts, + .num_fmts = ARRAY_SIZE(yuv_out_group1_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_yuv, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = YUV_GROUP1_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = YUV_GROUP1_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_YUVO_2_OUT, + .name = "yuvo 2", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_YUVO_2, + .fmts = yuv_out_group2_fmts, + .num_fmts = ARRAY_SIZE(yuv_out_group2_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_yuv, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = YUV_GROUP2_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = YUV_GROUP2_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_YUVO_3_OUT, + .name = "yuvo 3", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_YUVO_3, + .fmts = yuv_out_group1_fmts, + .num_fmts = ARRAY_SIZE(yuv_out_group1_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_yuv, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = YUV_GROUP1_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = YUV_GROUP1_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_YUVO_4_OUT, + .name = "yuvo 4", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_YUVO_4, + .fmts = yuv_out_group2_fmts, + .num_fmts = ARRAY_SIZE(yuv_out_group2_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_yuv, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = YUV_GROUP2_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = YUV_GROUP2_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_YUVO_5_OUT, + .name = "yuvo 5", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_YUVO_5, + .fmts = yuv_out_group2_fmts, + .num_fmts = ARRAY_SIZE(yuv_out_group2_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_yuv, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = YUV_GROUP2_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = YUV_GROUP2_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_DRZS4NO_1_OUT, + .name = "drzs4no 1", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_DRZS4NO_1, + .fmts = drzs4no1_out_fmts, + .num_fmts = ARRAY_SIZE(drzs4no1_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_drzs4no, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = DRZS4NO1_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = DRZS4NO1_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_DRZS4NO_2_OUT, + .name = "drzs4no 2", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_DRZS4NO_2, + .fmts = drzs4no2_out_fmts, + .num_fmts = ARRAY_SIZE(drzs4no2_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_drzs4no, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = DRZS4NO2_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = DRZS4NO2_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_DRZS4NO_3_OUT, + .name = "drzs4no 3", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_DRZS4NO_3, + .fmts = drzs4no3_out_fmts, + .num_fmts = ARRAY_SIZE(drzs4no3_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_drzs4no, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = DRZS4NO3_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = DRZS4NO3_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_RZH1N2TO_1_OUT, + .name = "rzh1n2to 1", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RZH1N2TO_1, + .fmts = rzh1n2to1_out_fmts, + .num_fmts = ARRAY_SIZE(rzh1n2to1_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_rzh1n2, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = RZH1N2TO1_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = RZH1N2TO1_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_RZH1N2TO_2_OUT, + .name = "rzh1n2to 2", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RZH1N2TO_2, + .fmts = rzh1n2to2_out_fmts, + .num_fmts = ARRAY_SIZE(rzh1n2to2_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_rzh1n2, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = RZH1N2TO2_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = RZH1N2TO2_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_RZH1N2TO_3_OUT, + .name = "rzh1n2to 3", + .cap = V4L2_CAP_VIDEO_CAPTURE_MPLANE, + .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = true, + .smem_alloc = false, + .dma_port = MTKCAM_IPI_RAW_RZH1N2TO_3, + .fmts = rzh1n2to3_out_fmts, + .num_fmts = ARRAY_SIZE(rzh1n2to3_out_fmts), + .default_fmt_idx = 0, + .pad_ops = &source_pad_ops_rzh1n2, + .ioctl_ops = &mtk_cam_v4l2_vcap_ioctl_ops, + .frmsizes = &(struct v4l2_frmsizeenum) { + .index = 0, + .type = V4L2_FRMSIZE_TYPE_CONTINUOUS, + .stepwise = { + .max_width = RZH1N2TO3_MAX_WIDTH, + .min_width = IMG_MIN_WIDTH, + .max_height = RZH1N2TO3_MAX_HEIGHT, + .min_height = IMG_MIN_HEIGHT, + .step_height = 1, + .step_width = 1, + }, + }, + }, + { + .id = MTK_RAW_META_OUT_0, + .name = "partial meta 0", + .cap = V4L2_CAP_META_CAPTURE, + .buf_type = V4L2_BUF_TYPE_META_CAPTURE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = false, + .smem_alloc = true, + .dma_port = MTKCAM_IPI_RAW_META_STATS_0, + .default_fmt_idx = 1, + .max_buf_count = 16, + .ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops, + }, + { + .id = MTK_RAW_META_OUT_1, + .name = "partial meta 1", + .cap = V4L2_CAP_META_CAPTURE, + .buf_type = V4L2_BUF_TYPE_META_CAPTURE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = false, + .smem_alloc = true, + /* .need_cache_sync_on_finish = true, */ + .dma_port = MTKCAM_IPI_RAW_META_STATS_1, + .default_fmt_idx = 2, + .max_buf_count = 16, + .ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops, + }, + { + .id = MTK_RAW_META_OUT_2, + .name = "partial meta 2", + .cap = V4L2_CAP_META_CAPTURE, + .buf_type = V4L2_BUF_TYPE_META_CAPTURE, + .link_flags = MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE, + .image = false, + .smem_alloc = false, + /* .need_cache_sync_on_finish = true, */ + .dma_port = MTKCAM_IPI_RAW_META_STATS_2, + .default_fmt_idx = 3, + .max_buf_count = 16, + .ioctl_ops = &mtk_cam_v4l2_meta_cap_ioctl_ops, + }, +}; + +static const +char *capture_queue_names[RAW_PIPELINE_NUM][MTK_RAW_TOTAL_CAPTURE_QUEUES] = { + {"mtk-cam raw-0 main-stream", + "mtk-cam raw-0 yuvo-1", "mtk-cam raw-0 yuvo-2", + "mtk-cam raw-0 yuvo-3", "mtk-cam raw-0 yuvo-4", + "mtk-cam raw-0 yuvo-5", + "mtk-cam raw-0 drzs4no-1", "mtk-cam raw-0 drzs4no-2", "mtk-cam raw-0 drzs4no-3", + "mtk-cam raw-0 rzh1n2to-1", "mtk-cam raw-0 rzh1n2to-2", "mtk-cam raw-0 rzh1n2to-3", + "mtk-cam raw-0 partial-meta-0", "mtk-cam raw-0 partial-meta-1", + "mtk-cam raw-0 partial-meta-2", + }, + {"mtk-cam raw-1 main-stream", + "mtk-cam raw-1 yuvo-1", "mtk-cam raw-1 yuvo-2", + "mtk-cam raw-1 yuvo-3", "mtk-cam raw-1 yuvo-4", + "mtk-cam raw-1 yuvo-5", + "mtk-cam raw-1 drzs4no-1", "mtk-cam raw-1 drzs4no-2", "mtk-cam raw-1 drzs4no-3", + "mtk-cam raw-1 rzh1n2to-1", "mtk-cam raw-1 rzh1n2to-2", "mtk-cam raw-1 rzh1n2to-3", + "mtk-cam raw-1 partial-meta-0", "mtk-cam raw-1 partial-meta-1", + "mtk-cam raw-1 partial-meta-2", + }, + + {"mtk-cam raw-2 main-stream", + "mtk-cam raw-2 yuvo-1", "mtk-cam raw-2 yuvo-2", + "mtk-cam raw-2 yuvo-3", "mtk-cam raw-2 yuvo-4", + "mtk-cam raw-2 yuvo-5", + "mtk-cam raw-2 drzs4no-1", "mtk-cam raw-2 drzs4no-2", "mtk-cam raw-2 drzs4no-3", + "mtk-cam raw-2 rzh1n2to-1", "mtk-cam raw-2 rzh1n2to-2", "mtk-cam raw-2 rzh1n2to-3", + "mtk-cam raw-2 partial-meta-0", "mtk-cam raw-2 partial-meta-1", + "mtk-cam raw-2 partial-meta-2", + }, +}; + +/* The helper to configure the device context */ +static void mtk_raw_pipeline_queue_setup(struct mtk_raw_pipeline *pipe) +{ + unsigned int node_idx, i; + + if (WARN_ON(MTK_RAW_TOTAL_OUTPUT_QUEUES + MTK_RAW_TOTAL_CAPTURE_QUEUES + != MTK_RAW_TOTAL_NODES)) + return; + + node_idx = 0; + /* Setup the output queue */ + for (i = 0; i < MTK_RAW_TOTAL_OUTPUT_QUEUES; i++) { + pipe->vdev_nodes[node_idx].desc = output_queues[i]; + + /* set input meta format */ + if (pipe->vdev_nodes[node_idx].desc.id == MTK_RAW_META_IN) + pipe->vdev_nodes[node_idx].desc.fmts = + camsys_get_meta_fmts(); + + pipe->vdev_nodes[node_idx++].desc.name = + output_queue_names[pipe->id][i]; + } + + /* Setup the capture queue */ + for (i = 0; i < MTK_RAW_TOTAL_CAPTURE_QUEUES; i++) { + pipe->vdev_nodes[node_idx].desc = capture_queues[i]; + + /* set partial meta and external meta format */ + if (pipe->vdev_nodes[node_idx].desc.id >= MTK_RAW_META_OUT_BEGIN && + pipe->vdev_nodes[node_idx].desc.id <= MTK_RAW_META_OUT_2) + pipe->vdev_nodes[node_idx].desc.fmts = + camsys_get_meta_fmts(); + + pipe->vdev_nodes[node_idx++].desc.name = + capture_queue_names[pipe->id][i]; + } +} + +static void mtk_raw_pipeline_ctrl_setup(struct mtk_raw_pipeline *pipe) +{ + struct v4l2_ctrl_handler *ctrl_hdlr; + struct v4l2_ctrl *ctrl; + struct device *dev = pipe->raw->devs[pipe->id]; + int ret = 0; + + ctrl_hdlr = &pipe->ctrl_handler; + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 5); + if (ret) { + dev_info(dev, "v4l2_ctrl_handler init failed\n"); + return; + } + mutex_init(&pipe->res_config.resource_lock); + mutex_init(&pipe->try_res_config.resource_lock); + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn_limit, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz_limit, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin_limit, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &hwn_try, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frz_try, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &bin_try, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + v4l2_ctrl_new_custom(ctrl_hdlr, &res_plan_policy, NULL); + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &res_pixel_rate, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &frame_sync_id, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &raw_path, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + + v4l2_ctrl_new_std(ctrl_hdlr, &cam_ctrl_ops, + V4L2_CID_HBLANK, 0, 65535, 1, 0); + v4l2_ctrl_new_std(ctrl_hdlr, &cam_ctrl_ops, + V4L2_CID_VBLANK, 0, 65535, 1, 0); + + /* PDE */ + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_pde_info, NULL); + + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &mtk_feature, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_res_update, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, &cfg_res_ctrl, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE | + V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + + ctrl = v4l2_ctrl_new_custom(ctrl_hdlr, + &mtk_camsys_hw_mode, NULL); + if (ctrl) + ctrl->flags |= V4L2_CTRL_FLAG_EXECUTE_ON_WRITE; + + pipe->res_config.hwn_limit_max = hwn_limit.def; + pipe->res_config.frz_limit = frz_limit.def; + pipe->res_config.bin_limit = bin_limit.def; + pipe->res_config.res_plan = res_plan_policy.def; + pipe->feature_pending = mtk_feature.def; + pipe->sync_id = frame_sync_id.def; + pipe->sensor_mode_update = cfg_res_update.def; + pipe->pde_config.pde_info.pdo_max_size = cfg_pde_info.def; + pipe->pde_config.pde_info.pdi_max_size = cfg_pde_info.def; + pipe->pde_config.pde_info.pd_table_offset = cfg_pde_info.def; + pipe->subdev.ctrl_handler = ctrl_hdlr; + pipe->hw_mode = mtk_camsys_hw_mode.def; +} + +static int mtk_raw_pipeline_register(unsigned int id, struct device *dev, + struct mtk_raw_pipeline *pipe, + struct v4l2_device *v4l2_dev) +{ + struct mtk_cam_device *cam = dev_get_drvdata(pipe->raw->cam_dev); + struct v4l2_subdev *sd = &pipe->subdev; + struct mtk_cam_video_device *video; + unsigned int i; + int ret; + + pipe->id = id; + + /* Initialize raw_pipe subdev */ + v4l2_subdev_init(sd, &mtk_raw_subdev_ops); + sd->internal_ops = &mtk_raw_subdev_internal_ops; + sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + sd->entity.ops = &mtk_cam_media_entity_ops; + sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS; + snprintf(sd->name, sizeof(sd->name), + "%s-%d", dev_driver_string(dev), pipe->id); + v4l2_set_subdevdata(sd, pipe); + mtk_raw_pipeline_ctrl_setup(pipe); + dev_info(dev, "%s: %s\n", __func__, sd->name); + + ret = v4l2_device_register_subdev(v4l2_dev, sd); + if (ret < 0) { + dev_info(dev, "Failed to register subdev: %d\n", ret); + return ret; + } + + mtk_raw_pipeline_queue_setup(pipe); + /* setup pads of raw pipeline */ + for (i = 0; i < ARRAY_SIZE(pipe->pads); i++) { + pipe->pads[i].flags = i < MTK_RAW_SOURCE_BEGIN ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + } + + media_entity_pads_init(&sd->entity, ARRAY_SIZE(pipe->pads), pipe->pads); + + /* setup video node */ + for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++) { + video = pipe->vdev_nodes + i; + + switch (pipe->id) { + case MTKCAM_SUBDEV_RAW_0: + case MTKCAM_SUBDEV_RAW_1: + case MTKCAM_SUBDEV_RAW_2: + video->uid.pipe_id = pipe->id; + break; + default: + dev_err(dev, "invalid pipe id\n"); + return -EINVAL; + } + + video->uid.id = video->desc.dma_port; + video->ctx = &cam->ctxs[id]; + ret = mtk_cam_video_register(video, v4l2_dev); + if (ret) + goto fail_unregister_video; + + if (V4L2_TYPE_IS_OUTPUT(video->desc.buf_type)) + ret = media_create_pad_link(&video->vdev.entity, 0, + &sd->entity, + video->desc.id, + video->desc.link_flags); + else + ret = media_create_pad_link(&sd->entity, + video->desc.id, + &video->vdev.entity, 0, + video->desc.link_flags); + + if (ret) + goto fail_unregister_video; + } + + for (i = 0; i < sd->entity.num_pads; i++) + pipe->cfg[i].mbus_fmt = mfmt_default; + + return 0; + +fail_unregister_video: + if (!i) + return ret; + + for (i = i - 1; i >= 0; i--) + mtk_cam_video_unregister(pipe->vdev_nodes + i); + + return ret; +} + +static void mtk_raw_pipeline_unregister(struct mtk_raw_pipeline *pipe) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(pipe->vdev_nodes); i++) + mtk_cam_video_unregister(pipe->vdev_nodes + i); + v4l2_ctrl_handler_free(&pipe->ctrl_handler); + mutex_destroy(&pipe->res_config.resource_lock); + v4l2_device_unregister_subdev(&pipe->subdev); + media_entity_cleanup(&pipe->subdev.entity); +} + +int mtk_cam_raw_setup_dependencies(struct mtk_raw *raw) +{ + struct device *dev = raw->cam_dev; + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + struct device *consumer, *supplier; + struct device_link *link; + struct mtk_raw_device *raw_dev; + struct mtk_yuv_device *yuv_dev; + int i; + + for (i = 0; i < cam_dev->num_raw_devices; i++) { + consumer = raw->devs[i]; + supplier = raw->yuvs[i]; + if (!consumer || !supplier) { + dev_info(dev, "failed to get raw/yuv dev for id %d\n", i); + continue; + } + + raw_dev = dev_get_drvdata(consumer); + yuv_dev = dev_get_drvdata(supplier); + raw_dev->yuv_base = yuv_dev->base; + + link = device_link_add(consumer, supplier, + DL_FLAG_AUTOREMOVE_CONSUMER | + DL_FLAG_PM_RUNTIME); + if (!link) { + dev_err(dev, "Unable to create link between %s and %s\n", + dev_name(consumer), dev_name(supplier)); + return -ENODEV; + } + } + + return 0; +} + +int mtk_cam_raw_register_entities(struct mtk_raw *raw, struct v4l2_device *v4l2_dev) +{ + struct device *dev = raw->cam_dev; + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + unsigned int i; + int ret; + + for (i = 0; i < cam_dev->num_raw_devices; i++) { + struct mtk_raw_pipeline *pipe = raw->pipelines + i; + + pipe->raw = raw; + memset(pipe->cfg, 0, sizeof(*pipe->cfg)); + ret = mtk_raw_pipeline_register(MTKCAM_SUBDEV_RAW_0 + i, + raw->devs[i], + raw->pipelines + i, v4l2_dev); + if (ret) + return ret; + } + return 0; +} + +void mtk_cam_raw_unregister_entities(struct mtk_raw *raw) +{ + struct device *dev = raw->cam_dev; + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + unsigned int i; + + for (i = 0; i < cam_dev->num_raw_devices; i++) + mtk_raw_pipeline_unregister(raw->pipelines + i); +} + +static int mtk_raw_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_raw_device *raw_dev; + struct v4l2_subdev *sd; + int ret; + + dev_dbg(dev, "camsys | start %s\n", __func__); + + raw_dev = devm_kzalloc(dev, sizeof(*raw_dev), GFP_KERNEL); + if (!raw_dev) + return -ENOMEM; + + raw_dev->dev = dev; + dev_set_drvdata(dev, raw_dev); + + ret = mtk_raw_of_probe(pdev, raw_dev); + if (ret) + return ret; + + raw_dev->fifo_size = + roundup_pow_of_two(8 * sizeof(struct mtk_camsys_irq_info)); + raw_dev->msg_buffer = devm_kzalloc(dev, raw_dev->fifo_size, GFP_KERNEL); + if (!raw_dev->msg_buffer) + return -ENOMEM; + + /* register raw as mtk_cam async child */ + sd = &raw_dev->subdev; + v4l2_subdev_init(sd, &mtk_raw_subdev_ops); + sd->internal_ops = &mtk_raw_subdev_internal_ops; + snprintf(sd->name, sizeof(sd->name), "%s", + of_node_full_name(dev->of_node)); + sd->dev = dev; + sd->owner = THIS_MODULE; + + ret = v4l2_async_register_subdev(sd); + if (ret) { + dev_err(dev, "%s failed on async_register_subdev\n", __func__); + return ret; + } + dev_dbg(dev, "%s id:%d register subdev\n", __func__, raw_dev->id); + + pm_runtime_enable(dev); + + dev_info(dev, "camsys | [%s] success\n", __func__); + + return 0; +} + +static void mtk_raw_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_raw_device *raw_dev = dev_get_drvdata(dev); + struct v4l2_subdev *sd = &raw_dev->subdev; + + dev_dbg(dev, "camsys | start %s\n", __func__); + + unregister_pm_notifier(&raw_dev->pm_notifier); + + pm_runtime_disable(dev); + + v4l2_async_unregister_subdev(sd); +} + +static int mtk_raw_runtime_suspend(struct device *dev) +{ + struct mtk_raw_device *drvdata = dev_get_drvdata(dev); + + dev_dbg(dev, "%s:disable clock\n", __func__); + + disable_irq(drvdata->irq); + + mtk_cam_raw_reset(drvdata); + + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b); + + return 0; +} + +static int mtk_raw_runtime_resume(struct device *dev) +{ + struct mtk_raw_device *drvdata = dev_get_drvdata(dev); + int ret; + + /* reset_msgfifo before enable_irq */ + ret = reset_msgfifo(drvdata); + if (ret) + return ret; + + enable_irq(drvdata->irq); + + dev_dbg(dev, "%s:enable clock\n", __func__); + + ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clk_b); + if (ret) { + dev_info(dev, "failed at clk_bulk_prepare_enable, ret = %d\n", ret); + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b); + return ret; + } + + mtk_cam_raw_reset(drvdata); + + return 0; +} + +static const struct dev_pm_ops mtk_raw_pm_ops = { + SET_RUNTIME_PM_OPS(mtk_raw_runtime_suspend, mtk_raw_runtime_resume, + NULL) +}; + +static const struct of_device_id mtk_raw_of_ids[] = { + {.compatible = "mediatek,cam-raw",}, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_raw_of_ids); + +struct platform_driver mtk_cam_raw_driver = { + .probe = mtk_raw_probe, + .remove = mtk_raw_remove, + .driver = { + .name = "mtk-cam raw", + .of_match_table = of_match_ptr(mtk_raw_of_ids), + .pm = &mtk_raw_pm_ops, + } +}; + +static inline unsigned int mtk_yuv_get_err_status(unsigned int irq_status) +{ + return irq_status & YUV_DMA_ERR_ST; +} + +static irqreturn_t mtk_irq_yuv(int irq, void *data) +{ + struct mtk_yuv_device *drvdata = (struct mtk_yuv_device *)data; + struct device *dev = drvdata->dev; + + unsigned int irq_status, err_status, dma_done_status; + unsigned int drop_status, dma_ofl_status; + + irq_status = + readl_relaxed(drvdata->base + REG_CTL_RAW_INT_STAT); + dma_done_status = + readl_relaxed(drvdata->base + REG_CTL_RAW_INT2_STAT); + drop_status = + readl_relaxed(drvdata->base + REG_CTL_RAW_INT4_STAT); + dma_ofl_status = + readl_relaxed(drvdata->base + REG_CTL_RAW_INT5_STAT); + + err_status = mtk_yuv_get_err_status(irq_status); + + if (unlikely(debug_raw)) + dev_dbg(dev, "YUV-INT:0x%x(err:0x%x) INT2/4/5 0x%x/0x%x/0x%x\n", + irq_status, err_status, + dma_done_status, drop_status, dma_ofl_status); + + return IRQ_HANDLED; +} + +static int mtk_yuv_pm_suspend_prepare(struct mtk_yuv_device *dev) +{ + int ret; + + dev_dbg(dev->dev, "- %s\n", __func__); + + if (pm_runtime_suspended(dev->dev)) + return 0; + + /* Force ISP HW to idle */ + ret = pm_runtime_force_suspend(dev->dev); + return ret; +} + +static int mtk_yuv_pm_post_suspend(struct mtk_yuv_device *dev) +{ + int ret; + + dev_dbg(dev->dev, "- %s\n", __func__); + + if (pm_runtime_suspended(dev->dev)) + return 0; + + /* Force ISP HW to resume */ + ret = pm_runtime_force_resume(dev->dev); + if (ret) + return ret; + + return 0; +} + +static int yuv_pm_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct mtk_yuv_device *yuv_dev = + container_of(nb, struct mtk_yuv_device, pm_notifier); + + switch (action) { + case PM_SUSPEND_PREPARE: + mtk_yuv_pm_suspend_prepare(yuv_dev); + break; + case PM_POST_SUSPEND: + mtk_yuv_pm_post_suspend(yuv_dev); + break; + default: + break; + } + + return NOTIFY_OK; +} + +static int mtk_yuv_of_probe(struct platform_device *pdev, + struct mtk_yuv_device *drvdata) +{ + struct device *dev = &pdev->dev; + struct resource *res; + int irq, ret; + int n_clks; + + ret = of_property_read_u32(dev->of_node, "mediatek,cam-id", + &drvdata->id); + if (ret) { + dev_dbg(dev, "missing camid property\n"); + return ret; + } + + if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) { + dev_err(dev, "%s: No suitable DMA available\n", __func__); + return -EIO; + } + + if (!dev->dma_parms) { + dev->dma_parms = + devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + + dma_set_max_seg_size(dev, UINT_MAX); + + /* base outer register */ + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "base"); + if (!res) { + dev_err(dev, "failed to get mem\n"); + return -ENODEV; + } + + drvdata->base = devm_ioremap_resource(dev, res); + if (IS_ERR(drvdata->base)) { + dev_dbg(dev, "failed to map register base\n"); + return PTR_ERR(drvdata->base); + } + + irq = platform_get_irq(pdev, 0); + if (irq < 0) { + dev_err(dev, "failed to get irq\n"); + return -ENODEV; + } + + ret = devm_request_irq(dev, irq, mtk_irq_yuv, 0, + dev_name(dev), drvdata); + if (ret) { + dev_err(dev, "failed to request irq=%d\n", irq); + return ret; + } + dev_dbg(dev, "registered irq=%d\n", irq); + + n_clks = devm_clk_bulk_get_all(dev, &drvdata->clk_b); + if (n_clks < 0) { + dev_err(dev, "failed to devm_clk_bulk_get_all=%d\n", n_clks); + return n_clks; + } + + drvdata->num_clks = n_clks; + dev_info(dev, "clk_num:%d\n", drvdata->num_clks); + +#ifdef CONFIG_PM_SLEEP + drvdata->pm_notifier.notifier_call = yuv_pm_notifier; + ret = register_pm_notifier(&drvdata->pm_notifier); + if (ret) { + dev_err(dev, "failed to register notifier block.\n"); + return ret; + } +#endif + + return 0; +} + +static int mtk_yuv_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_yuv_device *drvdata; + struct v4l2_subdev *sd; + int ret; + + dev_dbg(dev, "camsys | start %s\n", __func__); + + drvdata = devm_kzalloc(dev, sizeof(*drvdata), GFP_KERNEL); + if (!drvdata) + return -ENOMEM; + + drvdata->dev = dev; + dev_set_drvdata(dev, drvdata); + + ret = mtk_yuv_of_probe(pdev, drvdata); + if (ret) { + dev_info(dev, "mtk_yuv_of_probe failed\n"); + return ret; + } + + /* register yuv as mtk_cam async child */ + sd = &drvdata->subdev; + v4l2_subdev_init(sd, &mtk_raw_subdev_ops); + sd->internal_ops = &mtk_raw_subdev_internal_ops; + snprintf(sd->name, sizeof(sd->name), "%s", + of_node_full_name(dev->of_node)); + sd->dev = dev; + sd->owner = THIS_MODULE; + + ret = v4l2_async_register_subdev(sd); + if (ret) { + dev_err(dev, "%s failed on async_register_subdev\n", __func__); + return ret; + } + + pm_runtime_enable(dev); + + dev_info(dev, "camsys | [%s] success\n", __func__); + + return 0; +} + +static void mtk_yuv_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev); + struct v4l2_subdev *sd = &yuv_dev->subdev; + + dev_dbg(dev, "camsys | start %s\n", __func__); + + unregister_pm_notifier(&yuv_dev->pm_notifier); + + pm_runtime_disable(dev); + + v4l2_async_unregister_subdev(sd); +} + +/* driver for yuv part */ +static int mtk_yuv_runtime_suspend(struct device *dev) +{ + struct mtk_yuv_device *drvdata = dev_get_drvdata(dev); + + dev_info(dev, "%s:disable clock\n", __func__); + + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b); + + return 0; +} + +static int mtk_yuv_runtime_resume(struct device *dev) +{ + struct mtk_yuv_device *drvdata = dev_get_drvdata(dev); + int ret; + + dev_info(dev, "%s:enable clock\n", __func__); + + ret = clk_bulk_prepare_enable(drvdata->num_clks, drvdata->clk_b); + if (ret) { + dev_info(dev, "failed at clk_bulk_prepare_enable, ret = %d\n", ret); + clk_bulk_disable_unprepare(drvdata->num_clks, drvdata->clk_b); + return ret; + } + + return 0; +} + +static const struct dev_pm_ops mtk_yuv_pm_ops = { + SET_RUNTIME_PM_OPS(mtk_yuv_runtime_suspend, mtk_yuv_runtime_resume, + NULL) +}; + +static const struct of_device_id mtk_yuv_of_ids[] = { + {.compatible = "mediatek,cam-yuv",}, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_yuv_of_ids); + +struct platform_driver mtk_cam_yuv_driver = { + .probe = mtk_yuv_probe, + .remove = mtk_yuv_remove, + .driver = { + .name = "mtk-cam yuv", + .of_match_table = of_match_ptr(mtk_yuv_of_ids), + .pm = &mtk_yuv_pm_ops, + } +}; diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h new file mode 100644 index 000000000000..09a92df5d20a --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw.h @@ -0,0 +1,325 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_RAW_H +#define __MTK_CAM_RAW_H + +#include +#include +#include "mtk_cam-video.h" +#include "mtk_camera-v4l2-controls.h" + +struct mtk_cam_request_stream_data; + +/* ISP7_1 control */ +#define RAW_PIPELINE_NUM 3 + +#define SCQ_DEADLINE_MS 15 /* ~1/2 frame length */ +#define SCQ_DEFAULT_CLK_RATE 208 /* default 208MHz */ + +#define MTK_CAMSYS_RES_STEP_NUM 8 + +/* ISP7_1 image */ +#define IMG_MAX_WIDTH 12000 +#define IMG_MAX_HEIGHT 9000 + +#define IMG_MIN_WIDTH 80 +#define IMG_MIN_HEIGHT 60 +#define YUV_GROUP1_MAX_WIDTH 8160 +#define YUV_GROUP1_MAX_HEIGHT 3896 +#define YUV_GROUP2_MAX_WIDTH 3060 +#define YUV_GROUP2_MAX_HEIGHT 1145 +#define YUV1_MAX_WIDTH 8160 +#define YUV1_MAX_HEIGHT 2290 +#define YUV2_MAX_WIDTH 3060 +#define YUV2_MAX_HEIGHT 1145 +#define YUV3_MAX_WIDTH 7794 +#define YUV3_MAX_HEIGHT 3896 +#define YUV4_MAX_WIDTH 1530 +#define YUV4_MAX_HEIGHT 572 +#define YUV5_MAX_WIDTH 1530 +#define YUV5_MAX_HEIGHT 572 +#define DRZS4NO1_MAX_WIDTH 2400 +#define DRZS4NO1_MAX_HEIGHT 1080 +#define DRZS4NO2_MAX_WIDTH 2400 +#define DRZS4NO2_MAX_HEIGHT 1080 +#define DRZS4NO3_MAX_WIDTH 576 +#define DRZS4NO3_MAX_HEIGHT 432 +#define RZH1N2TO1_MAX_WIDTH 1280 +#define RZH1N2TO1_MAX_HEIGHT 600 +#define RZH1N2TO2_MAX_WIDTH 512 +#define RZH1N2TO2_MAX_HEIGHT 512 +#define RZH1N2TO3_MAX_WIDTH 1280 +#define RZH1N2TO3_MAX_HEIGHT 600 + +#define IMG_PIX_ALIGN 2 + +enum raw_module_id { + RAW_A = 0, + RAW_B = 1, + RAW_C = 2, + RAW_NUM, +}; + +/* feature mask to categorize all raw functions */ +#define MTK_CAM_FEATURE_HDR_MASK 0x0000000F +#define MTK_CAM_FEATURE_SUBSAMPLE_MASK 0x000000F0 +#define MTK_CAM_FEATURE_OFFLINE_M2M_MASK 0x00000100 +#define MTK_CAM_FEATURE_PURE_OFFLINE_M2M_MASK 0x00000200 + +enum raw_function_id { + /* bit [0~3] hdr */ + /* bit [4~7] fps */ + /* bit [8~9] m2m */ + OFFLINE_M2M = (1 << 8), + PURE_OFFLINE_M2M = (1 << 9), + RAW_FUNCTION_END = 0xF0000000, +}; + +enum hardware_mode_id { + DEFAULT = 0, + ON_THE_FLY = 1, + DCIF = 2, +}; + +/* enum for pads of raw pipeline */ +enum { + MTK_RAW_SINK_BEGIN = 0, + MTK_RAW_SINK = MTK_RAW_SINK_BEGIN, + MTK_RAW_SINK_NUM, + MTK_RAW_META_IN = MTK_RAW_SINK_NUM, + MTK_RAW_RAWI_2_IN, + MTK_RAW_RAWI_3_IN, + MTK_RAW_RAWI_4_IN, + MTK_RAW_SOURCE_BEGIN, + MTK_RAW_MAIN_STREAM_OUT = MTK_RAW_SOURCE_BEGIN, + MTK_RAW_YUVO_1_OUT, + MTK_RAW_YUVO_2_OUT, + MTK_RAW_YUVO_3_OUT, + MTK_RAW_YUVO_4_OUT, + MTK_RAW_YUVO_5_OUT, + MTK_RAW_DRZS4NO_1_OUT, + MTK_RAW_DRZS4NO_2_OUT, + MTK_RAW_DRZS4NO_3_OUT, + MTK_RAW_RZH1N2TO_1_OUT, + MTK_RAW_RZH1N2TO_2_OUT, + MTK_RAW_RZH1N2TO_3_OUT, + MTK_RAW_META_OUT_BEGIN, + MTK_RAW_META_OUT_0 = MTK_RAW_META_OUT_BEGIN, + MTK_RAW_META_OUT_1, + MTK_RAW_META_OUT_2, + MTK_RAW_PIPELINE_PADS_NUM, +}; + +static inline bool is_yuv_node(u32 desc_id) +{ + switch (desc_id) { + case MTK_RAW_YUVO_1_OUT: + case MTK_RAW_YUVO_2_OUT: + case MTK_RAW_YUVO_3_OUT: + case MTK_RAW_YUVO_4_OUT: + case MTK_RAW_YUVO_5_OUT: + case MTK_RAW_DRZS4NO_1_OUT: + case MTK_RAW_DRZS4NO_2_OUT: + case MTK_RAW_DRZS4NO_3_OUT: + case MTK_RAW_RZH1N2TO_1_OUT: + case MTK_RAW_RZH1N2TO_2_OUT: + case MTK_RAW_RZH1N2TO_3_OUT: + return true; + default: + return false; + } +} + +/* max(pdi_table1, pdi_table2, ...) */ +#define RAW_STATS_CFG_VARIOUS_SIZE ALIGN(0x7500, SZ_1K) + +#define MTK_RAW_TOTAL_NODES (MTK_RAW_PIPELINE_PADS_NUM - MTK_RAW_SINK_NUM) + +struct mtk_cam_dev; +struct mtk_cam_ctx; + +struct mtk_raw_pde_config { + struct mtk_cam_pde_info pde_info; +}; + +struct mtk_cam_resource_config { + struct v4l2_subdev *seninf; + struct mutex resource_lock; /* protect resource calculation */ + struct v4l2_fract interval; + s64 pixel_rate; + u32 bin_limit; + u32 frz_limit; + u32 hwn_limit_max; + u32 hwn_limit_min; + s64 hblank; + s64 vblank; + s64 sensor_pixel_rate; + u32 res_plan; + u32 raw_feature; + u32 res_strategy[MTK_CAMSYS_RES_STEP_NUM]; + u32 clk_target; + u32 raw_num_used; + u32 bin_enable; + u32 frz_enable; + u32 frz_ratio; + u32 tgo_pxl_mode; + u32 raw_path; + /* sink fmt adjusted according resource used*/ + struct v4l2_mbus_framefmt sink_fmt; +}; + +struct mtk_raw_pad_config { + struct v4l2_mbus_framefmt mbus_fmt; + struct v4l2_rect crop; +}; + +/* + * struct mtk_raw_pipeline - sub dev to use raws. + * + * @feature_pending: keep the user value of S_CTRL V4L2_CID_MTK_CAM_FEATURE. + * It it safe save to be used in mtk_cam_vidioc_s_fmt, + * mtk_cam_vb2_queue_setup and mtk_cam_vb2_buf_queue + * But considering that we can't when the user calls S_CTRL, + * please use mtk_cam_request_stream_data's + * feature.raw_feature field + * to avoid the CTRL value change tming issue. + * @feature_active: The active feature during streaming. It can't be changed + * during streaming and can only be used after streaming on. + * + */ +struct mtk_raw_pipeline { + unsigned int id; + struct v4l2_subdev subdev; + struct media_pad pads[MTK_RAW_PIPELINE_PADS_NUM]; + struct mtk_cam_video_device vdev_nodes[MTK_RAW_TOTAL_NODES]; + struct mtk_raw *raw; + struct mtk_raw_pad_config cfg[MTK_RAW_PIPELINE_PADS_NUM]; + + /* cached settings */ + unsigned int enabled_raw; + unsigned long enabled_dmas; + /* resource controls */ + struct v4l2_ctrl_handler ctrl_handler; + s64 feature_pending; + s64 feature_active; + + struct mtk_cam_resource user_res; + struct mtk_cam_resource_config res_config; + struct mtk_cam_resource_config try_res_config; + int sensor_mode_update; + s64 sync_id; + /* pde module */ + struct mtk_raw_pde_config pde_config; + s64 hw_mode; +}; + +struct mtk_raw_device { + struct v4l2_subdev subdev; + struct device *dev; + struct mtk_cam_device *cam; + unsigned int id; + int irq; + void __iomem *base; + void __iomem *base_inner; + void __iomem *yuv_base; + unsigned int num_clks; + struct clk_bulk_data *clk_b; +#ifdef CONFIG_PM_SLEEP + struct notifier_block pm_notifier; +#endif + + unsigned int fifo_size; + void *msg_buffer; + struct kfifo msg_fifo; + atomic_t is_fifo_overflow; + + struct mtk_raw_pipeline *pipeline; + bool is_sub; + + u64 sof_count; + u64 vsync_count; + + atomic_t vf_en; + int overrun_debug_dump_cnt; +}; + +struct mtk_yuv_device { + struct v4l2_subdev subdev; + struct device *dev; + unsigned int id; + void __iomem *base; + unsigned int num_clks; + struct clk_bulk_data *clk_b; +#ifdef CONFIG_PM_SLEEP + struct notifier_block pm_notifier; +#endif +}; + +/* AE information */ +struct mtk_ae_debug_data { + u64 obc_r1_sum[4]; + u64 obc_r2_sum[4]; + u64 obc_r3_sum[4]; + u64 aa_sum[4]; + u64 ltm_sum[4]; +}; + +/* + * struct mtk_raw - the raw device information + */ +struct mtk_raw { + struct device *cam_dev; + struct device *devs[RAW_PIPELINE_NUM]; + struct device *yuvs[RAW_PIPELINE_NUM]; + struct mtk_raw_pipeline pipelines[RAW_PIPELINE_NUM]; +}; + +static inline struct mtk_raw_pipeline * +mtk_cam_ctrl_handler_to_raw_pipeline(struct v4l2_ctrl_handler *handler) +{ + return container_of(handler, struct mtk_raw_pipeline, ctrl_handler); +}; + +int mtk_cam_raw_setup_dependencies(struct mtk_raw *raw); + +int mtk_cam_raw_register_entities(struct mtk_raw *raw, + struct v4l2_device *v4l2_dev); +void mtk_cam_raw_unregister_entities(struct mtk_raw *raw); + +int mtk_cam_raw_select(struct mtk_cam_ctx *ctx, + struct mtkcam_ipi_input_param *cfg_in_param); + +void mtk_cam_raw_initialize(struct mtk_raw_device *dev, int is_sub); + +void mtk_cam_raw_stream_on(struct mtk_raw_device *dev, int on); + +void mtk_cam_raw_apply_cq(struct mtk_raw_device *dev, dma_addr_t cq_addr, + unsigned int cq_size, unsigned int cq_offset, + unsigned int sub_cq_size, unsigned int sub_cq_offset); + +void mtk_cam_raw_trigger_rawi(struct mtk_raw_device *dev, + struct mtk_cam_ctx *ctx, + signed int hw_scene); + +void mtk_cam_raw_reset(struct mtk_raw_device *dev); + +void mtk_cam_raw_dump_aa_info(struct mtk_cam_ctx *ctx, + struct mtk_ae_debug_data *ae_info); + +extern struct platform_driver mtk_cam_raw_driver; +extern struct platform_driver mtk_cam_yuv_driver; + +static inline u32 dmaaddr_lsb(dma_addr_t addr) +{ + return addr & (u32)U32_MAX; +} + +static inline u32 dmaaddr_msb(dma_addr_t addr) +{ + return (u64)addr >> 32; +} + +#endif /*__MTK_CAM_RAW_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.c new file mode 100644 index 000000000000..bd81ce53b251 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.c @@ -0,0 +1,403 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2022 MediaTek Inc. + +#include +#include + +#include "mtk_cam-regs-mt8188.h" + +#include "mtk_cam-raw_debug.h" + +#define ADD_FBC_DMA(name) #name +static const char * const fbc_r1_list[] = { + ADD_FBC_DMA(IMGO_R1), + ADD_FBC_DMA(FHO_R1), + ADD_FBC_DMA(AAHO_R1), + ADD_FBC_DMA(PDO_R1), + ADD_FBC_DMA(AAO_R1), + ADD_FBC_DMA(TSFSO_R1), + ADD_FBC_DMA(LTMSO_R1), + ADD_FBC_DMA(AFO_R1), + ADD_FBC_DMA(FLKO_R1), + ADD_FBC_DMA(UFEO_R1), + ADD_FBC_DMA(TSFSO_R2), +}; + +static const char * const fbc_r2_list[] = { + ADD_FBC_DMA(YUVO_R1), + ADD_FBC_DMA(YUVBO_R1), + ADD_FBC_DMA(YUVCO_R1), + ADD_FBC_DMA(YUVDO_R1), + ADD_FBC_DMA(YUVO_R3), + ADD_FBC_DMA(YUVBO_R3), + ADD_FBC_DMA(YUVCO_R3), + ADD_FBC_DMA(YUVDO_R3), + ADD_FBC_DMA(YUVO_R2), + ADD_FBC_DMA(YUVBO_R2), + ADD_FBC_DMA(YUVO_R4), + ADD_FBC_DMA(YUVBO_R4), + ADD_FBC_DMA(RZH1N2TO_R1), + ADD_FBC_DMA(RZH1N2TBO_R1), + ADD_FBC_DMA(RZH1N2TO_R2), + ADD_FBC_DMA(RZH1N2TO_R3), + ADD_FBC_DMA(RZH1N2TBO_R3), + ADD_FBC_DMA(DRZS4NO_R1), + ADD_FBC_DMA(DRZS4NO_R2), + ADD_FBC_DMA(DRZS4NO_R3), + ADD_FBC_DMA(TNCSO_R1), + ADD_FBC_DMA(TNCSYO_R1), + ADD_FBC_DMA(TNCSBO_R1), + ADD_FBC_DMA(TNCSHO_R1), + ADD_FBC_DMA(ACTSO_R1), + ADD_FBC_DMA(YUVO_R5), + ADD_FBC_DMA(YUVBO_R5), +}; + +#define LOGGER_PREFIX_SIZE 16 +#define LOGGER_BUFSIZE 128 +struct buffered_logger { + struct device *dev; + void (*log_handler)(struct buffered_logger *log); + + char prefix[LOGGER_PREFIX_SIZE]; + char buf[LOGGER_BUFSIZE + 1]; + unsigned int size; +}; + +static void mtk_cam_init_logger(struct buffered_logger *logger, + struct device *dev, + void (*_hdl)(struct buffered_logger *)) +{ + logger->dev = dev; + logger->log_handler = _hdl; + logger->prefix[0] = '\0'; + logger->buf[LOGGER_BUFSIZE] = '\0'; + logger->size = 0; +} + +static __printf(2, 3) +void mtk_cam_log_set_prefix(struct buffered_logger *log, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vscnprintf(log->prefix, LOGGER_PREFIX_SIZE, fmt, args); + va_end(args); +} + +static void mtk_cam_log_handle_limited(struct buffered_logger *log) +{ + dev_info_ratelimited(log->dev, "%s: %.*s\n", + log->prefix, log->size, log->buf); + log->size = 0; +} + +static void mtk_cam_log_handle_info(struct buffered_logger *log) +{ + dev_info(log->dev, "%s: %.*s\n", log->prefix, log->size, log->buf); + log->size = 0; +} + +static void mtk_cam_log_flush(struct buffered_logger *log) +{ + log->log_handler(log); +} + +static __printf(2, 3) +void mtk_cam_log_push(struct buffered_logger *log, const char *fmt, ...) +{ + va_list args; + int len; + + va_start(args, fmt); + len = vscnprintf(log->buf + log->size, LOGGER_BUFSIZE - log->size + 1, + fmt, args); + va_end(args); + + if (len + log->size < LOGGER_BUFSIZE) { + log->size += len; + return; + } + + mtk_cam_log_flush(log); + + va_start(args, fmt); + len = vscnprintf(log->buf + log->size, LOGGER_BUFSIZE - log->size + 1, + fmt, args); + va_end(args); + + log->size += len; + + if (len == LOGGER_BUFSIZE) + dev_info(log->dev, "log buffer size not enough: %d\n", + LOGGER_BUFSIZE); +} + +void mtk_cam_raw_dump_fbc(struct device *dev, + void __iomem *base, void __iomem *yuvbase) +{ + struct buffered_logger log; + int fbc_r1_ctl2[ARRAY_SIZE(fbc_r1_list)]; + int fbc_r2_ctl2[ARRAY_SIZE(fbc_r2_list)]; + int i; + + for (i = 0; i < ARRAY_SIZE(fbc_r1_list); i++) + fbc_r1_ctl2[i] = readl(base + REG_FBC_CTL2(FBC_R1A_BASE, i)); + + for (i = 0; i < ARRAY_SIZE(fbc_r2_list); i++) + fbc_r2_ctl2[i] = readl(yuvbase + REG_FBC_CTL2(FBC_R2A_BASE, i)); + + mtk_cam_init_logger(&log, dev, mtk_cam_log_handle_info); + + mtk_cam_log_set_prefix(&log, "%s", "RAW FBC"); + for (i = 0; i < ARRAY_SIZE(fbc_r1_list); i++) + if (fbc_r1_ctl2[i] & 0xffffff) /* if has been used */ + mtk_cam_log_push(&log, " %s: 0x%08x", + fbc_r1_list[i], fbc_r1_ctl2[i]); + mtk_cam_log_flush(&log); + + mtk_cam_log_set_prefix(&log, "%s", "YUV FBC"); + for (i = 0; i < ARRAY_SIZE(fbc_r2_list); i++) + if (fbc_r2_ctl2[i] & 0xffffff) /* if has been used */ + mtk_cam_log_push(&log, " %s: 0x%08x", + fbc_r2_list[i], fbc_r2_ctl2[i]); + mtk_cam_log_flush(&log); +} + +struct reg_to_dump { + const char *name; + unsigned int reg; +}; + +#define ADD_DMA(name) { #name, REG_ ## name ## _BASE + DMA_OFFSET_ERR_STAT } +static const struct reg_to_dump raw_dma_list[] = { + ADD_DMA(IMGO_R1), + ADD_DMA(IMGO_R1), + ADD_DMA(UFEO_R1), + ADD_DMA(PDO_R1), + ADD_DMA(FLKO_R1), + ADD_DMA(TSFSO_R1), + ADD_DMA(TSFSO_R2), + ADD_DMA(AAO_R1), + ADD_DMA(AAHO_R1), + ADD_DMA(AFO_R1), + ADD_DMA(LTMSO_R1), + ADD_DMA(FHO_R1), + /* ADD_DMA(BPCO_R1), */ + + ADD_DMA(RAWI_R2), + ADD_DMA(UFDI_R2), + ADD_DMA(BPCI_R1), + ADD_DMA(LSCI_R1), + ADD_DMA(AAI_R1), + ADD_DMA(PDI_R1), + ADD_DMA(BPCI_R2), + ADD_DMA(RAWI_R3), + ADD_DMA(UFDI_R3), + ADD_DMA(BPCI_R3), + /* ADD_DMA(RAWI_R4), */ + /* ADD_DMA(BPCI_R4), */ + /* ADD_DMA(RAWI_R5), */ + ADD_DMA(RAWI_R6), + ADD_DMA(CACI_R1), +}; + +static const struct reg_to_dump yuv_dma_list[] = { + ADD_DMA(ACTSO_R1), + ADD_DMA(TNCSO_R1), + ADD_DMA(TNCSBO_R1), + ADD_DMA(TNCSHO_R1), + ADD_DMA(TNCSYO_R1), + ADD_DMA(DRZS4NO_R1), + ADD_DMA(DRZS4NO_R2), + ADD_DMA(DRZS4NO_R3), + ADD_DMA(RZH1N2TO_R1), + ADD_DMA(RZH1N2TBO_R1), + ADD_DMA(RZH1N2TO_R2), + ADD_DMA(RZH1N2TO_R3), + ADD_DMA(RZH1N2TBO_R3), + ADD_DMA(YUVO_R1), + ADD_DMA(YUVBO_R1), + ADD_DMA(YUVCO_R1), + ADD_DMA(YUVDO_R1), + ADD_DMA(YUVO_R2), + ADD_DMA(YUVBO_R2), + ADD_DMA(YUVO_R3), + ADD_DMA(YUVBO_R3), + ADD_DMA(YUVCO_R3), + ADD_DMA(YUVDO_R3), + ADD_DMA(YUVO_R4), + ADD_DMA(YUVBO_R4), + ADD_DMA(YUVO_R5), + ADD_DMA(YUVBO_R5), +}; + +static void mtk_cam_dump_dma_err_st(struct device *dev, void __iomem *base, + const char *prefix, + const struct reg_to_dump *from, + const struct reg_to_dump *to) +{ + struct buffered_logger log; + int err_found = 0; + int err_st; + + mtk_cam_init_logger(&log, dev, mtk_cam_log_handle_limited); + mtk_cam_log_set_prefix(&log, "%s", prefix); + + while (from < to) { + err_st = readl_relaxed(base + from->reg); + + /* [15:0] ERR_STAT */ + if (err_st & 0xffff) { + mtk_cam_log_push(&log, " %s: 0x%08x", + from->name, err_st); + err_found = 1; + } + from++; + } + + if (err_found) + mtk_cam_log_flush(&log); +} + +void mtk_cam_raw_dump_dma_err_st(struct device *dev, void __iomem *base) +{ + mtk_cam_dump_dma_err_st(dev, base, "RAW DMA_ERR", + raw_dma_list, + raw_dma_list + ARRAY_SIZE(raw_dma_list)); +} + +void mtk_cam_yuv_dump_dma_err_st(struct device *dev, void __iomem *base) +{ + mtk_cam_dump_dma_err_st(dev, base, "YUV DMA_ERR", + yuv_dma_list, + yuv_dma_list + ARRAY_SIZE(yuv_dma_list)); +} + +void mtk_cam_dump_req_rdy_status(struct device *dev, + void __iomem *base, void __iomem *yuvbase) +{ + dev_dbg_ratelimited(dev, + "REQ RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(base + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD5_REQ_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD6_REQ_STAT)); + dev_dbg_ratelimited(dev, + "RDY RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(base + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD5_RDY_STAT), + readl_relaxed(base + REG_CTL_RAW_MOD6_RDY_STAT)); + dev_dbg_ratelimited(dev, + "REQ YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(yuvbase + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD4_REQ_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD5_REQ_STAT)); + dev_dbg_ratelimited(dev, + "RDY YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(yuvbase + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD4_RDY_STAT), + readl_relaxed(yuvbase + REG_CTL_RAW_MOD5_RDY_STAT)); +} + +void mtk_cam_dump_dma_debug(struct device *dev, + void __iomem *dmatop_base, + const char *dma_name, + struct dma_debug_item *items, int n) +{ + void __iomem *dbg_sel = dmatop_base + 0x70; + void __iomem *dbg_port = dmatop_base + 0x74; + int i = 0; + unsigned int vals[16]; + + if (n >= 16) { + dev_dbg(dev, "%s: should enlarge array size for n(%d)\n", + __func__, n); + return; + } + + for (i = 0; i < n; i++) { + writel(items[i].debug_sel, dbg_sel); + if (readl(dbg_sel) != items[i].debug_sel) + dev_dbg(dev, "failed to write dbg_sel %08x\n", + items[i].debug_sel); + + vals[i] = readl(dbg_port); + }; + + dev_dbg(dev, "%s: %s, n = %d", __func__, dma_name, n); + for (i = 0; i < n; i++) + dev_dbg(dev, "%08x: %08x [%s]\n", + items[i].debug_sel, vals[i], items[i].msg); +} + +void mtk_cam_set_topdebug_rdyreq(struct device *dev, + void __iomem *base, void __iomem *yuvbase, + u32 event) +{ + u32 val = event << 16 | 0xa << 12; + + writel(val, base + REG_CTL_DBG_SET); + writel(event, base + REG_CTL_DBG_SET2); + writel(val, yuvbase + REG_CTL_DBG_SET); + dev_info(dev, + "set CAMCTL_DBG_SET2/CAMCTL_DBG_SET (RAW/YUV) 0x%08x/0x%08x\n", + event, val); +} + +void mtk_cam_dump_topdebug_rdyreq(struct device *dev, + void __iomem *base, void __iomem *yuvbase) +{ + static const u32 debug_sel[] = { + /* req group 1~7 */ + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, + /* rdy group 1~7 */ + 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, + /* latched_events */ + 0xF, + }; + void __iomem *dbg_set; + void __iomem *dbg_port; + u32 set; + int i; + + /* CAMCTL_DBG_SET + * CAMCTL_SNAPSHOT_SEL [23:16] + * CAMCTL_DEBUG_TOP_SEL [15:12] + * CAMCTL_DEBUG_SEL [11: 8] + * CAMCTL_DEBUG_MOD_SEL [ 7: 0] + */ + + /* CAMCTL_DEBUG_MOD_SEL + * 0: tg_scq_cnt_sub_pass1_done + * 1: rdyreq_dbg_data + */ + + dbg_set = base + REG_CTL_DBG_SET; + dbg_port = base + REG_CTL_DBG_PORT; + + set = (readl(dbg_set) & 0xfff000) | 0x1; + for (i = 0; i < ARRAY_SIZE(debug_sel); i++) { + writel(set | debug_sel[i] << 8, dbg_set); + dev_info(dev, "RAW debug_set 0x%08x port 0x%08x\n", + readl(dbg_set), readl(dbg_port)); + } + + dbg_set = yuvbase + REG_CTL_DBG_SET; + dbg_port = yuvbase + REG_CTL_DBG_PORT; + + set = (readl(dbg_set) & 0xfff000) | 0x1; + for (i = 0; i < ARRAY_SIZE(debug_sel); i++) { + writel(set | debug_sel[i] << 8, dbg_set); + dev_info(dev, "YUV debug_set 0x%08x port 0x%08x\n", + readl(dbg_set), readl(dbg_port)); + } +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.h new file mode 100644 index 000000000000..8d457403a5b0 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-raw_debug.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef _MTK_CAM_RAW_DEBUG_H +#define _MTK_CAM_RAW_DEBUG_H + +enum topdebug_event { + ALL_THE_TIME = BIT(0), + TG_OVERRUN = BIT(1), + CQ_MAIN_VS_ERR = BIT(2), + CQ_SUB_VS_ERR = BIT(3), + RAW_DMA_ERR = BIT(4), + YUV_DMA_ERR = BIT(5), +}; + +struct dma_debug_item { + unsigned int debug_sel; + const char *msg; +}; + +void mtk_cam_raw_dump_fbc(struct device *dev, + void __iomem *base, void __iomem *yuvbase); +void mtk_cam_raw_dump_dma_err_st(struct device *dev, void __iomem *base); +void mtk_cam_yuv_dump_dma_err_st(struct device *dev, void __iomem *yuvbase); +void mtk_cam_dump_req_rdy_status(struct device *dev, + void __iomem *base, void __iomem *yuvbase); +void mtk_cam_dump_dma_debug(struct device *dev, + void __iomem *dmatop_base, + const char *dma_name, + struct dma_debug_item *items, int n); +void mtk_cam_set_topdebug_rdyreq(struct device *dev, + void __iomem *base, void __iomem *yuvbase, + u32 event); +void mtk_cam_dump_topdebug_rdyreq(struct device *dev, + void __iomem *base, void __iomem *yuvbase); + +#endif /* _MTK_CAM_RAW_DEBUG_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h new file mode 100644 index 000000000000..b775e6c30aa1 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_camera-v4l2-controls.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAMERA_V4l2_CONTROLS_H +#define __MTK_CAMERA_V4l2_CONTROLS_H + +#include +#include +#include + +/* Allowed value of V4L2_CID_MTK_CAM_RAW_PATH_SELECT */ +#define V4L2_MTK_CAM_RAW_PATH_SELECT_BPC 1 +#define V4L2_MTK_CAM_RAW_PATH_SELECT_FUS 3 +#define V4L2_MTK_CAM_RAW_PATH_SELECT_DGN 4 +#define V4L2_MTK_CAM_RAW_PATH_SELECT_LSC 5 +#define V4L2_MTK_CAM_RAW_PATH_SELECT_LTM 7 + +#define V4L2_MBUS_FRAMEFMT_PAD_ENABLE BIT(1) + +#define MEDIA_BUS_FMT_MTISP_SBGGR10_1X10 0x8001 +#define MEDIA_BUS_FMT_MTISP_SBGGR12_1X12 0x8002 +#define MEDIA_BUS_FMT_MTISP_SBGGR14_1X14 0x8003 +#define MEDIA_BUS_FMT_MTISP_SGBRG10_1X10 0x8004 +#define MEDIA_BUS_FMT_MTISP_SGBRG12_1X12 0x8005 +#define MEDIA_BUS_FMT_MTISP_SGBRG14_1X14 0x8006 +#define MEDIA_BUS_FMT_MTISP_SGRBG10_1X10 0x8007 +#define MEDIA_BUS_FMT_MTISP_SGRBG12_1X12 0x8008 +#define MEDIA_BUS_FMT_MTISP_SGRBG14_1X14 0x8009 +#define MEDIA_BUS_FMT_MTISP_SRGGB10_1X10 0x800a +#define MEDIA_BUS_FMT_MTISP_SRGGB12_1X12 0x800b +#define MEDIA_BUS_FMT_MTISP_SRGGB14_1X14 0x800c +#define MEDIA_BUS_FMT_MTISP_BAYER8_UFBC 0x800d +#define MEDIA_BUS_FMT_MTISP_BAYER10_UFBC 0x800e +#define MEDIA_BUS_FMT_MTISP_BAYER12_UFBC 0x8010 +#define MEDIA_BUS_FMT_MTISP_BAYER14_UFBC 0x8011 +#define MEDIA_BUS_FMT_MTISP_BAYER16_UFBC 0x8012 +#define MEDIA_BUS_FMT_MTISP_NV12 0x8013 +#define MEDIA_BUS_FMT_MTISP_NV21 0x8014 +#define MEDIA_BUS_FMT_MTISP_NV12_10 0x8015 +#define MEDIA_BUS_FMT_MTISP_NV21_10 0x8016 +#define MEDIA_BUS_FMT_MTISP_NV12_10P 0x8017 +#define MEDIA_BUS_FMT_MTISP_NV21_10P 0x8018 +#define MEDIA_BUS_FMT_MTISP_NV12_12 0x8019 +#define MEDIA_BUS_FMT_MTISP_NV21_12 0x801a +#define MEDIA_BUS_FMT_MTISP_NV12_12P 0x801b +#define MEDIA_BUS_FMT_MTISP_NV21_12P 0x801c +#define MEDIA_BUS_FMT_MTISP_YUV420 0x801d +#define MEDIA_BUS_FMT_MTISP_NV12_UFBC 0x801e +#define MEDIA_BUS_FMT_MTISP_NV21_UFBC 0x8020 +#define MEDIA_BUS_FMT_MTISP_NV12_10_UFBC 0x8021 +#define MEDIA_BUS_FMT_MTISP_NV21_10_UFBC 0x8022 +#define MEDIA_BUS_FMT_MTISP_NV12_12_UFBC 0x8023 +#define MEDIA_BUS_FMT_MTISP_NV21_12_UFBC 0x8024 +#define MEDIA_BUS_FMT_MTISP_NV16 0x8025 +#define MEDIA_BUS_FMT_MTISP_NV61 0x8026 +#define MEDIA_BUS_FMT_MTISP_NV16_10 0x8027 +#define MEDIA_BUS_FMT_MTISP_NV61_10 0x8028 +#define MEDIA_BUS_FMT_MTISP_NV16_10P 0x8029 +#define MEDIA_BUS_FMT_MTISP_NV61_10P 0x802a + +#define MTK_CAM_RESOURCE_DEFAULT 0xFFFF + +#endif /* __MTK_CAMERA_V4l2_CONTROLS_H */ From patchwork Wed Oct 9 11:15:46 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: 13828189 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 C6B43CF0458 for ; Wed, 9 Oct 2024 11:23:07 +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=jhcL4I8ft5n2pnG/npyKdkYL5Gwk7YmR5PwHQkPcvCQ=; b=Oxbm+MKC/E0oO6HtWW50nZ2gyZ mgXSOe9sHyvjMhYrSy9Bug7NhWPB723JBUsk5xMGT17qaexFFVeYSLtT1GYYHB31CcfBzgUKA6YpH F8lQk/1mGQeEf1yPAvSL07tB9SnJavYr8PvE5X5qGuRbJVW1iJ8usFkK+ZKcpanZnwDQM8vd5Wb4i nFOF16tZmdMe907ZtJL6vkCxnauNev+rtl3agPfHrGGJSo/uF0mSLMFB47Xvt3PnjG5HPlkTmuSRv 55NbIGrdgNzfEG+zcx6NHeU9DP/4/yiyS2piA9h8vrSgZTfbWwgUWTvleStLsZF/7u+sqPbx+3r8m pTgwWshg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUmY-000000092ny-1waq; Wed, 09 Oct 2024 11:23:06 +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-000000091Oi-3QJM for linux-mediatek@bombadil.infradead.org; Wed, 09 Oct 2024 11:16:46 +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=jhcL4I8ft5n2pnG/npyKdkYL5Gwk7YmR5PwHQkPcvCQ=; b=Csw5quAh9BXn9tT7GfSW7TS0Rq zTvVmNhWR3X9jywrupvFV0JyJBlKxFID4xTf21QrajPRsg4j7K1t++9WmGxd/LVODK82Q1yt7EWpa 86q+L8og4ecBjkdHZ7kEzBza7saOiN4e6Qc4/oG+WZYgK1k1iv3vb/XmJ8gJNyplA48zi1mVC2Twj QCDQfMVWCItuRxFOk5XHV5KtNP7DKjhGAPHzleMfdt+7Ok5xI7luNfLMK72SGVmodlSI0F/tJpK3b IhF2TGyRmj2WF6T0rB59t4QuGLzncCPlreLTKLhuwa/TVDWBRGfITAZqmj9CJcaIs4+t5oQCsZAVH 0ESAYPNg==; Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgH-00000004v7g-2eGx for linux-mediatek@lists.infradead.org; Wed, 09 Oct 2024 11:16:42 +0000 X-UUID: e3908ff0862f11efb3adad29d29602c1-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=jhcL4I8ft5n2pnG/npyKdkYL5Gwk7YmR5PwHQkPcvCQ=; b=RHuSS8mSXB0EeN2HnQXv02GbP7PUiK1hMwDoHIJhjsofTD7RmhTwXothB32mnYUzj5UDMrj815W76LcWqJcmRjudD0paCUVU3paFEkaGENy5W99Z0WGiiVbSHLx5zHTvW+WWHTIT5W47aGG6oA+bnHehuMHGaJw5NRfc85qDJx0=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:40cf5274-45ad-4f80-8385-e20c0f7e5fab,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:22a58926-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: e3908ff0862f11efb3adad29d29602c1-20241009 Received: from mtkmbs10n1.mediatek.inc [(172.21.101.34)] by mailgw01.mediatek.com (envelope-from ) (musrelay.mediatek.com ESMTP with TLSv1.2 ECDHE-RSA-AES256-GCM-SHA384 256/256) with ESMTP id 1623821281; Wed, 09 Oct 2024 04:16:11 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by mtkmbs11n1.mediatek.inc (172.21.101.185) 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:07 +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: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 05/10] media: platform: mediatek: add isp_7x camsys unit Date: Wed, 9 Oct 2024 19:15:46 +0800 Message-ID: <20241009111551.27052-6-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-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Introduces the top media device driver for the MediaTek ISP7X CAMSYS. The driver maintains the camera system, including sub-device management, DMA operations, and integration with the V4L2 framework. It handles request stream data, buffer management, and MediaTek-specific features, and pipeline management, streaming control, error handling mechanism. Additionally, it aggregates sub-drivers for the camera interface, raw and yuv pipelines. Signed-off-by: Shu-hsiang Yang --- .../isp/isp_7x/camsys/mtk_cam-timesync.c | 125 + .../isp/isp_7x/camsys/mtk_cam-timesync.h | 12 + .../isp/isp_7x/camsys/mtk_cam-ufbc-def.h | 59 + .../mediatek/isp/isp_7x/camsys/mtk_cam.c | 4168 +++++++++++++++++ .../mediatek/isp/isp_7x/camsys/mtk_cam.h | 733 +++ 5 files changed, 5097 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ufbc-def.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c new file mode 100644 index 000000000000..b333434d86c0 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (C) 2017 MediaTek Inc. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_cam-timesync.h" + +#define FILTER_DATAPOINTS 16 +#define FILTER_FREQ 10000000ULL /* 10 ms */ + +struct moving_average { + u64 last_time; + s64 input[FILTER_DATAPOINTS]; + s64 output; + u8 cnt; + u8 tail; +}; + +static struct moving_average moving_average_algo_mono; +static struct moving_average moving_average_algo_boot; +static DEFINE_SPINLOCK(moving_average_lock); + +static u64 arch_counter_to_ns(u64 cyc) +{ + /* arch counter is 13M */ + u64 num, max = ULLONG_MAX; + u32 mult = 161319385; + u32 shift = 21; + s64 nsec = 0; + + do_div(max, mult); + if (cyc > max) { + num = div64_u64(cyc, max); + nsec = (((u64)max * mult) >> shift) * num; + cyc -= num * max; + } + nsec += ((u64)cyc * mult) >> shift; + return nsec; +} + +static void moving_average_filter(struct moving_average *filter, + u64 base_time, u64 archcounter_time) +{ + int i = 0; + s64 avg = 0; + s64 ret_avg = 0; + + if (base_time < filter->last_time + FILTER_FREQ) + return; + + filter->last_time = base_time; + + filter->input[filter->tail++] = base_time - archcounter_time; + filter->tail &= (FILTER_DATAPOINTS - 1); + if (filter->cnt < FILTER_DATAPOINTS) + filter->cnt++; + + for (i = 1, avg = 0; i < filter->cnt; i++) + avg += (filter->input[i] - filter->input[0]); + ret_avg = div_s64(avg, filter->cnt) + filter->input[0]; + WRITE_ONCE(filter->output, ret_avg); +} + +static u64 get_filter_output(struct moving_average *filter) +{ + return READ_ONCE(filter->output); +} + +u64 mtk_cam_timesync_to_monotonic(u64 hwclock) +{ + unsigned long flags = 0; + u64 base_time = 0; + u64 archcounter_time = 0; + u64 reslut_time = 0; + + spin_lock(&moving_average_lock); + + local_irq_save(flags); + base_time = ktime_to_ns(ktime_get()); + archcounter_time = + arch_counter_to_ns(__arch_counter_get_cntvct_stable()); + local_irq_restore(flags); + + moving_average_filter(&moving_average_algo_mono, + base_time, archcounter_time); + + reslut_time = arch_counter_to_ns(hwclock) + + get_filter_output(&moving_average_algo_mono); + + spin_unlock(&moving_average_lock); + return reslut_time; +} + +u64 mtk_cam_timesync_to_boot(u64 hwclock) +{ + unsigned long flags = 0; + u64 base_time = 0; + u64 archcounter_time = 0; + u64 reslut_time = 0; + + spin_lock(&moving_average_lock); + + local_irq_save(flags); + base_time = ktime_get_boottime_ns(); + archcounter_time = + arch_counter_to_ns(__arch_counter_get_cntvct_stable()); + local_irq_restore(flags); + + moving_average_filter(&moving_average_algo_boot, + base_time, archcounter_time); + + reslut_time = arch_counter_to_ns(hwclock) + + get_filter_output(&moving_average_algo_boot); + + spin_unlock(&moving_average_lock); + return reslut_time; +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h new file mode 100644 index 000000000000..7a226bd1c0a9 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-timesync.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2017 MediaTek Inc. + */ + +#ifndef __ARCHCOUNTER_TIMESYNC__ +#define __ARCHCOUNTER_TIMESYNC__ + +u64 mtk_cam_timesync_to_monotonic(u64 hwclock); +u64 mtk_cam_timesync_to_boot(u64 hwclock); + +#endif diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ufbc-def.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ufbc-def.h new file mode 100644 index 000000000000..12fc415380fe --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ufbc-def.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Hung-Wen Hsieh + */ + +#ifndef __UFBC_DEF_H__ +#define __UFBC_DEF_H__ + +/** + * MediaTek Universal Frame Buffer Compression (UFBC) buffer header + * Caller must follow the bit stream buffer size and length table buffer size. + * + * Header Size + * Fixed size of 4096 bytes. Caller SHOULD NOT edit it. + * + * Bit Stream Size + * Bit stream width must be aligned to 64 pixel. + */ + +struct ufbc_buf_header { + /** Describe image resolution, unit in pixel. */ + u32 width; + /** Describe image resolution, unit in pixel. */ + u32 height; + /** Describe UFBC data plane count, UFBC supports maximum 2 planes. */ + u32 plane_count; + /** Describe the original image data bits per pixel of the given plane. */ + u32 bits_per_pixel[3]; + + /** + * Describe the offset of the given plane bit stream data in bytes, + * including header size. + */ + u32 bitstream_offset[3]; + /** Describe the bit stream data size in bytes of the given plane. */ + u32 bitstream_size[3]; + /** Describe the encoded data size in bytes of the given plane. */ + u32 bitstream_data_size[3]; + + /** + * Describe the offset of length table of the given plane, including + * header size. + */ + u32 table_offset[3]; + /** Describe the length table size of the given plane */ + u32 table_size[3]; + /** Describe the total buffer size, including buffer header. */ + u32 buffer_size; +}; + +struct ufbc_buffer_header { + union { + struct ufbc_buf_header header; + u8 bits[4096]; + }; +}; + +#endif /* __UFBC_DEF_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c new file mode 100644 index 000000000000..5773dc7352da --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.c @@ -0,0 +1,4168 @@ +// 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 "mtk_cam.h" +#include "mtk_cam-ctrl.h" +#include "mtk_cam-feature.h" +#include "mtk_cam-pool.h" +#include "mtk_cam-regs-mt8188.h" +#include "mtk_camera-v4l2-controls.h" +#include "mtk_cam-ufbc-def.h" +#include "mtk_cam-timesync.h" + +static unsigned int debug_ae; +module_param(debug_ae, uint, 0644); +MODULE_PARM_DESC(debug_ae, "activates debug ae info"); + +#define MTK_CAM_CIO_PAD_SRC PAD_SRC_RAW0 +#define MTK_CAM_CIO_PAD_SINK MTK_RAW_SINK +#define MTK_CAM_IPI_SEND_TIMEOUT 1000 +/* consider running_job_list depth 3*3 */ +#define RUNNING_JOB_DEPTH 9 + +static const struct of_device_id mtk_cam_of_ids[] = { + {.compatible = "mediatek,camisp",}, + {} +}; +MODULE_DEVICE_TABLE(of, mtk_cam_of_ids); + +/* + * All member of mtk_cam_request_stream_data which may be used + * after media_request_ioctl_reinit and before the next + * media_request_ioctl_queue must be clean here. For + * example, the pending set fmt, set selection, and sensor + * switch extension of camsys driver. + */ +static void +mtk_cam_req_s_data_clean(struct mtk_cam_request_stream_data *s_data) +{ + s_data->sensor = NULL; + s_data->flags = 0; +} + +static void +mtk_cam_req_pipe_s_data_clean(struct mtk_cam_request *req, int pipe_id, + int index) +{ + struct mtk_cam_request_stream_data *req_stream_data; + + req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, index); + if (req_stream_data) { + mtk_cam_req_s_data_clean(req_stream_data); + /** + * Notice that the we clean req_stream_data->bufs here so + * we should not use it after this function called on it. + * mtk_cam_vb2_return_all_buffers() uses another list + * of mtk_cam_video_device to keep the vb2 buffers to be clean. + */ + memset(req_stream_data->bufs, 0, sizeof(req_stream_data->bufs)); + } +} + +void mtk_cam_s_data_update_timestamp(struct mtk_cam_buffer *buf, + struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_ctx *ctx; + struct vb2_buffer *vb; + struct mtk_cam_video_device *node; + + ctx = mtk_cam_s_data_get_ctx(s_data); + if (!ctx) { + pr_info("%s: get ctx from s_data failed", __func__); + return; + } + + vb = &buf->vbb.vb2_buf; + node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + + buf->vbb.sequence = s_data->frame_seq_no; + if (vb->vb2_queue->timestamp_flags & V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC) + vb->timestamp = s_data->timestamp_mono; + else + vb->timestamp = s_data->timestamp; + + /* check buffer's timestamp */ + if (node->desc.dma_port == MTKCAM_IPI_RAW_META_STATS_CFG) + dev_dbg(ctx->cam->dev, + "%s:%s:vb sequence:%d, queue type:%d, timestamp_flags:0x%x, timestamp:%lld\n", + __func__, node->desc.name, buf->vbb.sequence, + vb->vb2_queue->type, vb->vb2_queue->timestamp_flags, + vb->timestamp); +} + +static void mtk_cam_req_return_pipe_buffers(struct mtk_cam_request *req, + int pipe_id, int index) +{ + struct mtk_cam_device *cam = + container_of(req->req.mdev, struct mtk_cam_device, media_dev); + struct mtk_cam_request_stream_data *s_data_pipe; + struct mtk_cam_buffer *buf_ret[MTK_RAW_TOTAL_NODES]; + struct mtk_cam_buffer *buf; + struct mtk_cam_video_device *node; + struct vb2_buffer *vb; + int buf_state; + u32 i, buf_ret_cnt = 0, buf_start = 0, buf_end = 0; + + s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, index); + if (!s_data_pipe) { + pr_info("%s: get s_data pipe failed", __func__); + return; + } + + if (is_raw_subdev(pipe_id)) { + buf_start = MTK_RAW_SINK_NUM; + buf_end = MTK_RAW_PIPELINE_PADS_NUM; + } + + for (i = buf_start; i < buf_end; i++) { + /* make sure do not touch req/s_data after vb2_buffe_done */ + buf = mtk_cam_s_data_get_vbuf(s_data_pipe, i); + if (!buf) + continue; + buf_ret[buf_ret_cnt++] = buf; + /* clean the stream data for req reinit case */ + mtk_cam_s_data_reset_vbuf(s_data_pipe, i); + } + + /* clean the req_stream_data being used right after request reinit */ + mtk_cam_req_pipe_s_data_clean(req, pipe_id, index); + + buf_state = atomic_read(&s_data_pipe->buf_state); + if (buf_state == -1) + buf_state = VB2_BUF_STATE_ERROR; + + dev_dbg(cam->dev, + "%s:%s: pipe_id(%d) buf_state(%d) buf_ret_cnt(%d)\n", __func__, + req->req.debug_str, pipe_id, buf_state, buf_ret_cnt); + + for (i = 0; i < buf_ret_cnt; i++) { + buf = buf_ret[i]; + vb = &buf->vbb.vb2_buf; + node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + if (node->uid.pipe_id != pipe_id) { + dev_info(cam->dev, + "%s:%s:node(%s): invalid pipe id (%d), should be (%d)\n", + __func__, req->req.debug_str, + node->desc.name, node->uid.pipe_id, pipe_id); + continue; + } + + if (atomic_read(&req->state) > MTK_CAM_REQ_STATE_PENDING) + mtk_cam_s_data_update_timestamp(buf, s_data_pipe); + + vb2_buffer_done(&buf->vbb.vb2_buf, buf_state); + } +} + +struct mtk_cam_request_stream_data * +mtk_cam_get_req_s_data(struct mtk_cam_ctx *ctx, unsigned int pipe_id, + unsigned int frame_seq_no) + +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtk_cam_request *req, *req_prev; + struct mtk_cam_request_stream_data *req_stream_data; + int i; + + spin_lock(&cam->running_job_lock); + list_for_each_entry_safe(req, req_prev, &cam->running_job_list, list) { + if (req->pipe_used & (1 << pipe_id)) { + for (i = 0; i < req->p_data[pipe_id].s_data_num; i++) { + req_stream_data = &req->p_data[pipe_id].s_data[i]; + if (req_stream_data->frame_seq_no == frame_seq_no) { + spin_unlock(&cam->running_job_lock); + return req_stream_data; + } + } + } + } + spin_unlock(&cam->running_job_lock); + + return NULL; +} + +struct mtk_cam_request *mtk_cam_get_req(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no) +{ + struct mtk_cam_request_stream_data *req_stream_data; + + req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, frame_seq_no); + if (!req_stream_data) + return NULL; + + return req_stream_data->req; +} + +bool watchdog_scenario(struct mtk_cam_ctx *ctx) +{ + if (ctx->sensor && !mtk_cam_is_m2m(ctx) && ctx->used_raw_num) + return true; + else + return false; +} + +static bool finish_cq_buf(struct mtk_cam_request_stream_data *req_stream_data) +{ + struct mtk_cam_ctx *ctx = req_stream_data->ctx; + struct mtk_cam_working_buf_entry *cq_buf_entry; + + if (!ctx->used_raw_num) + return false; + + spin_lock(&ctx->processing_buffer_list.lock); + + cq_buf_entry = req_stream_data->working_buf; + /* Check if the cq buffer is already finished */ + if (!cq_buf_entry || !cq_buf_entry->s_data) { + dev_info(ctx->cam->dev, + "%s:%s:ctx(%d):req(%d):working_buf is already release\n", + __func__, req_stream_data->req->req.debug_str, + ctx->stream_id, req_stream_data->frame_seq_no); + spin_unlock(&ctx->processing_buffer_list.lock); + return false; + } + + list_del(&cq_buf_entry->list_entry); + mtk_cam_s_data_reset_wbuf(req_stream_data); + ctx->processing_buffer_list.cnt--; + spin_unlock(&ctx->processing_buffer_list.lock); + + mtk_cam_working_buf_put(cq_buf_entry); + + dev_dbg(ctx->cam->dev, "put cq buf:%pad, %s\n", + &cq_buf_entry->buffer.iova, + req_stream_data->req->req.debug_str); + + return true; +} + +static void update_hw_mapping(struct mtk_cam_ctx *ctx, + struct mtkcam_ipi_config_param *config_param) +{ + /* raw config */ + config_param->maps[0].pipe_id = ctx->pipe->id; + config_param->maps[0].dev_mask = MTKCAM_SUBDEV_RAW_MASK & ctx->used_raw_dev; + config_param->n_maps = 1; +} + +static void mtk_cam_del_req_from_running(struct mtk_cam_ctx *ctx, + struct mtk_cam_request *req, int pipe_id) +{ + struct mtk_cam_request_stream_data *s_data; + + s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + dev_dbg(ctx->cam->dev, + "%s: %s: removed, req:%d, ctx:(%d/0x%x/0x%x), pipe:(%d/0x%x/0x%x) done_status:0x%x)\n", + __func__, req->req.debug_str, s_data->frame_seq_no, + ctx->stream_id, req->ctx_used, ctx->cam->streaming_ctx, + pipe_id, req->pipe_used, ctx->cam->streaming_pipe, + req->done_status); + + atomic_set(&req->state, MTK_CAM_REQ_STATE_COMPLETE); + spin_lock(&ctx->cam->running_job_lock); + list_del(&req->list); + ctx->cam->running_job_count--; + spin_unlock(&ctx->cam->running_job_lock); +} + +static void mtk_cam_req_works_clean(struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + char *dbg_str = mtk_cam_s_data_get_dbg_str(s_data); + + /* flush the sensor work */ + if (atomic_read(&s_data->sensor_work.is_queued)) { + kthread_flush_work(&s_data->sensor_work.work); + dev_dbg(ctx->cam->dev, + "%s:ctx(%d):%s:seq(%d): flushed sensor_work\n", + __func__, ctx->stream_id, dbg_str, s_data->frame_seq_no); + } +} + +static void mtk_cam_get_timestamp(struct mtk_cam_ctx *ctx, + struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_buffer *buf; + struct vb2_buffer *vb; + void *vaddr; + u64 *timestamp_addr; + u64 *fho_va; + + buf = mtk_cam_s_data_get_vbuf(s_data, MTK_RAW_META_OUT_0); + if (!buf) { + dev_info(ctx->cam->dev, + "ctx(%d): can't get MTK_RAW_META_OUT_0 buf from req(%d)\n", + ctx->stream_id, s_data->frame_seq_no); + return; + } + + vb = &buf->vbb.vb2_buf; + if (!vb) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get vb2 buf\n", + __func__, ctx->stream_id); + return; + } + + vaddr = vb2_plane_vaddr(&buf->vbb.vb2_buf, 0); + if (!vaddr) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get plane_vadd\n", + __func__, ctx->stream_id); + return; + } + + if (!s_data->working_buf->buffer.va || + s_data->working_buf->buffer.size == 0) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get working_buf\n", + __func__, ctx->stream_id); + return; + } + + fho_va = (u64 *)(s_data->working_buf->buffer.va + + s_data->working_buf->buffer.size - 64); + + timestamp_addr = camsys_get_timestamp_addr(vaddr); + *timestamp_addr = div_u64(mtk_cam_timesync_to_monotonic(*fho_va), 1000); + *(timestamp_addr + 1) = div_u64(mtk_cam_timesync_to_boot(*fho_va), 1000); + dev_dbg(ctx->cam->dev, + "timestamp TS:momo %llu us boot %llu us, TS_cnt:%llu\n", + *timestamp_addr, *(timestamp_addr + 1), *fho_va); +} + +int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx, + unsigned int dequeued_frame_seq_no, + int pipe_id) +{ + struct mtk_cam_request *req, *req_prev; + struct mtk_cam_request_stream_data *s_data, *s_data_pipe; + struct mtk_cam_request_stream_data *deq_s_data[RUNNING_JOB_DEPTH]; + struct mtk_raw_pipeline *pipe = ctx->pipe; + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_ae_debug_data ae_data; + int buf_state; + u32 dequeue_cnt, s_data_cnt, handled_cnt; + bool del_job, del_req; + bool unreliable = false; + unsigned int done_status_latch; + + memset(&ae_data, 0, sizeof(struct mtk_ae_debug_data)); + dequeue_cnt = 0; + s_data_cnt = 0; + spin_lock(&ctx->cam->running_job_lock); + list_for_each_entry_safe(req, req_prev, &ctx->cam->running_job_list, list) { + if (!(req->pipe_used & (1 << pipe_id))) + continue; + + s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + if (!s_data) { + dev_info(ctx->cam->dev, + "frame_seq:%d[ctx=%d,pipe=%d], de-queue request not found\n", + dequeued_frame_seq_no, ctx->stream_id, pipe_id); + continue; + } + + if (s_data->frame_seq_no > dequeued_frame_seq_no) + goto STOP_SCAN; + + deq_s_data[s_data_cnt++] = s_data; + if (s_data_cnt >= RUNNING_JOB_DEPTH) { + dev_info(ctx->cam->dev, + "%s:%s:ctx(%d):pipe(%d):seq(%d/%d) dequeue s_data over local buffer cnt(%d)\n", + __func__, req->req.debug_str, ctx->stream_id, pipe_id, + s_data->frame_seq_no, dequeued_frame_seq_no, + s_data_cnt); + goto STOP_SCAN; + } + } + +STOP_SCAN: + spin_unlock(&ctx->cam->running_job_lock); + + for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) { + s_data = deq_s_data[handled_cnt]; + del_req = false; + del_job = false; + req = mtk_cam_s_data_get_req(s_data); + if (!req) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):pipe(%d):seq(%d) req not found\n", + __func__, ctx->stream_id, pipe_id, + s_data->frame_seq_no); + continue; + } + + spin_lock(&req->done_status_lock); + + if (req->done_status & 1 << pipe_id) { + /* already handled by another job done work */ + spin_unlock(&req->done_status_lock); + continue; + } + + /* Check whether all pipelines of single ctx are done */ + req->done_status |= 1 << pipe_id; + if ((req->done_status & ctx->streaming_pipe) == + (req->pipe_used & ctx->streaming_pipe)) + del_job = true; + + if ((req->done_status & ctx->cam->streaming_pipe) == + (req->pipe_used & ctx->cam->streaming_pipe)) { + if (MTK_CAM_REQ_STATE_RUNNING == + atomic_cmpxchg(&req->state, + MTK_CAM_REQ_STATE_RUNNING, + MTK_CAM_REQ_STATE_DELETING)) + del_req = true; + } + done_status_latch = req->done_status; + spin_unlock(&req->done_status_lock); + + if (is_raw_subdev(pipe_id) && debug_ae) { + mtk_cam_raw_dump_aa_info(ctx, &ae_data); + dev_dbg(ctx->cam->dev, + "%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d),metaout,size(%u,%u),AA(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)(0x%llx,0x%llx,0x%llx,0x%llx)\n", + __func__, req->req.debug_str, ctx->stream_id, pipe_id, + dequeued_frame_seq_no, s_data->frame_seq_no, + done_status_latch, req->pipe_used, + ctx->streaming_pipe, ctx->cam->streaming_pipe, + del_job, del_req, + pipe->res_config.sink_fmt.width, + pipe->res_config.sink_fmt.height, + ae_data.obc_r1_sum[0], ae_data.obc_r1_sum[1], + ae_data.obc_r1_sum[2], ae_data.obc_r1_sum[3], + ae_data.obc_r2_sum[0], ae_data.obc_r2_sum[1], + ae_data.obc_r2_sum[2], ae_data.obc_r2_sum[3], + ae_data.obc_r3_sum[0], ae_data.obc_r3_sum[1], + ae_data.obc_r3_sum[2], ae_data.obc_r3_sum[3], + ae_data.aa_sum[0], ae_data.aa_sum[1], + ae_data.aa_sum[2], ae_data.aa_sum[3], + ae_data.ltm_sum[0], ae_data.ltm_sum[1], + ae_data.ltm_sum[2], ae_data.ltm_sum[3]); + } else { + dev_dbg(ctx->cam->dev, + "%s:%s:ctx(%d):pipe(%d):de-queue seq(%d):handle seq(%d),done(0x%x),pipes(req:0x%x,ctx:0x%x,all:0x%x),del_job(%d),del_req(%d)\n", + __func__, req->req.debug_str, ctx->stream_id, pipe_id, + dequeued_frame_seq_no, s_data->frame_seq_no, + done_status_latch, req->pipe_used, + ctx->streaming_pipe, ctx->cam->streaming_pipe, + del_job, del_req); + } + + if (is_raw_subdev(pipe_id)) { + mtk_cam_get_timestamp(ctx, s_data); + mtk_cam_req_dbg_works_clean(s_data); + mtk_cam_req_works_clean(s_data); + } + + if (del_job) { + atomic_dec(&ctx->running_s_data_cnt); + mtk_camsys_state_delete(ctx, sensor_ctrl, req); + + /* release internal buffers */ + finish_cq_buf(s_data); + } + + if (del_req) { + mtk_cam_del_req_from_running(ctx, req, pipe_id); + dequeue_cnt++; + } + + /* release vb2 buffers of the pipe */ + s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0); + if (!s_data_pipe) { + dev_info(ctx->cam->dev, + "%s:%s:ctx(%d):pipe(%d):seq(%d) s_data_pipe not found\n", + __func__, req->req.debug_str, ctx->stream_id, pipe_id, + s_data->frame_seq_no); + continue; + } + + if (s_data->frame_seq_no < dequeued_frame_seq_no) { + buf_state = VB2_BUF_STATE_ERROR; + dev_dbg(ctx->cam->dev, + "%s:%s:pipe(%d) seq:%d, time:%lld drop, ctx:%d\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no, s_data->timestamp, + ctx->stream_id); + } else if (s_data->state.estate == E_STATE_DONE_MISMATCH) { + buf_state = VB2_BUF_STATE_ERROR; + dev_dbg(ctx->cam->dev, + "%s:%s:pipe(%d) seq:%d, state done mismatch", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } else if (unreliable) { + buf_state = VB2_BUF_STATE_ERROR; + dev_dbg(ctx->cam->dev, + "%s:%s:pipe(%d) seq:%d, done (unreliable)", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } else { + buf_state = VB2_BUF_STATE_DONE; + dev_dbg(ctx->cam->dev, + "%s:%s:pipe(%d) seq:%d, done success", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + + if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) { + /* handle vb2_buffer_done */ + if (mtk_cam_req_put(req, pipe_id)) + dev_dbg(ctx->cam->dev, + "%s:%s:pipe(%d) return request", + __func__, req->req.debug_str, pipe_id); + } + } + + return dequeue_cnt; +} + +void mtk_cam_dev_req_clean_pending(struct mtk_cam_device *cam, int pipe_id, + int buf_state) +{ + struct mtk_cam_request *req, *req_prev; + struct mtk_cam_request_stream_data *s_data_pipe; + struct list_head *pending = &cam->pending_job_list; + struct list_head req_clean_list; + + /* Consider pipe bufs and pipe_used only */ + + INIT_LIST_HEAD(&req_clean_list); + + spin_lock(&cam->pending_job_lock); + list_for_each_entry_safe(req, req_prev, pending, list) { + /* update pipe_used */ + req->pipe_used &= ~(1 << pipe_id); + list_add_tail(&req->cleanup_list, &req_clean_list); + if (!(req->pipe_used & cam->streaming_pipe)) { + /* the last pipe */ + list_del(&req->list); + dev_info(cam->dev, + "%s:%s:pipe(%d) remove req from pending list\n", + __func__, req->req.debug_str, pipe_id); + } + } + spin_unlock(&cam->pending_job_lock); + + list_for_each_entry_safe(req, req_prev, &req_clean_list, cleanup_list) { + list_del(&req->cleanup_list); + s_data_pipe = mtk_cam_req_get_s_data(req, pipe_id, 0); + if (!s_data_pipe) { + dev_dbg(cam->dev, + "%s:%s:pipe_used(0x%x):pipe(%d) s_data_pipe not found\n", + __func__, req->req.debug_str, req->pipe_used, + pipe_id); + continue; + } + if (mtk_cam_s_data_set_buf_state(s_data_pipe, buf_state)) { + /* handle vb2_buffer_done */ + if (mtk_cam_req_put(req, pipe_id)) + dev_dbg(cam->dev, + "%s:%s:pipe_used(0x%x):pipe(%d) return request", + __func__, req->req.debug_str, + req->pipe_used, pipe_id); + /* DO NOT touch req after here */ + } + } +} + +void mtk_cam_dev_req_cleanup(struct mtk_cam_ctx *ctx, int pipe_id, int buf_state) +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtk_cam_request *req, *req_prev; + struct mtk_cam_request_stream_data *s_data, *s_data_pipe; + struct mtk_cam_request_stream_data *clean_s_data[RUNNING_JOB_DEPTH]; + struct list_head *running = &cam->running_job_list; + unsigned int other_pipes, done_status; + int i; + u32 num_s_data, s_data_cnt, handled_cnt; + bool need_clean_req; + + mtk_cam_dev_req_clean_pending(cam, pipe_id, buf_state); + + s_data_cnt = 0; + spin_lock(&cam->running_job_lock); + list_for_each_entry_safe(req, req_prev, running, list) { + /* only handle requests belong to current ctx */ + if (!(req->pipe_used & ctx->streaming_pipe)) + continue; + + num_s_data = mtk_cam_req_get_num_s_data(req, pipe_id); + /* reverse the order for release req with s_data_0 */ + for (i = num_s_data - 1; i >= 0; i--) { + s_data = mtk_cam_req_get_s_data(req, pipe_id, i); + if (s_data) { + clean_s_data[s_data_cnt++] = s_data; + if (s_data_cnt >= RUNNING_JOB_DEPTH) { + dev_info(cam->dev, + "%s: over local buffer cnt(%d)\n", + __func__, s_data_cnt); + goto STOP_SCAN; + } + } else { + dev_info(cam->dev, + "%s:%s:pipe(%d): get s_data failed\n", + __func__, req->req.debug_str, pipe_id); + } + } + } +STOP_SCAN: + spin_unlock(&cam->running_job_lock); + + for (handled_cnt = 0; handled_cnt < s_data_cnt; handled_cnt++) { + s_data = clean_s_data[handled_cnt]; + req = mtk_cam_s_data_get_req(s_data); + if (!req) { + pr_info("ERR can't be recovered: invalid req found in s_data_clean_list\n"); + continue; + } + + if (ctx->used_raw_num != 0) { + if (s_data->index > 0) + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): clean s_data_%d, raw_feature(%lld)\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no, s_data->index, + ctx->pipe->feature_pending); + else + dev_dbg(cam->dev, + "%s:%s:pipe(%d):seq(%d): clean s_data_%d, raw_feature(%lld)\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no, s_data->index, + ctx->pipe->feature_pending); + } + + /* Cancel s_data's works before we clean up the data */ + if (atomic_read(&s_data->sensor_work.is_queued)) { + kthread_cancel_work_sync(&s_data->sensor_work.work); + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): cancel sensor_work\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + atomic_set(&s_data->sensor_work.is_queued, 1); + + if (atomic_read(&s_data->meta1_done_work.is_queued)) { + cancel_work_sync(&s_data->meta1_done_work.work); + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): cancel AFO done_work\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + atomic_set(&s_data->meta1_done_work.is_queued, 1); + + if (atomic_read(&s_data->frame_done_work.is_queued)) { + cancel_work_sync(&s_data->frame_done_work.work); + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): cancel frame_done_work\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + atomic_set(&s_data->frame_done_work.is_queued, 1); + + if (atomic_read(&s_data->dbg_exception_work.state) == + MTK_CAM_REQ_DBGWORK_S_PREPARED) { + atomic_set(&s_data->dbg_exception_work.state, + MTK_CAM_REQ_DBGWORK_S_CANCEL); + mtk_cam_debug_wakeup(&ctx->cam->debug_exception_waitq); + cancel_work_sync(&s_data->dbg_exception_work.work); + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): cancel dbg_exception_work\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + atomic_set(&s_data->dbg_exception_work.state, + MTK_CAM_REQ_DBGWORK_S_FINISHED); + + if (atomic_read(&s_data->dbg_work.state) == + MTK_CAM_REQ_DBGWORK_S_PREPARED) { + cancel_work_sync(&s_data->dbg_work.work); + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): cancel dbg_work\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + atomic_set(&s_data->dbg_work.state, + MTK_CAM_REQ_DBGWORK_S_FINISHED); + + spin_lock(&req->done_status_lock); + dev_dbg(cam->dev, + "%s:%s:pipe(%d):seq(%d):req staus before clean:done(0x%x),pipe_used(0x%x)\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no, req->done_status, req->pipe_used); + + need_clean_req = false; + if (atomic_read(&req->state) == MTK_CAM_REQ_STATE_RUNNING) { + /* mark request status to done for release */ + req->done_status |= req->pipe_used & (1 << pipe_id); + if (req->done_status == req->pipe_used && + MTK_CAM_REQ_STATE_RUNNING == + atomic_cmpxchg(&req->state, + MTK_CAM_REQ_STATE_RUNNING, + MTK_CAM_REQ_STATE_DELETING)) + need_clean_req = true; + } + + /* if being the last one, check other pipes in the ctx */ + other_pipes = 0; + done_status = req->done_status; + if (need_clean_req) + other_pipes = ctx->streaming_pipe & ~(1 << pipe_id); + spin_unlock(&req->done_status_lock); + + /** + * Before remove the request, flush other pipe's done work + * in the same ctx to make sure mtk_cam_dev_job_done finished + */ + if (other_pipes) { + for (i = 0; i < MTKCAM_SUBDEV_MAX; i++) { + if (!(1 << i & other_pipes & done_status)) + continue; + + s_data_pipe = mtk_cam_req_get_s_data(req, i, 0); + if (!s_data_pipe) + continue; + + /** + * if done_status is marked, it means the work + * is running or complete + */ + if (flush_work(&s_data->frame_done_work.work)) + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): flush pipe(%d) frame_done_work\n", + __func__, req->req.debug_str, + pipe_id, s_data_pipe->frame_seq_no, + i); + } + } + + mtk_cam_complete_sensor_hdl(s_data); + mtk_cam_complete_raw_hdl(s_data); + /* + * reset fs state, if one sensor off and another one alive, + * Let the req be the single sensor case. + */ + mutex_lock(&req->fs.op_lock); + mtk_cam_fs_reset(&req->fs); + mutex_unlock(&req->fs.op_lock); + if (need_clean_req) { + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): remove req from running list\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + atomic_set(&req->state, MTK_CAM_REQ_STATE_CLEANUP); + spin_lock(&cam->running_job_lock); + list_del(&req->list); + cam->running_job_count--; + spin_unlock(&cam->running_job_lock); + } else { + dev_info(cam->dev, + "%s:%s:pipe(%d):seq(%d): skip remove req from running list\n", + __func__, req->req.debug_str, pipe_id, + s_data->frame_seq_no); + } + + if (mtk_cam_s_data_set_buf_state(s_data, buf_state)) { + if (s_data->index > 0) { + mtk_cam_req_return_pipe_buffers(req, pipe_id, + s_data->index); + } else { + /* handle vb2_buffer_done */ + if (mtk_cam_req_put(req, pipe_id)) + dev_dbg(cam->dev, + "%s:%s:pipe(%d) return request", + __func__, req->req.debug_str, + pipe_id); + } + } + } + + /* all bufs in this node should be returned by req */ + + dev_dbg(cam->dev, + "%s: cleanup all stream off req, streaming ctx:0x%x, streaming pipe:0x%x)\n", + __func__, cam->streaming_ctx, cam->streaming_pipe); +} + +void mtk_cam_req_get(struct mtk_cam_request *req, int pipe_id) +{ + atomic_inc(&req->ref_cnt); +} + +bool mtk_cam_req_put(struct mtk_cam_request *req, int pipe_id) +{ + bool ret = false; + + if (!atomic_dec_return(&req->ref_cnt)) + ret = true; + + /* release the pipe buf with s_data_pipe buf state */ + mtk_cam_req_return_pipe_buffers(req, pipe_id, 0); + + return ret; +} + +static int config_img_in_fmt(struct mtk_cam_device *cam, + struct mtk_cam_video_device *node, + const struct v4l2_format *cfg_fmt, + struct mtkcam_ipi_img_input *in_fmt) +{ + /* Check output & input image size dimension */ + if (node->desc.dma_port != MTKCAM_IPI_RAW_RAWI_2) { + dev_info(cam->dev, + "pipe(%d):dam_port(%d) only support MTKCAM_IPI_RAW_RAWI_2 now\n", + node->uid.pipe_id, node->desc.dma_port); + return -EINVAL; + } + + in_fmt->fmt.format = + mtk_cam_get_img_fmt(cfg_fmt->fmt.pix_mp.pixelformat); + if (in_fmt->fmt.format == MTKCAM_IPI_IMG_FMT_UNKNOWN) { + dev_info(cam->dev, "pipe: %d, node:%d unknown pixel fmt:%d\n", + node->uid.pipe_id, node->desc.dma_port, + cfg_fmt->fmt.pix_mp.pixelformat); + return -EINVAL; + } + + in_fmt->fmt.s.w = cfg_fmt->fmt.pix_mp.width; + in_fmt->fmt.s.h = cfg_fmt->fmt.pix_mp.height; + in_fmt->fmt.stride[0] = cfg_fmt->fmt.pix_mp.plane_fmt[0].bytesperline; + + dev_dbg(cam->dev, + "pipe: %d dma_port:%d size=%0dx%0d, stride:%d\n", + node->uid.pipe_id, node->desc.dma_port, in_fmt->fmt.s.w, + in_fmt->fmt.s.h, in_fmt->fmt.stride[0]); + + return 0; +} + +static int config_img_fmt(struct mtk_cam_device *cam, + struct mtk_cam_video_device *node, + const struct v4l2_format *cfg_fmt, + struct mtkcam_ipi_img_output *out_fmt, int sd_width, + int sd_height) +{ + /* Check output & input image size dimension */ + if (node->desc.dma_port == MTKCAM_IPI_RAW_IMGO && + (cfg_fmt->fmt.pix_mp.width > sd_width || + cfg_fmt->fmt.pix_mp.height > sd_height)) { + dev_err(cam->dev, "pipe: %d cfg(%d,%d) size is larger than sensor(%d,%d)\n", + node->uid.pipe_id, + cfg_fmt->fmt.pix_mp.width, cfg_fmt->fmt.pix_mp.height, + sd_width, sd_height); + return -EINVAL; + } + + out_fmt->fmt.format = + mtk_cam_get_img_fmt(cfg_fmt->fmt.pix_mp.pixelformat); + if (out_fmt->fmt.format == MTKCAM_IPI_IMG_FMT_UNKNOWN) { + dev_err(cam->dev, "pipe: %d, node:%d unknown pixel fmt:%d\n", + node->uid.pipe_id, node->desc.dma_port, + cfg_fmt->fmt.pix_mp.pixelformat); + return -EINVAL; + } + out_fmt->fmt.s.w = cfg_fmt->fmt.pix_mp.width; + out_fmt->fmt.s.h = cfg_fmt->fmt.pix_mp.height; + + /* not support multi-plane stride */ + out_fmt->fmt.stride[0] = cfg_fmt->fmt.pix_mp.plane_fmt[0].bytesperline; + + if (out_fmt->crop.p.x == 0 && out_fmt->crop.s.w == 0) { + out_fmt->crop.p.x = 0; + out_fmt->crop.p.y = 0; + out_fmt->crop.s.w = sd_width; + out_fmt->crop.s.h = sd_height; + } + + dev_dbg(cam->dev, + "pipe: %d dma_port:%d size=%0dx%0d, stride:%d, crop=%0dx%0d\n", + node->uid.pipe_id, node->desc.dma_port, out_fmt->fmt.s.w, + out_fmt->fmt.s.h, out_fmt->fmt.stride[0], out_fmt->crop.s.w, + out_fmt->crop.s.h); + + return 0; +} + +static void mtk_cam_req_set_vfmt(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *raw_pipeline, + struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_video_device *node; + struct mtk_cam_request *req; + struct v4l2_format *f; + struct v4l2_selection *s; + int i; + + req = mtk_cam_s_data_get_req(s_data); + + /* force update format to every video device before re-streamon */ + for (i = MTK_RAW_SINK_NUM + 1; i < MTK_RAW_META_OUT_BEGIN; i++) { + node = &raw_pipeline->vdev_nodes[i - MTK_RAW_SINK_NUM]; + f = mtk_cam_s_data_get_vfmt(s_data, node->desc.id); + if (!f) { + dev_info(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n", + __func__, req->req.debug_str, + node->uid.pipe_id, node->desc.name); + } else { + *f = node->active_fmt; + dev_dbg(cam->dev, + "%s:%s:pipe(%d):%s:save v4l2 fmt: pixelfmt(0x%x), w(%d), h(%d)\n", + __func__, req->req.debug_str, + node->uid.pipe_id, node->desc.name, + f->fmt.pix_mp.pixelformat, + f->fmt.pix_mp.width, f->fmt.pix_mp.height); + } + + s = mtk_cam_s_data_get_vsel(s_data, node->desc.id); + if (!s) { + dev_info(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vsel field to save\n", + __func__, req->req.debug_str, + node->uid.pipe_id, + node->desc.name); + } else { + *s = node->active_crop; + } + } +} + +static int mtk_cam_req_set_fmt(struct mtk_cam_device *cam, + struct mtk_cam_request *req) +{ + int pipe_id; + int pad; + struct mtk_cam_request_stream_data *stream_data; + struct mtk_raw_pipeline *raw_pipeline; + + dev_dbg(cam->dev, "%s:%s\n", __func__, req->req.debug_str); + for (pipe_id = 0; pipe_id < cam->max_stream_num; pipe_id++) { + if (req->pipe_used & (1 << pipe_id)) { + if (is_raw_subdev(pipe_id)) { + stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0); + raw_pipeline = &cam->raw.pipelines[pipe_id]; + mtk_cam_req_set_vfmt(cam, raw_pipeline, + stream_data); + pad = MTK_RAW_SINK; + + /* Set MEDIA_PAD_FL_SINK pad's fmt */ + for (pad = MTK_RAW_SINK_BEGIN; + pad < MTK_RAW_SOURCE_BEGIN; pad++) { + stream_data->pad_fmt[pad].format = + raw_pipeline->cfg[pad].mbus_fmt; + } + /* Set MEDIA_PAD_FL_SOURCE pad's fmt */ + for (pad = MTK_RAW_SOURCE_BEGIN; + pad < MTK_RAW_PIPELINE_PADS_NUM; pad++) { + stream_data->pad_fmt[pad].format = + raw_pipeline->cfg[pad].mbus_fmt; + } + } + } + } + return 0; +} + +static int mtk_cam_req_update_ctrl(struct mtk_raw_pipeline *raw_pipe, + struct mtk_cam_request_stream_data *s_data) +{ + char *debug_str = mtk_cam_s_data_get_dbg_str(s_data); + struct mtk_cam_request *req; + struct mtk_cam_req_raw_pipe_data *raw_pipe_data; + + raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data); + if (!raw_pipe_data) { + dev_err(raw_pipe->subdev.v4l2_dev->dev, + "%s: cannot find raw_pipe_data, pipe_id:%d, frm_seq:%d\n", + __func__, s_data->pipe_id, s_data->frame_seq_no); + return -EINVAL; + } + req = mtk_cam_s_data_get_req(s_data); + if (!req) { + dev_err(raw_pipe->subdev.v4l2_dev->dev, + "%s: cannot find req, pipe_id:%d, frm_seq:%d\n", + __func__, s_data->pipe_id, s_data->frame_seq_no); + return -EINVAL; + } + + /* clear seamless switch mode */ + raw_pipe->sensor_mode_update = 0; + mtk_cam_req_ctrl_setup(raw_pipe, req); + + s_data->feature.raw_feature = raw_pipe->feature_pending; + atomic_set(&s_data->first_setting_check, 0); + + dev_dbg(raw_pipe->subdev.v4l2_dev->dev, + "%s:%s:%s:raw_feature(0x%0x), sensor_mode_update(0x%0x)\n", + __func__, raw_pipe->subdev.name, debug_str, + s_data->feature.raw_feature, + raw_pipe->sensor_mode_update); + + if (raw_pipe->sensor_mode_update) + s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1; + + raw_pipe_data->res = raw_pipe->user_res; + + return 0; +} + +static int mtk_cam_fill_img_buf(struct mtkcam_ipi_img_output *img_out, + const struct v4l2_format *f, dma_addr_t daddr) +{ + u32 pixelformat = f->fmt.pix_mp.pixelformat; + u32 width = f->fmt.pix_mp.width; + u32 height = f->fmt.pix_mp.height; + const struct v4l2_plane_pix_format *plane = &f->fmt.pix_mp.plane_fmt[0]; + u32 stride = plane->bytesperline; + u32 aligned_width; + unsigned int addr_offset = 0; + int i; + + if (is_mtk_format(pixelformat)) { + const struct mtk_format_info *info; + + info = mtk_format_info(pixelformat); + if (!info) + return -EINVAL; + + aligned_width = stride / info->bpp[0]; + if (info->mem_planes == 1) { + if (is_yuv_ufo(pixelformat)) { + aligned_width = ALIGN(width, 64); + img_out->buf[0][0].iova = daddr; + img_out->fmt.stride[0] = aligned_width * info->bit_r_num + / info->bit_r_den; + img_out->buf[0][0].size = img_out->fmt.stride[0] * height; + img_out->buf[0][0].size += img_out->fmt.stride[0] * height / 2; + img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height; + img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height + / 2; + img_out->buf[0][0].size += sizeof(struct ufbc_buffer_header); + + pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n", + 0, img_out->fmt.stride[0], img_out->buf[0][0].size, + (unsigned long)img_out->buf[0][0].iova); + } else if (is_raw_ufo(pixelformat)) { + aligned_width = ALIGN(width, 64); + img_out->buf[0][0].iova = daddr; + img_out->fmt.stride[0] = aligned_width * info->bit_r_num / + info->bit_r_den; + img_out->buf[0][0].size = img_out->fmt.stride[0] * height; + img_out->buf[0][0].size += ALIGN((aligned_width / 64), 8) * height; + img_out->buf[0][0].size += sizeof(struct ufbc_buffer_header); + + pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n", + 0, img_out->fmt.stride[0], + img_out->buf[0][0].size, + (unsigned long)img_out->buf[0][0].iova); + } else { + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + + img_out->buf[0][i].iova = daddr + addr_offset; + img_out->fmt.stride[i] = info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv); + img_out->buf[0][i].size = img_out->fmt.stride[i] + * DIV_ROUND_UP(height, vdiv); + addr_offset += img_out->buf[0][i].size; + + pr_debug("plane:%d stride:%d plane_size:%d addr:0x%lx\n", + i, img_out->fmt.stride[i], + img_out->buf[0][i].size, + (unsigned long)img_out->buf[0][i].iova); + } + } + } else { + pr_debug("do not support non contiguous mplane\n"); + } + } else { + const struct v4l2_format_info *info; + + info = v4l2_format_info(pixelformat); + if (!info) + return -EINVAL; + + aligned_width = stride / info->bpp[0]; + if (info->mem_planes == 1) { + for (i = 0; i < info->comp_planes; i++) { + unsigned int hdiv = (i == 0) ? 1 : info->hdiv; + unsigned int vdiv = (i == 0) ? 1 : info->vdiv; + + img_out->buf[0][i].iova = daddr + addr_offset; + img_out->fmt.stride[i] = info->bpp[i] * + DIV_ROUND_UP(aligned_width, hdiv); + img_out->buf[0][i].size = img_out->fmt.stride[i] + * DIV_ROUND_UP(height, vdiv); + addr_offset += img_out->buf[0][i].size; + + pr_debug("stride:%d plane_size:%d addr:0x%lx\n", + img_out->fmt.stride[i], + img_out->buf[0][i].size, + (unsigned long)img_out->buf[0][i].iova); + } + } else { + pr_debug("do not support non contiguous mplane\n"); + } + } + + return 0; +} + +static void mtk_cam_config_raw_path(struct mtk_cam_device *cam, + struct mtkcam_ipi_frame_param *frame_param, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_video_device *node; + struct mtk_raw_pipeline *raw_pipeline; + + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + raw_pipeline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id); + if (!raw_pipeline) { + dev_err(cam->dev, "%s: cannot find raw_pipeline, pipe_id:%d\n", + __func__, node->uid.pipe_id); + return; + } + + if (raw_pipeline->res_config.raw_path == V4L2_MTK_CAM_RAW_PATH_SELECT_BPC) + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_AFTER_BPC; + else if (raw_pipeline->res_config.raw_path == V4L2_MTK_CAM_RAW_PATH_SELECT_FUS) + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_AFTER_FUS; + else if (raw_pipeline->res_config.raw_path == V4L2_MTK_CAM_RAW_PATH_SELECT_DGN) + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_AFTER_DGN; + else if (raw_pipeline->res_config.raw_path == V4L2_MTK_CAM_RAW_PATH_SELECT_LSC) + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_AFTER_LSC; + else if (raw_pipeline->res_config.raw_path == V4L2_MTK_CAM_RAW_PATH_SELECT_LTM) + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_AFTER_LTM; + else + /* un-processed raw frame */ + frame_param->raw_param.imgo_path_sel = MTKCAM_IPI_IMGO_UNPROCESSED; + + dev_dbg(cam->dev, "%s: node:%d fd:%d idx:%d raw_path(%d) ipi imgo_path_sel(%d))\n", + __func__, node->desc.id, buf->vbb.request_fd, buf->vbb.vb2_buf.index, + raw_pipeline->res_config.raw_path, frame_param->raw_param.imgo_path_sel); +} + +static void mtk_cam_config_raw_img_out_imgo(struct mtk_cam_device *cam, + struct mtkcam_ipi_frame_param *frame_param, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_video_device *node; + struct mtkcam_ipi_img_output *img_out; + unsigned int pixelformat; + + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + pixelformat = node->active_fmt.fmt.pix_mp.pixelformat; + img_out->buf[0][0].iova = buf->daddr; + if (is_raw_ufo(pixelformat)) + mtk_cam_fill_img_buf(img_out, &node->active_fmt, buf->daddr); +} + +/* Update dmo's buffer information except imgo (address and size) */ +static void mtk_cam_config_raw_img_out(struct mtk_cam_device *cam, + struct mtkcam_ipi_frame_param *frame_param, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_video_device *node; + struct mtkcam_ipi_img_output *img_out; + + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + mtk_cam_fill_img_buf(img_out, &node->active_fmt, buf->daddr); +} + +static int +mtk_cam_config_raw_img_fmt(struct mtk_cam_device *cam, + struct mtkcam_ipi_frame_param *frame_param, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_video_device *node; + struct mtkcam_ipi_img_output *img_out; + struct v4l2_mbus_framefmt *pfmt; + int sd_width, sd_height, ret; + struct mtk_raw_pipeline *raw_pipline; + + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + raw_pipline = mtk_cam_dev_get_raw_pipeline(cam, node->uid.pipe_id); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + + pfmt = &raw_pipline->cfg[MTK_RAW_SINK].mbus_fmt; + sd_width = pfmt->width; + sd_height = pfmt->height; + + img_out->uid.pipe_id = node->uid.pipe_id; + img_out->uid.id = node->desc.dma_port; + + img_out->crop.p.x = node->active_crop.r.left; + img_out->crop.p.y = node->active_crop.r.top; + img_out->crop.s.w = node->active_crop.r.width; + img_out->crop.s.h = node->active_crop.r.height; + + ret = config_img_fmt(cam, node, &node->active_fmt, img_out, + sd_width, sd_height); + if (ret) + return ret; + + return 0; +} + +/* Update raw_param.imgo_path_sel */ +static void mtk_cam_req_config_raw_path(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtkcam_ipi_frame_param *frame_param; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + frame_param = &s_data->frame_params; + + mtk_cam_config_raw_path(cam, frame_param, buf); +} + +/* + * Update: + * 1. imgo's buffer information (address and size) + * 2. rawi's buffer information (address and size) + */ +static int mtk_cam_req_config_raw_img_out_imgo(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtk_cam_request *req; + struct mtk_cam_video_device *node; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_img_output *img_out; + const struct v4l2_format *cfg_fmt; + unsigned int pixelformat; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + req = mtk_cam_s_data_get_req(s_data); + frame_param = &s_data->frame_params; + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id); + if (!cfg_fmt) { + dev_info(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n", + __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name); + return -EINVAL; + } + pixelformat = cfg_fmt->fmt.pix_mp.pixelformat; + img_out->buf[0][0].iova = buf->daddr; + if (is_raw_ufo(pixelformat)) + mtk_cam_fill_img_buf(img_out, cfg_fmt, buf->daddr); + + return 0; +} + +/* Update dmo's buffer information except imgo (address and size) */ +static int mtk_cam_req_config_raw_img_out(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtk_cam_request *req; + struct mtk_cam_video_device *node; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_img_output *img_out; + const struct v4l2_format *cfg_fmt; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + req = mtk_cam_s_data_get_req(s_data); + frame_param = &s_data->frame_params; + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id); + if (!cfg_fmt) { + dev_info(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n", + __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name); + return -EINVAL; + } + + mtk_cam_fill_img_buf(img_out, cfg_fmt, buf->daddr); + + return 0; +} + +static int +mtk_cam_req_config_raw_img_fmt(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtk_cam_request *req; + struct mtk_cam_video_device *node; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_img_output *img_out; + struct v4l2_mbus_framefmt *pfmt; + int sd_width, sd_height, ret; + const struct v4l2_format *cfg_fmt; + struct v4l2_selection *cfg_selection; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + req = mtk_cam_s_data_get_req(s_data); + frame_param = &s_data->frame_params; + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + + /* not support sub-sampling multi-plane buffer */ + img_out = &frame_param->img_outs[node->desc.id - MTK_RAW_SOURCE_BEGIN]; + cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id); + if (!cfg_fmt) { + dev_err(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n", + __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name); + return -EINVAL; + } + + cfg_selection = mtk_cam_s_data_get_vsel(s_data, node->desc.id); + if (!cfg_selection) { + dev_err(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vsel field to save\n", + __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name); + return -EINVAL; + } + + pfmt = mtk_cam_s_data_get_pfmt(s_data, MTK_RAW_SINK); + sd_width = pfmt->width; + sd_height = pfmt->height; + + img_out->uid.pipe_id = node->uid.pipe_id; + img_out->uid.id = node->desc.dma_port; + + img_out->crop.p.x = cfg_selection->r.left; + img_out->crop.p.y = cfg_selection->r.top; + img_out->crop.s.w = cfg_selection->r.width; + img_out->crop.s.h = cfg_selection->r.height; + + ret = config_img_fmt(cam, node, cfg_fmt, img_out, sd_width, sd_height); + if (ret) + return ret; + + return 0; +} + +static int +mtk_cam_req_config_raw_img_in_rawi2(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtk_cam_request *req; + struct mtk_cam_video_device *node; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_img_input *in_fmt; + const struct v4l2_format *cfg_fmt; + int ret; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + req = mtk_cam_s_data_get_req(s_data); + frame_param = &s_data->frame_params; + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + in_fmt = &frame_param->img_ins[node->desc.id - MTK_RAW_RAWI_2_IN]; + + cfg_fmt = mtk_cam_s_data_get_vfmt(s_data, node->desc.id); + if (!cfg_fmt) { + dev_info(cam->dev, + "%s:%s:pipe(%d):%s: can't find the vfmt field to save\n", + __func__, req->req.debug_str, node->uid.pipe_id, node->desc.name); + return -EINVAL; + } + + in_fmt->buf[0].iova = buf->daddr; + frame_param->raw_param.hardware_scenario = + MTKCAM_IPI_HW_PATH_OFFLINE_M2M; + + in_fmt->uid.pipe_id = node->uid.pipe_id; + in_fmt->uid.id = node->desc.dma_port; + ret = config_img_in_fmt(cam, node, cfg_fmt, in_fmt); + if (ret) + return ret; + + return 0; +} + +static int mtk_cam_req_update(struct mtk_cam_device *cam, + struct mtk_cam_request *req) +{ + struct media_request_object *obj, *obj_prev; + struct vb2_buffer *vb; + struct mtk_cam_buffer *buf; + struct mtk_cam_video_device *node; + struct mtk_cam_ctx *ctx; + struct mtk_cam_request_stream_data *req_stream_data; + int i, ctx_cnt; + int ret; + + dev_dbg(cam->dev, "update request:%s\n", req->req.debug_str); + + mtk_cam_req_set_fmt(cam, req); + + list_for_each_entry_safe(obj, obj_prev, &req->req.objects, list) { + if (!vb2_request_object_is_buffer(obj)) + continue; + vb = container_of(obj, struct vb2_buffer, req_obj); + buf = mtk_cam_vb2_buf_to_dev_buf(vb); + node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + + ctx = mtk_cam_find_ctx(cam, &node->vdev.entity); + if (!ctx) + return -EINVAL; + req->ctx_used |= 1 << ctx->stream_id; + + req_stream_data = mtk_cam_req_get_s_data(req, node->uid.pipe_id, 0); + req_stream_data->ctx = ctx; + req_stream_data->no_frame_done_cnt = 0; + atomic_set(&req_stream_data->sensor_work.is_queued, 0); + atomic_set(&req_stream_data->dbg_work.state, MTK_CAM_REQ_DBGWORK_S_INIT); + req_stream_data->dbg_work.dump_flags = 0; + atomic_set(&req_stream_data->dbg_exception_work.state, MTK_CAM_REQ_DBGWORK_S_INIT); + req_stream_data->dbg_exception_work.dump_flags = 0; + atomic_set(&req_stream_data->frame_done_work.is_queued, 0); + req->sync_id = (ctx->used_raw_num) ? ctx->pipe->sync_id : 0; + + /* not support TWIN independent AFO */ + if (ctx->used_raw_num && ctx->pipe->res_config.raw_num_used == 1) + req_stream_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT; + + /* update buffer format */ + switch (node->desc.dma_port) { + case MTKCAM_IPI_RAW_RAWI_2: + ret = mtk_cam_req_config_raw_img_in_rawi2(req_stream_data, buf); + if (ret) + return ret; + break; + case MTKCAM_IPI_RAW_IMGO: + mtk_cam_req_config_raw_path(req_stream_data, buf); + ret = mtk_cam_req_config_raw_img_out_imgo(req_stream_data, buf); + if (ret) + return ret; + + ret = mtk_cam_req_config_raw_img_fmt(req_stream_data, buf); + if (ret) + return ret; + break; + case MTKCAM_IPI_RAW_YUVO_1: + case MTKCAM_IPI_RAW_YUVO_2: + case MTKCAM_IPI_RAW_YUVO_3: + case MTKCAM_IPI_RAW_YUVO_4: + case MTKCAM_IPI_RAW_YUVO_5: + case MTKCAM_IPI_RAW_RZH1N2TO_1: + case MTKCAM_IPI_RAW_RZH1N2TO_2: + case MTKCAM_IPI_RAW_RZH1N2TO_3: + case MTKCAM_IPI_RAW_DRZS4NO_1: + case MTKCAM_IPI_RAW_DRZS4NO_2: + case MTKCAM_IPI_RAW_DRZS4NO_3: + ret = mtk_cam_req_config_raw_img_out(req_stream_data, buf); + if (ret) + return ret; + + ret = mtk_cam_req_config_raw_img_fmt(req_stream_data, buf); + if (ret) + return ret; + break; + case MTKCAM_IPI_RAW_META_STATS_CFG: + case MTKCAM_IPI_RAW_META_STATS_0: + case MTKCAM_IPI_RAW_META_STATS_1: + case MTKCAM_IPI_RAW_META_STATS_2: + break; + default: + /* Do nothing for the ports not related to crop settings */ + break; + } + } + + /* frame sync */ + /* prepare img working buf */ + ctx_cnt = 0; + for (i = 0; i < cam->max_stream_num; i++) { + if (!(1 << i & req->ctx_used)) + continue; + + /* internal fs */ + ctx_cnt++; + + ctx = &cam->ctxs[i]; + req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + if (!req_stream_data) + continue; + } + req->fs.target = ctx_cnt > 1 ? ctx_cnt : 0; + + return 0; +} + +/* Check all pipeline involved in the request are streamed on */ +static int mtk_cam_dev_req_is_stream_on(struct mtk_cam_device *cam, + struct mtk_cam_request *req) +{ + dev_dbg(cam->dev, + "%s: pipe_used(0x%x), streaming_pipe(0x%x), req(%s)\n", + __func__, req->pipe_used, cam->streaming_pipe, + req->req.debug_str); + return (req->pipe_used & cam->streaming_pipe) == req->pipe_used; +} + +static void mtk_cam_req_work_init(struct mtk_cam_req_work *work, + struct mtk_cam_request_stream_data *s_data) +{ + work->s_data = s_data; +} + +static void mtk_cam_req_s_data_init(struct mtk_cam_request *req, + u32 pipe_id, + u32 s_data_index) +{ + struct mtk_cam_request_stream_data *req_stream_data; + + req_stream_data = &req->p_data[pipe_id].s_data[s_data_index]; + req_stream_data->req = req; + req_stream_data->pipe_id = pipe_id; + req_stream_data->state.estate = E_STATE_READY; + req_stream_data->index = s_data_index; + atomic_set(&req_stream_data->buf_state, -1); + + /** + * req_stream_data->flags is cleaned by + * mtk_cam_req_s_data_clean () at previous job done + * and may by updated by qbuf before request enqueue + * so we don't reset it here. + */ + mtk_cam_req_work_init(&req_stream_data->seninf_s_fmt_work, req_stream_data); + mtk_cam_req_work_init(&req_stream_data->frame_work, req_stream_data); + mtk_cam_req_work_init(&req_stream_data->frame_done_work, req_stream_data); + mtk_cam_req_work_init(&req_stream_data->meta1_done_work, req_stream_data); + /** + * clean the param structs since we support req reinit. + * the mtk_cam_request may not be "zero" when it is + * enqueued. + */ + memset(&req_stream_data->frame_params, 0, + sizeof(req_stream_data->frame_params)); + + /* generally is single exposure */ + req_stream_data->frame_params.raw_param.exposure_num = 1; +} + +void mtk_cam_dev_req_try_queue(struct mtk_cam_device *cam) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_request *req, *req_prev; + struct mtk_cam_request_stream_data *s_data; + int i, s_data_flags; + int enqueue_req_cnt, job_count, s_data_cnt; + struct list_head equeue_list; + struct v4l2_ctrl_handler *hdl; + struct media_request_object *sensor_hdl_obj, *raw_hdl_obj, *obj; + unsigned long flags; + + if (!cam->streaming_ctx) { + dev_info(cam->dev, "streams are off\n"); + return; + } + + INIT_LIST_HEAD(&equeue_list); + + spin_lock(&cam->running_job_lock); + job_count = cam->running_job_count; + spin_unlock(&cam->running_job_lock); + + /* Pick up requests which are runnable */ + enqueue_req_cnt = 0; + spin_lock(&cam->pending_job_lock); + list_for_each_entry_safe(req, req_prev, &cam->pending_job_list, list) { + if (likely(mtk_cam_dev_req_is_stream_on(cam, req))) { + if (job_count + enqueue_req_cnt >= + RAW_PIPELINE_NUM * MTK_CAM_MAX_RUNNING_JOBS) { + dev_dbg(cam->dev, "jobs are full, job cnt(%d)\n", + job_count); + break; + } + dev_dbg(cam->dev, "%s job cnt(%d), allow req_enqueue(%s)\n", + __func__, job_count + enqueue_req_cnt, req->req.debug_str); + + enqueue_req_cnt++; + list_del(&req->list); + list_add_tail(&req->list, &equeue_list); + } + } + spin_unlock(&cam->pending_job_lock); + + if (!enqueue_req_cnt) + return; + + list_for_each_entry_safe(req, req_prev, &equeue_list, list) { + for (i = 0; i < cam->max_stream_num; i++) { + if (!(req->pipe_used & 1 << i)) + continue; + + /* Initialize ctx related s_data fields */ + ctx = &cam->ctxs[i]; + sensor_hdl_obj = NULL; + raw_hdl_obj = NULL; + s_data_flags = 0; + + /* Update frame_seq_no */ + s_data = mtk_cam_req_get_s_data(req, i, 0); + s_data->frame_seq_no = + atomic_inc_return(&ctx->enqueued_frame_seq_no); + if (is_raw_subdev(i) && ctx->sensor) { + s_data_cnt = + atomic_inc_return(&ctx->running_s_data_cnt); + s_data->sensor = ctx->sensor; + + spin_lock_irqsave(&req->req.lock, flags); + list_for_each_entry(obj, &req->req.objects, list) { + if (vb2_request_object_is_buffer(obj)) + continue; + + hdl = (struct v4l2_ctrl_handler *)obj->priv; + if (hdl == &ctx->pipe->ctrl_handler) + raw_hdl_obj = obj; + else if (hdl == ctx->sensor->ctrl_handler) + sensor_hdl_obj = obj; + } + spin_unlock_irqrestore(&req->req.lock, flags); + + if (raw_hdl_obj) { + s_data->flags |= + MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN; + s_data->raw_hdl_obj = raw_hdl_obj; + dev_dbg(cam->dev, + "%s:%s:ctx(%d): find pipe hdl\n", + __func__, req->req.debug_str, i); + } + + /* Apply raw subdev's ctrl */ + mtk_cam_req_update_ctrl(ctx->pipe, s_data); + + if (s_data->sensor && s_data->sensor->ctrl_handler && + sensor_hdl_obj) { + s_data->sensor_hdl_obj = sensor_hdl_obj; + dev_dbg(cam->dev, + "%s:%s:ctx(%d): find sensor(%s) hdl\n", + __func__, req->req.debug_str, i, + s_data->sensor->name); + s_data->flags |= + MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN; + } + + s_data_flags = s_data->flags; + + /* reload s_data */ + s_data->flags = s_data_flags; + s_data->raw_hdl_obj = raw_hdl_obj; + s_data->sensor_hdl_obj = sensor_hdl_obj; + + /* copy s_data content */ + if (req->p_data[i].s_data_num == 2) + dev_info(cam->dev, + "%s:req(%s): undefined s_data_1, raw_feature(%lld), s_data_cnt(%d)\n", + __func__, req->req.debug_str, + ctx->pipe->feature_pending, + s_data_cnt); + } else if (is_raw_subdev(i) && !ctx->sensor) { + /* pure m2m raw ctrl handle */ + s_data_cnt = + atomic_inc_return(&ctx->running_s_data_cnt); + + spin_lock_irqsave(&req->req.lock, flags); + list_for_each_entry(obj, &req->req.objects, list) { + if (vb2_request_object_is_buffer(obj)) + continue; + + hdl = (struct v4l2_ctrl_handler *)obj->priv; + if (hdl == &ctx->pipe->ctrl_handler) + raw_hdl_obj = obj; + } + spin_unlock_irqrestore(&req->req.lock, flags); + + if (raw_hdl_obj) { + s_data->flags |= + MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN; + s_data->raw_hdl_obj = raw_hdl_obj; + dev_dbg(cam->dev, + "%s:%s:ctx(%d): find pipe hdl, s_data_cnt(%d)\n", + __func__, req->req.debug_str, i, + s_data_cnt); + } + + /* Apply raw subdev's ctrl */ + mtk_cam_req_update_ctrl(ctx->pipe, s_data); + } + } + + if (mtk_cam_req_update(cam, req)) { + dev_info(cam->dev, + "%s:req(%s): invalid req settings which can't be recovered\n", + __func__, req->req.debug_str); + WARN_ON(1); + return; + } + + atomic_set(&req->state, MTK_CAM_REQ_STATE_RUNNING); + spin_lock(&cam->running_job_lock); + cam->running_job_count++; + list_del(&req->list); + list_add_tail(&req->list, &cam->running_job_list); + spin_unlock(&cam->running_job_lock); + mtk_cam_dev_req_enqueue(cam, req); + } +} + +static struct media_request *mtk_cam_req_alloc(struct media_device *mdev) +{ + struct mtk_cam_request *cam_req; + + cam_req = vzalloc(sizeof(*cam_req)); + spin_lock_init(&cam_req->done_status_lock); + mutex_init(&cam_req->fs.op_lock); + + return &cam_req->req; +} + +static void mtk_cam_req_free(struct media_request *req) +{ + struct mtk_cam_request *cam_req = to_mtk_cam_req(req); + + vfree(cam_req); +} + +static int mtk_cam_req_chk_job_list(struct mtk_cam_device *cam, + struct mtk_cam_request *new_req, + struct list_head *job_list, + char *job_list_name) +{ + if (!job_list || !job_list->prev || !job_list->prev->next || !new_req) { + dev_dbg(cam->dev, + "%s:%s: job_list, job_list->prev, job_list->prev->next, new_req can't be NULL\n", + __func__, job_list_name); + return -EINVAL; + } + + if (job_list->prev->next != job_list) { + dev_dbg(cam->dev, + "%s broken: job_list->prev->next(%p), job_list(%p), req(%s)\n", + job_list_name, job_list->prev->next, job_list, + new_req->req.debug_str); + return -EINVAL; + } + + if (&new_req->list == job_list->prev || &new_req->list == job_list) { + dev_dbg(cam->dev, "%s job double add: req(%s)\n", + job_list_name, new_req->req.debug_str); + return -EINVAL; + } + + return 0; +} + +static void mtk_cam_req_p_data_init(struct mtk_cam_request *req, + u32 pipe_id, + u32 s_data_num) +{ + u32 i = 0; + + if (pipe_id >= MTKCAM_SUBDEV_MAX) + return; + + req->p_data[pipe_id].s_data_num = s_data_num; + for (i = 0; i < s_data_num; i++) + mtk_cam_req_s_data_init(req, pipe_id, i); +} + +static inline void mtk_cam_req_cnt_init(struct mtk_cam_request *req) +{ + atomic_set(&req->ref_cnt, 0); +} + +static unsigned int mtk_cam_req_get_pipe_used(struct media_request *req) +{ + /** + * V4L2 framework doesn't trigger q->ops->buf_queue(q, buf) when it is + * stream off. We have to check the used context through the request + * directly before streaming on. + */ + struct media_request_object *obj; + unsigned int pipe_used = 0; + struct mtk_cam_request *cam_req = to_mtk_cam_req(req); + unsigned int i; + struct mtk_cam_device *cam = + container_of(req->mdev, struct mtk_cam_device, media_dev); + + list_for_each_entry(obj, &req->objects, list) { + struct vb2_buffer *vb; + struct mtk_cam_video_device *node; + + if (!vb2_request_object_is_buffer(obj)) + continue; + vb = container_of(obj, struct vb2_buffer, req_obj); + node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + pipe_used |= 1 << node->uid.pipe_id; + } + + mtk_cam_req_cnt_init(cam_req); + + /* Initialize per pipe's stream data (without ctx)*/ + for (i = 0; i < cam->max_stream_num; i++) { + if (pipe_used & (1 << i)) { + mtk_cam_req_p_data_init(cam_req, i, 1); + mtk_cam_req_get(cam_req, i); /* pipe id */ + } + } + + return pipe_used; +} + +static void mtk_cam_req_queue(struct media_request *req) +{ + struct mtk_cam_request *cam_req = to_mtk_cam_req(req); + struct mtk_cam_device *cam = + container_of(req->mdev, struct mtk_cam_device, media_dev); + + /* reset done status */ + cam_req->done_status = 0; + cam_req->pipe_used = mtk_cam_req_get_pipe_used(req); + cam_req->ctx_used = 0; /* will update after stream on */ + mtk_cam_fs_reset(&cam_req->fs); + + /* update frame_params's dma_bufs in mtk_cam_vb2_buf_queue */ + vb2_request_queue(req); + + /* add to pending job list */ + spin_lock(&cam->pending_job_lock); + if (mtk_cam_req_chk_job_list(cam, cam_req, &cam->pending_job_list, + "pending_job_list")) { + spin_unlock(&cam->pending_job_lock); + return; + } + + /** + * Add req's ref cnt since it is used by pending_job_list and running + * pending_job_list. + */ + atomic_set(&cam_req->state, MTK_CAM_REQ_STATE_PENDING); + list_add_tail(&cam_req->list, &cam->pending_job_list); + spin_unlock(&cam->pending_job_lock); + mutex_lock(&cam->queue_lock); + mtk_cam_dev_req_try_queue(cam); + mutex_unlock(&cam->queue_lock); +} + +static int mtk_cam_link_notify(struct media_link *link, u32 flags, + unsigned int notification) +{ + struct media_entity *source = link->source->entity; + struct media_entity *sink = link->sink->entity; + struct v4l2_subdev *subdev; + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + + if (source->function != MEDIA_ENT_F_VID_IF_BRIDGE || + notification != MEDIA_DEV_NOTIFY_POST_LINK_CH) + return v4l2_pipeline_link_notify(link, flags, notification); + + subdev = media_entity_to_v4l2_subdev(sink); + if (!subdev) + return -EINVAL; + cam = container_of(subdev->v4l2_dev->mdev, struct mtk_cam_device, media_dev); + ctx = mtk_cam_find_ctx(cam, sink); + + if (!ctx || !ctx->streaming || !(flags & MEDIA_LNK_FL_ENABLED)) + return v4l2_pipeline_link_notify(link, flags, notification); + + dev_info(cam->dev, "stream_id(%d) is streaming, can't change link\n", + ctx->stream_id); + + return -EBUSY; +} + +static const struct media_device_ops mtk_cam_dev_ops = { + .link_notify = mtk_cam_link_notify, + .req_alloc = mtk_cam_req_alloc, + .req_free = mtk_cam_req_free, + .req_validate = vb2_request_validate, + .req_queue = mtk_cam_req_queue, +}; + +static int mtk_cam_of_rproc(struct mtk_cam_device *cam, + struct platform_device *pdev) +{ + struct device *dev = cam->dev; + + cam->scp = scp_get(pdev); + if (!cam->scp) { + dev_err(dev, "failed to get scp device\n"); + return -ENODEV; + } + + cam->rproc_handle = scp_get_rproc(cam->scp); + dev_dbg(dev, "camsys rproc_phandle: 0x%pK\n", cam->rproc_handle); + cam->smem_dev = scp_get_device(cam->scp); + + return 0; +} + +struct mtk_raw_device *get_main_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe) +{ + struct device *dev_main = NULL; + unsigned int i; + + for (i = 0; i < cam->num_raw_devices; i++) { + if (pipe->enabled_raw & (1 << i)) { + dev_main = cam->raw.devs[i]; + break; + } + } + + if (!dev_main) { + dev_err(cam->dev, "Not found main raw device\n"); + return NULL; + } + + return dev_get_drvdata(dev_main); +} + +struct mtk_raw_device *get_sub_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe) +{ + struct device *dev_sub = NULL; + unsigned int i; + + for (i = 0; i < cam->num_raw_devices - 1; i++) { + if (pipe->enabled_raw & (1 << i)) { + dev_sub = cam->raw.devs[i + 1]; + break; + } + } + + if (!dev_sub) { + dev_err(cam->dev, "Not found sub raw device\n"); + return NULL; + } + + return dev_get_drvdata(dev_sub); +} + +struct mtk_raw_device *get_sub2_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe) +{ + struct device *dev_sub = NULL; + unsigned int i; + + for (i = 0; i < cam->num_raw_devices; i++) { + if (pipe->enabled_raw & (1 << i)) { + dev_sub = cam->raw.devs[i + 2]; + break; + } + } + + if (!dev_sub) { + dev_err(cam->dev, "Not found second sub raw device\n"); + return NULL; + } + + return dev_get_drvdata(dev_sub); +} + +static int isp_composer_handle_ack(struct mtk_cam_device *cam, + struct mtkcam_ipi_event *ipi_msg) +{ + struct device *dev = cam->dev; + struct mtk_cam_ctx *ctx; + struct mtk_cam_working_buf_entry *buf_entry; + struct mtk_cam_request_stream_data *s_data; + struct mtk_raw_device *raw_dev; + bool is_m2m_apply_cq = false; + + ctx = &cam->ctxs[ipi_msg->cookie.session_id]; + + if (mtk_cam_is_m2m(ctx)) { + if (ipi_msg->cookie.frame_no > 1) { + dev_dbg(dev, "[M2M] wait_for_completion +\n"); + wait_for_completion(&ctx->m2m_complete); + dev_dbg(dev, "[M2M] wait_for_completion -\n"); + } + } + + spin_lock(&ctx->using_buffer_list.lock); + + ctx->composed_frame_seq_no = ipi_msg->cookie.frame_no; + dev_dbg(dev, "ctx:%d ack frame_num:%d\n", + ctx->stream_id, ctx->composed_frame_seq_no); + + /* get from using list */ + if (list_empty(&ctx->using_buffer_list.list)) { + spin_unlock(&ctx->using_buffer_list.lock); + return -EINVAL; + } + /* assign raw using buf */ + buf_entry = list_first_entry(&ctx->using_buffer_list.list, + struct mtk_cam_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + ctx->using_buffer_list.cnt--; + + spin_lock(&cam->dma_processing_lock); + if (!list_empty(&cam->dma_processing)) { + spin_unlock(&cam->dma_processing_lock); + buf_entry->cq_desc_offset = + ipi_msg->ack_data.frame_result.cq_desc_offset; + buf_entry->cq_desc_size = + ipi_msg->ack_data.frame_result.cq_desc_size; + buf_entry->sub_cq_desc_offset = + ipi_msg->ack_data.frame_result.sub_cq_desc_offset; + buf_entry->sub_cq_desc_size = + ipi_msg->ack_data.frame_result.sub_cq_desc_size; + + if (mtk_cam_is_m2m(ctx)) { + dev_info(dev, "Unsupport M2M with non-request buffer\n"); + spin_unlock(&ctx->using_buffer_list.lock); + return -EINVAL; + } + goto skip_req; + } + spin_unlock(&cam->dma_processing_lock); + + s_data = buf_entry->s_data; + if (!s_data) { + dev_dbg(dev, "ctx:%d no req for ack frame_num:%d\n", + ctx->stream_id, ctx->composed_frame_seq_no); + spin_unlock(&ctx->using_buffer_list.lock); + return -EINVAL; + } + + buf_entry->cq_desc_offset = + ipi_msg->ack_data.frame_result.cq_desc_offset; + buf_entry->cq_desc_size = + ipi_msg->ack_data.frame_result.cq_desc_size; + buf_entry->sub_cq_desc_offset = + ipi_msg->ack_data.frame_result.sub_cq_desc_offset; + buf_entry->sub_cq_desc_size = + ipi_msg->ack_data.frame_result.sub_cq_desc_size; + + /* Do nothing if the user doesn't enable force dump */ + mtk_cam_req_dump(s_data, MTK_CAM_REQ_DUMP_FORCE, + "Camsys Force Dump", false); + + if (ipi_msg->ack_data.ret) + mtk_cam_req_dump(s_data, MTK_CAM_REQ_DUMP_DEQUEUE_FAILED, + "Camsys compose error", false); + + if (mtk_cam_is_m2m(ctx)) { + spin_lock(&ctx->composed_buffer_list.lock); + dev_dbg(dev, "%s ctx->composed_buffer_list.cnt %d\n", + __func__, ctx->composed_buffer_list.cnt); + + if (ctx->composed_buffer_list.cnt == 0) + is_m2m_apply_cq = true; + + spin_unlock(&ctx->composed_buffer_list.lock); + + spin_lock(&ctx->processing_buffer_list.lock); + dev_dbg(dev, "%s ctx->processing_buffer_list.cnt %d\n", + __func__, ctx->processing_buffer_list.cnt); + spin_unlock(&ctx->processing_buffer_list.lock); + } + +skip_req: + if (ctx->composed_frame_seq_no == 1 || is_m2m_apply_cq) { + struct device *dev; + /* apply raw CQ */ + spin_lock(&ctx->processing_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, + &ctx->processing_buffer_list.list); + ctx->processing_buffer_list.cnt++; + spin_unlock(&ctx->processing_buffer_list.lock); + spin_unlock(&ctx->using_buffer_list.lock); + + dev = mtk_cam_find_raw_dev(cam, ctx->pipe->enabled_raw); + if (!dev) { + dev_dbg(dev, "frm#1 raw device not found\n"); + return -EINVAL; + } + + raw_dev = dev_get_drvdata(dev); + + if (mtk_cam_is_m2m(ctx)) { + dev_dbg(dev, + "%s M2M apply_cq, composed_buffer_list.cnt %d frame_seq_no %d\n", + __func__, ctx->composed_buffer_list.cnt, + s_data->frame_seq_no); + mtk_cam_m2m_enter_cq_state(&s_data->state); + } + + mtk_cam_raw_apply_cq(raw_dev, buf_entry->buffer.iova, + buf_entry->cq_desc_size, + buf_entry->cq_desc_offset, + buf_entry->sub_cq_desc_size, + buf_entry->sub_cq_desc_offset); + if (s_data) { + s_data->timestamp = ktime_get_boottime_ns(); + s_data->timestamp_mono = ktime_get_ns(); + } + + return 0; + } + + /* add composed_buffer_list */ + spin_lock(&ctx->composed_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, &ctx->composed_buffer_list.list); + ctx->composed_buffer_list.cnt++; + if (mtk_cam_is_m2m(ctx)) { + dev_dbg(dev, "%s M2M composed_buffer_list.cnt %d\n", + __func__, ctx->composed_buffer_list.cnt); + } + spin_unlock(&ctx->composed_buffer_list.lock); + + spin_unlock(&ctx->using_buffer_list.lock); + + return 0; +} + +static void isp_composer_handler(void *data, unsigned int len, void *priv) +{ + struct mtk_cam_device *cam = (struct mtk_cam_device *)priv; + struct device *dev = cam->dev; + struct mtkcam_ipi_event *ipi_msg; + struct mtk_cam_ctx *ctx; + + ipi_msg = (struct mtkcam_ipi_event *)data; + + if (len < offsetofend(struct mtkcam_ipi_event, ack_data)) { + dev_dbg(dev, "wrong IPI len:%d\n", len); + return; + } + + if (ipi_msg->cmd_id != CAM_CMD_ACK || + (ipi_msg->ack_data.ack_cmd_id != CAM_CMD_FRAME && + ipi_msg->ack_data.ack_cmd_id != CAM_CMD_DESTROY_SESSION)) + return; + + if (ipi_msg->ack_data.ack_cmd_id == CAM_CMD_FRAME) { + isp_composer_handle_ack(cam, ipi_msg); + return; + + } else if (ipi_msg->ack_data.ack_cmd_id == CAM_CMD_DESTROY_SESSION) { + ctx = &cam->ctxs[ipi_msg->cookie.session_id]; + complete(&ctx->session_complete); + dev_info(dev, "%s:ctx(%d): session destroyed", + __func__, ctx->stream_id); + } +} + +static int isp_composer_init(struct mtk_cam_device *cam) +{ + struct device *dev = cam->dev; + int ret; + + ret = rproc_boot(cam->rproc_handle); + if (ret) { + dev_err(dev, "failed to rproc_boot\n"); + return ret; + } + + ret = scp_ipi_register(cam->scp, SCP_IPI_ISP_CMD, + isp_composer_handler, cam); + if (ret) { + dev_err(dev, "failed to register IPI cmd\n"); + return ret; + } + + ret = scp_ipi_register(cam->scp, SCP_IPI_ISP_FRAME, + isp_composer_handler, cam); + if (ret) { + dev_err(dev, "failed to register IPI frame\n"); + goto unreg_ipi_cmd; + } + + return 0; + +unreg_ipi_cmd: + scp_ipi_unregister(cam->scp, SCP_IPI_ISP_CMD); + + return ret; +} + +static void isp_composer_uninit(struct mtk_cam_device *cam) +{ + scp_ipi_unregister(cam->scp, SCP_IPI_ISP_CMD); + scp_ipi_unregister(cam->scp, SCP_IPI_ISP_FRAME); +} + +int isp_composer_create_session(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtkcam_ipi_event event; + struct mtkcam_ipi_session_cookie *session = &event.cookie; + struct mtkcam_ipi_session_param *session_data = &event.session_data; + + memset(&event, 0, sizeof(event)); + event.cmd_id = CAM_CMD_CREATE_SESSION; + session->session_id = ctx->stream_id; + session_data->workbuf.iova = ctx->buf_pool.working_buf_iova; + session_data->workbuf.scp_addr = ctx->buf_pool.working_buf_scp_addr; + session_data->workbuf.size = ctx->buf_pool.working_buf_size; + session_data->msg_buf.scp_addr = ctx->buf_pool.msg_buf_scp_addr; + session_data->msg_buf.size = ctx->buf_pool.msg_buf_size; + session_data->raw_workbuf.scp_addr = ctx->buf_pool.raw_workbuf_scp_addr; + session_data->raw_workbuf.size = ctx->buf_pool.raw_workbuf_size; + session_data->priv_workbuf.scp_addr = ctx->buf_pool.priv_workbuf_scp_addr; + session_data->priv_workbuf.size = ctx->buf_pool.priv_workbuf_size; + session_data->session_buf.scp_addr = ctx->buf_pool.session_buf_scp_addr; + session_data->session_buf.size = ctx->buf_pool.session_buf_size; + + scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event, + sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT); + dev_dbg(cam->dev, + "%s: IPI send id: %d, cq_buf(scp addr:%x,sz:%d, msg_buf(scp addr:%x,sz%d)\n", + __func__, event.cmd_id, session_data->workbuf.scp_addr, + session_data->workbuf.size, session_data->msg_buf.scp_addr, + session_data->msg_buf.size); + return 0; +} + +void isp_composer_destroy_session(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtkcam_ipi_event event; + struct mtkcam_ipi_session_cookie *session = &event.cookie; + + memset(&event, 0, sizeof(event)); + event.cmd_id = CAM_CMD_DESTROY_SESSION; + session->session_id = ctx->stream_id; + scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event, + sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT); + dev_info(cam->dev, "IPI send id: %d\n", event.cmd_id); +} + +static void +isp_composer_hw_config(struct mtk_cam_device *cam, + struct mtk_cam_ctx *ctx, + struct mtkcam_ipi_config_param *config_param) +{ + struct mtkcam_ipi_event event; + struct mtkcam_ipi_session_cookie *session = &event.cookie; + struct mtkcam_ipi_config_param *config = &event.config_data; + + memset(&event, 0, sizeof(event)); + event.cmd_id = CAM_CMD_CONFIG; + session->session_id = ctx->stream_id; + memcpy(config, config_param, sizeof(*config_param)); + dev_dbg(cam->dev, "%s sw_feature:%d\n", __func__, config->sw_feature); + scp_ipi_send(cam->scp, SCP_IPI_ISP_CMD, &event, + sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT); + dev_dbg(cam->dev, "IPI send id: %d\n", event.cmd_id); + + /* For debug dump file */ + memcpy(&ctx->config_params, config_param, sizeof(*config_param)); + dev_dbg(cam->dev, "%s:ctx(%d): save config_param to ctx, sz:%zu\n", + __func__, ctx->stream_id, sizeof(*config_param)); +} + +static int mtk_cam_s_data_dev_config(struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data; + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct device *dev; + struct mtkcam_ipi_config_param config_param; + struct mtkcam_ipi_input_param *cfg_in_param; + struct mtk_raw_pipeline *pipe; + struct mtk_raw *raw; + struct v4l2_mbus_framefmt *mf; + struct device *dev_raw; + struct mtk_raw_device *raw_dev; + struct v4l2_format *img_fmt; + unsigned int i; + u32 mf_code; + + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + dev = cam->dev; + pipe = ctx->pipe; + raw = pipe->raw; + mf = &pipe->cfg[MTK_RAW_SINK].mbus_fmt; + s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data); + if (!s_raw_pipe_data) + return -EINVAL; + + memset(&config_param, 0, sizeof(config_param)); + + /* Update cfg_in_param */ + cfg_in_param = &config_param.input; + cfg_in_param->pixel_mode = ctx->pipe->res_config.tgo_pxl_mode; + + cfg_in_param->data_pattern = MTKCAM_IPI_SENSOR_PATTERN_NORMAL; + img_fmt = &pipe->vdev_nodes[MTK_RAW_SINK].pending_fmt; + cfg_in_param->in_crop.s.w = img_fmt->fmt.pix_mp.width; + cfg_in_param->in_crop.s.h = img_fmt->fmt.pix_mp.height; + dev_dbg(dev, "sink pad code:0x%x, tg size:%d %d\n", mf->code, + cfg_in_param->in_crop.s.w, cfg_in_param->in_crop.s.h); + + mf_code = mf->code & 0xffff; /* sensor mode */ + cfg_in_param->raw_pixel_id = mtk_cam_get_sensor_pixel_id(mf_code); + cfg_in_param->fmt = mtk_cam_get_sensor_fmt(mf_code); + if (cfg_in_param->fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN || + cfg_in_param->raw_pixel_id == MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN) { + dev_err(dev, "unknown sd code:%d\n", mf_code); + return -EINVAL; + } + + s_raw_pipe_data->enabled_raw = ctx->pipe->enabled_raw & + MTKCAM_SUBDEV_RAW_MASK; + config_param.flags = MTK_CAM_IPI_CONFIG_TYPE_INPUT_CHANGE; + + dev_dbg(dev, "%s: config_param flag:0x%x enabled_raw:0x%x\n", __func__, + config_param.flags, s_raw_pipe_data->enabled_raw); + + update_hw_mapping(ctx, &config_param); + + config_param.sw_feature = MTKCAM_IPI_SW_FEATURE_NORMAL; + + dev_raw = mtk_cam_find_raw_dev(cam, s_raw_pipe_data->enabled_raw); + if (!dev_raw) { + dev_err(dev, "config raw device not found\n"); + return -EINVAL; + } + + raw_dev = dev_get_drvdata(dev_raw); + for (i = 0; i < RAW_PIPELINE_NUM; i++) + if (raw->pipelines[i].enabled_raw & 1 << raw_dev->id) { + raw_dev->pipeline = &raw->pipelines[i]; + /* TWIN case */ + if (raw->pipelines[i].res_config.raw_num_used != 1) { + struct mtk_raw_device *raw_dev_sub = + get_sub_raw_dev(cam, ctx->pipe); + raw_dev_sub->pipeline = &raw->pipelines[i]; + dev_dbg(dev, "twin main/sub raw_id:%d/%d\n", + raw_dev->id, raw_dev_sub->id); + if (raw->pipelines[i].res_config.raw_num_used == 3) { + struct mtk_raw_device *raw_dev_sub2 = + get_sub2_raw_dev(cam, ctx->pipe); + raw_dev_sub2->pipeline = &raw->pipelines[i]; + dev_dbg(dev, + "triplet m/s/s2 raw_id:%d/%d/%d\n", + raw_dev->id, raw_dev_sub->id, + raw_dev_sub2->id); + } + } + break; + } + + isp_composer_hw_config(cam, ctx, &config_param); + dev_dbg(dev, "raw %d %s done\n", raw_dev->id, __func__); + + return 0; +} + +static void mtk_cam_res_init(struct mtk_cam_resource_config *res_cfg) +{ + res_cfg->raw_num_used = 1; + res_cfg->bin_enable = 0; + res_cfg->raw_path = 0; + res_cfg->hwn_limit_min = 1; + res_cfg->raw_feature = 0; +} + +static int mtk_cam_buf_config(struct mtk_cam_device *cam, + struct mtkcam_ipi_frame_param *frame_param, + struct mtk_cam_buffer *buf) +{ + struct vb2_buffer *vb; + struct mtk_cam_video_device *node; + int ret; + + vb = &buf->vbb.vb2_buf; + node = mtk_cam_vbq_to_vdev(vb->vb2_queue); + + /* update buffer format */ + switch (node->desc.dma_port) { + case MTKCAM_IPI_RAW_IMGO: + mtk_cam_config_raw_path(cam, frame_param, buf); + mtk_cam_config_raw_img_out_imgo(cam, frame_param, buf); + ret = mtk_cam_config_raw_img_fmt(cam, frame_param, buf); + if (ret) + return ret; + break; + case MTKCAM_IPI_RAW_YUVO_1: + case MTKCAM_IPI_RAW_YUVO_2: + case MTKCAM_IPI_RAW_YUVO_3: + case MTKCAM_IPI_RAW_YUVO_4: + case MTKCAM_IPI_RAW_YUVO_5: + case MTKCAM_IPI_RAW_RZH1N2TO_1: + case MTKCAM_IPI_RAW_RZH1N2TO_2: + case MTKCAM_IPI_RAW_RZH1N2TO_3: + case MTKCAM_IPI_RAW_DRZS4NO_1: + case MTKCAM_IPI_RAW_DRZS4NO_2: + case MTKCAM_IPI_RAW_DRZS4NO_3: + mtk_cam_config_raw_img_out(cam, frame_param, buf); + break; + default: + /* Do nothing for the ports not related to crop settings */ + break; + } + + return 0; +} + +void mtk_cam_buf_try_queue(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_device *cam; + struct mtk_cam_buffer *buf, *buf_prev; + struct mtkcam_ipi_event event; + struct mtkcam_ipi_session_cookie *session = &event.cookie; + struct mtkcam_ipi_frame_info *frame_info = &event.frame_data; + struct mtkcam_ipi_frame_param *frame_param; + struct mtkcam_ipi_frame_param *frame_data; + struct mtk_cam_working_buf_entry *buf_entry; + struct list_head equeue_list; + unsigned int processing_cnt, enque_cnt; + + cam = ctx->cam; + if (!cam->streaming_ctx) { + dev_info(cam->dev, "streams are off\n"); + return; + } + + INIT_LIST_HEAD(&equeue_list); + + spin_lock(&cam->dma_processing_lock); + processing_cnt = cam->dma_processing_count; + spin_unlock(&cam->dma_processing_lock); + + enque_cnt = 0; + spin_lock(&cam->dma_pending_lock); + list_for_each_entry_safe(buf, buf_prev, &cam->dma_pending, list) { + if (processing_cnt + enque_cnt >= MTK_CAM_MAX_PROCESSING_BUFS) { + dev_dbg(cam->dev, + "processing bufs are full, buf cnt(%d)\n", + processing_cnt); + break; + } + dev_dbg(cam->dev, "%s buf cnt(%d)\n", + __func__, processing_cnt + enque_cnt); + + enque_cnt++; + list_del(&buf->list); + list_add_tail(&buf->list, &equeue_list); + } + spin_unlock(&cam->dma_pending_lock); + + if (!enque_cnt) + return; + + frame_param = kzalloc(sizeof(*frame_param), GFP_KERNEL); + if (!frame_param) + return; + + list_for_each_entry_safe(buf, buf_prev, &equeue_list, list) { + if (buf->state.estate == E_BUF_STATE_COMPOSED) + continue; + + memset(&event, 0, sizeof(event)); + event.cmd_id = CAM_CMD_FRAME; + session->session_id = ctx->stream_id; + /* prepare working buffer */ + buf_entry = mtk_cam_working_buf_get(ctx); + if (!buf_entry) { + dev_info(cam->dev, + "%s: No CQ buf availablle: enqueued_frame_seq_no:%d\n", + __func__, atomic_read(&ctx->enqueued_frame_seq_no)); + WARN_ON(1); + goto EXIT; + } + + spin_lock(&ctx->using_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, &ctx->using_buffer_list.list); + ctx->using_buffer_list.cnt++; + spin_unlock(&ctx->using_buffer_list.lock); + + spin_lock(&cam->dma_processing_lock); + list_del(&buf->list); + list_add_tail(&buf->list, &cam->dma_processing); + cam->dma_processing_count++; + spin_unlock(&cam->dma_processing_lock); + + /* Prepare rp message */ + frame_info->cur_msgbuf_offset = + buf_entry->msg_buffer.va - + cam->ctxs[session->session_id].buf_pool.msg_buf_va; + frame_info->cur_msgbuf_size = buf_entry->msg_buffer.size; + frame_data = (struct mtkcam_ipi_frame_param *)buf_entry->msg_buffer.va; + session->frame_no = atomic_inc_return(&ctx->enqueued_frame_seq_no); + + if (mtk_cam_buf_config(cam, frame_param, buf)) { + dev_err(cam->dev, "%s: Buffer config failed\n", __func__); + continue; + } + memcpy(frame_data, frame_param, sizeof(*frame_param)); + frame_data->cur_workbuf_offset = + buf_entry->buffer.iova - + cam->ctxs[session->session_id].buf_pool.working_buf_iova; + frame_data->cur_workbuf_size = buf_entry->buffer.size; + + if (ctx->pipe->res_config.bin_limit == BIN_AUTO) + frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_enable; + else + frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_limit; + + scp_ipi_send(cam->scp, SCP_IPI_ISP_FRAME, &event, + sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT); + buf->state.estate = E_BUF_STATE_COMPOSED; + } +EXIT: + kfree(frame_param); +} + +static void isp_tx_frame_worker(struct work_struct *work) +{ + struct mtk_cam_req_work *req_work = (struct mtk_cam_req_work *)work; + struct mtkcam_ipi_event event; + struct mtkcam_ipi_session_cookie *session = &event.cookie; + struct mtkcam_ipi_frame_info *frame_info = &event.frame_data; + struct mtkcam_ipi_frame_param *frame_data; + struct mtk_cam_request *req; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_ctx *ctx; + struct mtk_cam_device *cam; + struct mtk_cam_working_buf_entry *buf_entry; + struct mtk_cam_resource *res_user; + struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data; + + req_stream_data = mtk_cam_req_work_get_s_data(req_work); + if (!req_stream_data) { + pr_info("%s mtk_cam_req_work(%p), req_stream_data(%p), dropped\n", + __func__, req_work, req_stream_data); + return; + } + req = mtk_cam_s_data_get_req(req_stream_data); + if (!req) { + pr_info("%s req_stream_data(%p), req(%p), dropped\n", + __func__, req_stream_data, req); + return; + } + ctx = mtk_cam_s_data_get_ctx(req_stream_data); + if (!ctx) { + pr_info("%s req_stream_data(%p), ctx(%p), dropped\n", + __func__, req_stream_data, ctx); + return; + } + + cam = ctx->cam; + if (ctx->used_raw_num == 0) { + dev_dbg(cam->dev, "raw is un-used, skip frame work"); + return; + } + /* check if the ctx is streaming */ + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + dev_info(cam->dev, + "%s: skip frame work, for stream off ctx:%d, req:%d\n", + __func__, ctx->stream_id, req_stream_data->frame_seq_no); + spin_unlock(&ctx->streaming_lock); + return; + } + spin_unlock(&ctx->streaming_lock); + + s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(req_stream_data); + + /* Send CAM_CMD_CONFIG if the sink pad fmt is changed */ + if (req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE) + mtk_cam_s_data_dev_config(req_stream_data); + + if (!s_raw_pipe_data) { + dev_info(cam->dev, "error: %s: s_raw_pipe_data = NULL\n", __func__); + return; + } + + memset(&event, 0, sizeof(event)); + event.cmd_id = CAM_CMD_FRAME; + session->session_id = ctx->stream_id; + /* prepare working buffer */ + buf_entry = mtk_cam_working_buf_get(ctx); + if (!buf_entry) { + dev_info(cam->dev, "%s: No CQ buf availablle: req:%d(%s)\n", + __func__, req_stream_data->frame_seq_no, + req->req.debug_str); + WARN_ON(1); + return; + } + mtk_cam_s_data_set_wbuf(req_stream_data, buf_entry); + /* put to using list */ + spin_lock(&ctx->using_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, &ctx->using_buffer_list.list); + ctx->using_buffer_list.cnt++; + spin_unlock(&ctx->using_buffer_list.lock); + + /* Prepare rp message */ + frame_info->cur_msgbuf_offset = + buf_entry->msg_buffer.va - + cam->ctxs[session->session_id].buf_pool.msg_buf_va; + frame_info->cur_msgbuf_size = buf_entry->msg_buffer.size; + frame_data = (struct mtkcam_ipi_frame_param *)buf_entry->msg_buffer.va; + session->frame_no = req_stream_data->frame_seq_no; + + memcpy(frame_data, &req_stream_data->frame_params, + sizeof(req_stream_data->frame_params)); + frame_data->cur_workbuf_offset = + buf_entry->buffer.iova - + cam->ctxs[session->session_id].buf_pool.working_buf_iova; + frame_data->cur_workbuf_size = buf_entry->buffer.size; + + res_user = mtk_cam_s_data_get_res(req_stream_data); + if (res_user && res_user->raw_res.bin) { + frame_data->raw_param.bin_flag = res_user->raw_res.bin; + } else { + if (ctx->pipe->res_config.bin_limit == BIN_AUTO) + frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_enable; + else + frame_data->raw_param.bin_flag = ctx->pipe->res_config.bin_limit; + } + + scp_ipi_send(cam->scp, SCP_IPI_ISP_FRAME, &event, + sizeof(event), MTK_CAM_IPI_SEND_TIMEOUT); + dev_dbg(cam->dev, + "%s: IPI send id: %d, ctx:%d, seq:%d, bin:(0x%x)\n", + req->req.debug_str, event.cmd_id, session->session_id, + req_stream_data->frame_seq_no, + frame_data->raw_param.bin_flag); +} + +static void mtk_cam_dev_summit_sensor_work(struct mtk_cam_ctx *ctx, + struct mtk_camsys_sensor_ctrl *sensor_ctrl) +{ + unsigned int drained_seq_no = 0; + + if (ctx->pipe->feature_active == 0 && ctx->dequeued_frame_seq_no > 3) { + drained_seq_no = atomic_read(&sensor_ctrl->last_drained_seq_no); + if (atomic_read(&sensor_ctrl->sensor_enq_seq_no) == drained_seq_no) + mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq, + sensor_ctrl); + } +} + +void mtk_cam_dev_req_enqueue(struct mtk_cam_device *cam, + struct mtk_cam_request *req) +{ + unsigned int i, j; + + for (i = 0; i < cam->max_stream_num; i++) { + if (req->pipe_used & (1 << i)) { + unsigned int stream_id = i; + struct mtk_cam_req_work *frame_work, *done_work; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_request_stream_data *pipe_stream_data; + struct mtk_cam_ctx *ctx = &cam->ctxs[stream_id]; + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + unsigned int initial_frame = 0; + + if (!ctx->streaming) + continue; + + atomic_set(&ctx->sensor_ctrl.sensor_enq_seq_no, + atomic_read(&ctx->enqueued_frame_seq_no)); + /* sensor setting after request drained check */ + if (ctx->used_raw_num) + mtk_cam_dev_summit_sensor_work(ctx, sensor_ctrl); + req_stream_data = mtk_cam_req_get_s_data(req, stream_id, 0); + + if (req_stream_data->frame_seq_no == 1) + initial_frame = 1; + frame_work = &req_stream_data->frame_work; + mtk_cam_req_work_init(frame_work, req_stream_data); + + for (j = 0 ; j < MTKCAM_SUBDEV_MAX ; j++) { + if ((1 << j & ctx->streaming_pipe) && + (1 << j & req->pipe_used)) { + pipe_stream_data = mtk_cam_req_get_s_data(req, j, 0); + done_work = &pipe_stream_data->frame_done_work; + INIT_WORK(&done_work->work, mtk_cam_frame_done_work); + + done_work = &pipe_stream_data->meta1_done_work; + atomic_set(&done_work->is_queued, 0); + INIT_WORK(&done_work->work, mtk_cam_meta1_done_work); + } + } + + if (ctx->sensor && (initial_frame || mtk_cam_is_m2m(ctx))) + mtk_cam_initial_sensor_setup(req, ctx); + + if (ctx->used_raw_num != 0) { + if (ctx->sensor && + ctx->pipe->feature_active == 0 && + req_stream_data->frame_seq_no == 2) + mtk_cam_initial_sensor_setup(req, ctx); + } else { + if (ctx->sensor && + req_stream_data->frame_seq_no == 2) + mtk_cam_initial_sensor_setup(req, ctx); + } + + /* Prepare CQ compose work */ + mtk_cam_req_dump_work_init(req_stream_data); + INIT_WORK(&frame_work->work, isp_tx_frame_worker); + queue_work(ctx->composer_wq, &frame_work->work); + + dev_dbg(cam->dev, + "%s:ctx:%d:req:%d(%s) enqueue ctx_used:0x%x,streaming_ctx:0x%x,job cnt:%d, running(%d)\n", + __func__, stream_id, req_stream_data->frame_seq_no, + req->req.debug_str, req->ctx_used, + cam->streaming_ctx, cam->running_job_count, + atomic_read(&ctx->running_s_data_cnt)); + } + } +} + +struct mtk_raw_pipeline * +mtk_cam_dev_get_raw_pipeline(struct mtk_cam_device *cam, unsigned int pipe_id) +{ + if (pipe_id < MTKCAM_SUBDEV_RAW_START || + pipe_id >= MTKCAM_SUBDEV_RAW_START + cam->num_raw_devices) + return NULL; + else + return &cam->raw.pipelines[pipe_id - MTKCAM_SUBDEV_RAW_0]; +} + +static int +mtk_cam_raw_pipeline_config(struct mtk_cam_ctx *ctx, + struct mtkcam_ipi_input_param *cfg_in_param) +{ + struct mtk_raw_pipeline *pipe = ctx->pipe; + struct mtk_raw *raw = pipe->raw; + int ret, i; + + /* reset pm_runtime during streaming dynamic change */ + if (ctx->streaming) { + for (i = 0; i < ARRAY_SIZE(raw->devs); i++) { + if (pipe->enabled_raw & 1 << i) { + dev_info(raw->cam_dev, + "%s: power off raw (%d) for reset\n", + __func__, i); + pm_runtime_put_sync(raw->devs[i]); + } + } + } + + ret = mtk_cam_raw_select(ctx, cfg_in_param); + if (ret) { + dev_info(raw->cam_dev, "failed select raw: %d\n", + ctx->stream_id); + return ret; + } + + for (i = 0; i < ARRAY_SIZE(raw->devs); i++) { + if (pipe->enabled_raw & 1 << i) { + dev_info(raw->cam_dev, "%s: power on raw (%d)\n", + __func__, i); + ret = pm_runtime_get_sync(raw->devs[i]); + + if (ret < 0) { + dev_info(raw->cam_dev, + "failed at pm_runtime_get_sync: %s\n", + dev_driver_string(raw->devs[i])); + + /* put devices already get */ + for (; i >= 0; i--) { + pm_runtime_put_sync(raw->devs[i]); + dev_info(raw->cam_dev, + "%s: power off raw (%d)\n", + __func__, i); + } + + return ret; + } + } + } + + ctx->used_raw_dev = pipe->enabled_raw; + dev_info(raw->cam_dev, "ctx_id %d used_raw_dev 0x%x pipe_id %d\n", + ctx->stream_id, ctx->used_raw_dev, pipe->id); + return 0; +} + +void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_req_raw_pipe_data *s_raw_pipe_data; + struct mtk_cam_ctx *ctx; + char *debug_str = mtk_cam_s_data_get_dbg_str(s_data); + + s_raw_pipe_data = mtk_cam_s_data_get_raw_pipe_data(s_data); + if (!s_raw_pipe_data) + return; + + ctx = mtk_cam_s_data_get_ctx(s_data); + if (!ctx) + return; + ctx->pipe->feature_active = ctx->pipe->user_res.raw_res.feature; + ctx->pipe->enabled_raw = s_raw_pipe_data->enabled_raw; + ctx->used_raw_dev = s_raw_pipe_data->enabled_raw; + + dev_info(ctx->cam->dev, + "%s:%s:pipe(%d):seq(%d):feature_active(0x%llx), ctx->pipe->user_res.raw_res.feature(%lld), enabled_raw(0x%x)\n", + __func__, debug_str, ctx->stream_id, s_data->frame_seq_no, + ctx->pipe->feature_active, + ctx->pipe->user_res.raw_res.feature, + ctx->pipe->enabled_raw); +} + +static int mtk_cam_dev_config(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_device *cam = ctx->cam; + struct device *dev = cam->dev; + struct mtkcam_ipi_config_param config_param; + struct mtkcam_ipi_input_param *cfg_in_param; + struct mtk_raw_pipeline *pipe = ctx->pipe; + struct mtk_raw *raw = pipe->raw; + struct v4l2_mbus_framefmt *mf = &pipe->cfg[MTK_RAW_SINK].mbus_fmt; + struct device *dev_raw; + struct mtk_raw_device *raw_dev; + unsigned int i; + int ret; + u32 mf_code; + + /** + * If don't want to get the first req's raw_feature (not the max exp. num), + * you can use read ctx->pipe->feature_pending here. + */ + + memset(&config_param, 0, sizeof(config_param)); + + /* Update cfg_in_param */ + cfg_in_param = &config_param.input; + cfg_in_param->pixel_mode = ctx->pipe->res_config.tgo_pxl_mode; + + cfg_in_param->data_pattern = MTKCAM_IPI_SENSOR_PATTERN_NORMAL; + cfg_in_param->in_crop.s.w = mf->width; + cfg_in_param->in_crop.s.h = mf->height; + + if (mtk_cam_is_pure_m2m(ctx)) { + mf = &pipe->cfg[MTK_RAW_RAWI_2_IN].mbus_fmt; + dev_dbg(dev, "[pure m2m] rawi2 pad code:0x%x, sink tg size:%d %d\n", + mf->code, cfg_in_param->in_crop.s.w, cfg_in_param->in_crop.s.h); + } else { + dev_dbg(dev, "sink pad code:0x%x, tg size:%d %d\n", mf->code, + cfg_in_param->in_crop.s.w, cfg_in_param->in_crop.s.h); + } + + mf_code = mf->code & 0xffff; /* sensor mode */ + cfg_in_param->raw_pixel_id = mtk_cam_get_sensor_pixel_id(mf_code); + cfg_in_param->fmt = mtk_cam_get_sensor_fmt(mf_code); + if (cfg_in_param->fmt == MTKCAM_IPI_IMG_FMT_UNKNOWN || + cfg_in_param->raw_pixel_id == MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN) { + dev_err(dev, "unknown sd code:%d\n", mf_code); + return -EINVAL; + } + + config_param.flags = MTK_CAM_IPI_CONFIG_TYPE_INIT; + ret = mtk_cam_raw_pipeline_config(ctx, cfg_in_param); + if (ret) + return ret; + + dev_dbg(dev, "%s: config_param flag:0x%x enabled_raw:0x%x\n", + __func__, config_param.flags, ctx->pipe->enabled_raw); + + update_hw_mapping(ctx, &config_param); + config_param.sw_feature = MTKCAM_IPI_SW_FEATURE_NORMAL; + + dev_raw = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev); + if (!dev_raw) { + dev_err(dev, "config raw device not found\n"); + return -EINVAL; + } + raw_dev = dev_get_drvdata(dev_raw); + for (i = 0; i < RAW_PIPELINE_NUM; i++) + if (raw->pipelines[i].enabled_raw & 1 << raw_dev->id) { + raw_dev->pipeline = &raw->pipelines[i]; + if (raw->pipelines[i].res_config.raw_num_used == 0) + mtk_cam_res_init(&raw->pipelines[i].res_config); + break; + } + + mtk_cam_raw_reset(raw_dev); + isp_composer_hw_config(cam, ctx, &config_param); + dev_dbg(dev, "raw %d %s done\n", raw_dev->id, __func__); + + return 0; +} + +static int __maybe_unused mtk_cam_runtime_suspend(struct device *dev) +{ + dev_dbg(dev, "- %s\n", __func__); + return 0; +} + +static int __maybe_unused mtk_cam_runtime_resume(struct device *dev) +{ + dev_dbg(dev, "- %s\n", __func__); + return 0; +} + +static void mtk_cam_ctx_watchdog_worker(struct work_struct *work) +{ + struct mtk_cam_ctx *ctx; + struct mtk_raw_device *raw; + struct v4l2_subdev *seninf; + static u64 last_vsync_count; + + ctx = container_of(work, struct mtk_cam_ctx, watchdog_work); + + /* dump cam-raw */ + raw = get_main_raw_dev(ctx->cam, ctx->pipe); + if (!raw) + goto EXIT; + dev_info(ctx->cam->dev, + "%s:ctx(%d):[timeout] VF(%d) vsync count(%lld) sof count(%lld) timeout_tg(%d)(>%dms)\n", + __func__, ctx->stream_id, atomic_read(&raw->vf_en), + raw->vsync_count, raw->sof_count, ctx->watchdog_timeout_tg, + ctx->watchdog_timeout_tg * MTK_CAM_CTX_WATCHDOG_INTERVAL); + + if (last_vsync_count == raw->vsync_count) + dev_err(ctx->cam->dev, "%s:cam-raw abnormal vsync\n", __func__); + last_vsync_count = raw->vsync_count; + + /* dump seninf */ + seninf = ctx->seninf; + if (seninf) + mtk_cam_seninf_dump(seninf); + +EXIT: + atomic_inc(&ctx->watchdog_dump); +} + +#define WDT_DUMP_CNT 4 + +static void mtk_ctx_watchdog_callback(struct timer_list *t) +{ + struct mtk_cam_ctx *ctx = from_timer(ctx, t, watchdog_timer); + + /* disable if not streaming */ + if (!ctx->streaming) + return; + + if (atomic_read(&ctx->watchdog_dump) < WDT_DUMP_CNT) + schedule_work(&ctx->watchdog_work); + + dev_info_ratelimited(ctx->cam->dev, + "%s:ctx(%d):[TIMEOUT] no_sync_tg:%d(>%dms)\n", + __func__, ctx->stream_id, ctx->watchdog_timeout_tg, + jiffies_to_msecs(jiffies - + atomic_long_read(&ctx->watchdog_prev))); + + /* update timer */ + mod_timer(&ctx->watchdog_timer, + jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL)); +} + +void mtk_ctx_watchdog_kick(struct mtk_cam_ctx *ctx) +{ + dev_dbg(ctx->cam->dev, "%s:ctx(%d)\n", __func__, ctx->stream_id); + atomic_set(&ctx->watchdog_dump, 0); + + /* delay timer */ + mod_timer(&ctx->watchdog_timer, + jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL * + ctx->watchdog_timeout_tg)); + atomic_long_set(&ctx->watchdog_prev, jiffies); +} + +static void mtk_ctx_watchdog_init(struct mtk_cam_ctx *ctx) +{ + INIT_WORK(&ctx->watchdog_work, mtk_cam_ctx_watchdog_worker); + timer_setup(&ctx->watchdog_timer, mtk_ctx_watchdog_callback, 0); +} + +static void mtk_ctx_watchdog_start(struct mtk_cam_ctx *ctx, int timeout_tg) +{ + dev_info(ctx->cam->dev, + "%s:ctx(%d):start the watchdog, timeout setting(%dms)\n", + __func__, ctx->stream_id, + MTK_CAM_CTX_WATCHDOG_INTERVAL * timeout_tg); + + ctx->watchdog_timeout_tg = timeout_tg; + atomic_set(&ctx->watchdog_dump, 0); + + mod_timer(&ctx->watchdog_timer, + jiffies + msecs_to_jiffies(MTK_CAM_CTX_WATCHDOG_INTERVAL * + ctx->watchdog_timeout_tg)); + atomic_long_set(&ctx->watchdog_prev, jiffies); +} + +static void mtk_ctx_watchdog_stop(struct mtk_cam_ctx *ctx) +{ + dev_info(ctx->cam->dev, "%s:ctx(%d):stop the watchdog\n", + __func__, ctx->stream_id); + del_timer_sync(&ctx->watchdog_timer); +} + +struct mtk_cam_ctx *mtk_cam_find_ctx(struct mtk_cam_device *cam, + struct media_entity *entity) +{ + unsigned int i; + + for (i = 0; i < cam->max_stream_num; i++) { + if (media_entity_pipeline(entity) == &cam->ctxs[i].pipeline) + return &cam->ctxs[i]; + } + + return NULL; +} + +struct mtk_cam_ctx *mtk_cam_start_ctx(struct mtk_cam_device *cam, + struct mtk_cam_video_device *node) +{ + struct mtk_cam_ctx *ctx = node->ctx; + struct device *dev; + struct v4l2_subdev **target_sd; + int ret, i, is_first_ctx; + struct media_entity *entity = &node->vdev.entity; + struct media_graph graph; + + dev_info(cam->dev, "%s:ctx(%d): triggered by %s\n", + __func__, ctx->stream_id, entity->name); + + atomic_set(&ctx->enqueued_frame_seq_no, 0); + ctx->composed_frame_seq_no = 0; + ctx->dequeued_frame_seq_no = 0; + atomic_set(&ctx->running_s_data_cnt, 0); + init_completion(&ctx->session_complete); + init_completion(&ctx->m2m_complete); + + is_first_ctx = !cam->composer_cnt; + if (is_first_ctx) { + spin_lock(&cam->dma_processing_lock); + cam->dma_processing_count = 0; + spin_unlock(&cam->dma_processing_lock); + + spin_lock(&cam->running_job_lock); + cam->running_job_count = 0; + spin_unlock(&cam->running_job_lock); + + dev_info(cam->dev, "%s: power on camsys\n", __func__); + ret = pm_runtime_resume_and_get(cam->dev); + if (ret < 0) { + dev_info(cam->dev, "%s: power on camsys failed\n", + __func__); + return NULL; + } + + ret = isp_composer_init(cam); + if (ret) + goto fail_shutdown; + + /* To catch camsys exception and trigger dump */ + if (cam->debug_fs) + cam->debug_fs->ops->exp_reinit(cam->debug_fs); + } + cam->composer_cnt++; + if (is_yuv_node(node->desc.id)) + dev = cam->raw.yuvs[0]; + else + dev = cam->raw.devs[0]; + + ret = mtk_cam_working_buf_pool_init(ctx, dev); + if (ret) { + dev_info(cam->dev, "failed to reserve DMA memory:%d\n", ret); + goto fail_uninit_composer; + } + + kthread_init_worker(&ctx->sensor_worker); + ctx->sensor_worker_task = kthread_run(kthread_worker_fn, + &ctx->sensor_worker, + "sensor_worker-%d", + ctx->stream_id); + if (IS_ERR(ctx->sensor_worker_task)) { + dev_info(cam->dev, + "%s:ctx(%d): could not create sensor_worker_task\n", + __func__, ctx->stream_id); + goto fail_release_buffer_pool; + } + + sched_set_fifo(ctx->sensor_worker_task); + + ctx->composer_wq = alloc_ordered_workqueue(dev_name(cam->dev), + WQ_HIGHPRI | WQ_FREEZABLE); + if (!ctx->composer_wq) { + dev_info(cam->dev, "failed to alloc composer workqueue\n"); + goto fail_uninit_sensor_worker_task; + } + + ctx->frame_done_wq = alloc_ordered_workqueue(dev_name(cam->dev), + WQ_HIGHPRI | WQ_FREEZABLE); + if (!ctx->frame_done_wq) { + dev_info(cam->dev, "failed to alloc frame_done workqueue\n"); + goto fail_uninit_composer_wq; + } + + ret = media_pipeline_start(&entity->pads[0], &ctx->pipeline); + if (ret) { + dev_warn(cam->dev, + "%s:pipe(%d):failed in media_pipeline_start:%d\n", + __func__, node->uid.pipe_id, ret); + goto fail_uninit_frame_done_wq; + } + + /* traverse to update used subdevs & number of nodes */ + i = 0; + ret = media_graph_walk_init(&graph, entity->graph_obj.mdev); + if (ret) + goto fail_stop_pipeline; + + media_graph_walk_start(&graph, entity); + while ((entity = media_graph_walk_next(&graph))) { + dev_dbg(cam->dev, "linked entity %s\n", entity->name); + + target_sd = NULL; + + switch (entity->function) { + case MEDIA_ENT_F_IO_V4L: + ctx->enabled_node_cnt++; + break; + case MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER: /* pipeline */ + if (i >= MAX_PIPES_PER_STREAM) + goto fail_stop_pipeline; + target_sd = ctx->pipe_subdevs + i; + i++; + break; + case MEDIA_ENT_F_VID_IF_BRIDGE: /* seninf */ + target_sd = &ctx->seninf; + break; + case MEDIA_ENT_F_CAM_SENSOR: + target_sd = &ctx->sensor; + break; + default: + break; + } + + if (!target_sd) + continue; + + if (*target_sd) { + dev_info(cam->dev, "duplicated subdevs!!!\n"); + goto fail_traverse_subdev; + } + + if (is_media_entity_v4l2_subdev(entity)) + *target_sd = media_entity_to_v4l2_subdev(entity); + } + media_graph_walk_cleanup(&graph); + + return ctx; + +fail_traverse_subdev: + media_graph_walk_cleanup(&graph); +fail_stop_pipeline: + media_pipeline_stop(&entity->pads[0]); +fail_uninit_frame_done_wq: + destroy_workqueue(ctx->frame_done_wq); +fail_uninit_composer_wq: + destroy_workqueue(ctx->composer_wq); +fail_uninit_sensor_worker_task: + kthread_stop(ctx->sensor_worker_task); + ctx->sensor_worker_task = NULL; +fail_release_buffer_pool: + mtk_cam_working_buf_pool_release(ctx, dev); +fail_uninit_composer: + isp_composer_uninit(cam); + cam->composer_cnt--; +fail_shutdown: + if (is_first_ctx) + rproc_shutdown(cam->rproc_handle); + + return NULL; +} + +void mtk_cam_stop_ctx(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node) +{ + struct mtk_cam_device *cam = ctx->cam; + struct media_entity *entity = &node->vdev.entity; + struct device *dev; + unsigned int i; + + if (is_yuv_node(node->desc.id)) + dev = cam->raw.yuvs[0]; + else + dev = cam->raw.devs[0]; + + dev_info(cam->dev, "%s:ctx(%d): triggered by %s\n", + __func__, ctx->stream_id, entity->name); + + media_pipeline_stop(&entity->pads[0]); + + if (ctx->session_created) { + dev_dbg(cam->dev, + "%s:ctx(%d): session_created, wait for composer session destroy\n", + __func__, ctx->stream_id); + if (wait_for_completion_timeout(&ctx->session_complete, + msecs_to_jiffies(300)) == 0) + dev_info(cam->dev, "%s:ctx(%d): complete timeout\n", + __func__, ctx->stream_id); + } + + /* For M2M feature, signal all waiters */ + if (mtk_cam_is_m2m(ctx)) + complete_all(&ctx->m2m_complete); + + if (!cam->streaming_ctx) { + struct v4l2_subdev *sd; + + v4l2_device_for_each_subdev(sd, &cam->v4l2_dev) { + if (sd->entity.function == MEDIA_ENT_F_VID_IF_BRIDGE) { + int ret; + + ret = v4l2_subdev_call(sd, video, s_stream, 0); + if (ret) + dev_err(cam->dev, + "failed to streamoff %s:%d\n", + sd->name, ret); + } + } + } + + drain_workqueue(ctx->composer_wq); + destroy_workqueue(ctx->composer_wq); + ctx->composer_wq = NULL; + drain_workqueue(ctx->frame_done_wq); + destroy_workqueue(ctx->frame_done_wq); + ctx->frame_done_wq = NULL; + kthread_flush_worker(&ctx->sensor_worker); + kthread_stop(ctx->sensor_worker_task); + ctx->sensor_worker_task = NULL; + ctx->session_created = 0; + ctx->enabled_node_cnt = 0; + ctx->streaming_node_cnt = 0; + ctx->streaming_pipe = 0; + ctx->sensor = NULL; + ctx->seninf = NULL; + atomic_set(&ctx->enqueued_frame_seq_no, 0); + ctx->composed_frame_seq_no = 0; + ctx->is_first_cq_done = 0; + ctx->cq_done_status = 0; + ctx->used_raw_num = 0; + + INIT_LIST_HEAD(&ctx->using_buffer_list.list); + INIT_LIST_HEAD(&ctx->composed_buffer_list.list); + INIT_LIST_HEAD(&ctx->processing_buffer_list.list); + + INIT_LIST_HEAD(&ctx->processing_img_buffer_list.list); + for (i = 0; i < MAX_PIPES_PER_STREAM; i++) + ctx->pipe_subdevs[i] = NULL; + + isp_composer_uninit(cam); + cam->composer_cnt--; + + dev_info(cam->dev, "%s: ctx-%d: composer_cnt:%d\n", + __func__, ctx->stream_id, cam->composer_cnt); + + mtk_cam_working_buf_pool_release(ctx, dev); + + if (ctx->cam->rproc_handle && !ctx->cam->composer_cnt) { + dev_info(cam->dev, "%s power off camsys\n", __func__); + pm_runtime_put_sync(cam->dev); + rproc_shutdown(cam->rproc_handle); + } +} + +static int pipeid_to_tgidx(int pipe_id) +{ + switch (pipe_id) { + case MTKCAM_SUBDEV_RAW_0: + return 0; + case MTKCAM_SUBDEV_RAW_1: + return 1; + case MTKCAM_SUBDEV_RAW_2: + return 2; + default: + break; + } + return -1; +} + +int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx, + struct v4l2_subdev *sd, + int pad_id, int pixel_mode) +{ + int ret; + + ret = mtk_cam_seninf_set_pixelmode(sd, pad_id, pixel_mode); + dev_dbg(ctx->cam->dev, + "%s:ctx(%d): seninf(%s): pad(%d), pixel_mode(%d)\n, ret(%d)", + __func__, ctx->stream_id, sd->name, pad_id, pixel_mode, + ret); + + return ret; +} + +int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node) +{ + struct mtk_cam_device *cam = ctx->cam; + struct device *dev; + struct mtk_raw_device *raw_dev; + int i, ret; + int tgo_pxl_mode; + bool need_dump_mem = false; + unsigned int streaming_ctx_latch; + + dev_dbg(cam->dev, "ctx %d stream on, streaming_pipe:0x%x\n", + ctx->stream_id, ctx->streaming_pipe); + + if (ctx->streaming) { + dev_dbg(cam->dev, "ctx-%d is already streaming on\n", ctx->stream_id); + return 0; + } + + for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) { + ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, + s_stream, 1); + if (ret) { + dev_info(cam->dev, "failed to stream on %s: %d\n", + ctx->pipe_subdevs[i]->name, ret); + goto fail_pipe_off; + } + } + + if (ctx->used_raw_num) { + tgo_pxl_mode = ctx->pipe->res_config.tgo_pxl_mode; + + ret = mtk_cam_dev_config(ctx); + if (ret) + goto fail_pipe_off; + dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev); + if (!dev) { + dev_info(cam->dev, "streamon raw device not found\n"); + goto fail_pipe_off; + } + raw_dev = dev_get_drvdata(dev); + + if (!mtk_cam_is_m2m(ctx)) { + mtk_cam_call_seninf_set_pixelmode(ctx, ctx->seninf, + PAD_SRC_RAW0, + tgo_pxl_mode); + mtk_cam_seninf_set_camtg(ctx->seninf, PAD_SRC_RAW0, + pipeid_to_tgidx(raw_dev->id)); + } + } + + if (!mtk_cam_is_m2m(ctx)) { + ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 1); + if (ret) { + dev_info(cam->dev, "failed to stream on seninf %s:%d\n", + ctx->seninf->name, ret); + goto fail_pipe_off; + } + } else { + ctx->processing_buffer_list.cnt = 0; + ctx->composed_buffer_list.cnt = 0; + dev_dbg(cam->dev, + "[M2M] reset processing_buffer_list.cnt & composed_buffer_list.cnt\n"); + } + + if (ctx->used_raw_num) { + mtk_cam_raw_initialize(raw_dev, 0); + /* Twin */ + if (ctx->pipe->res_config.raw_num_used != 1) { + struct mtk_raw_device *raw_dev_sub = + get_sub_raw_dev(cam, ctx->pipe); + mtk_cam_raw_initialize(raw_dev_sub, 1); + + if (ctx->pipe->res_config.raw_num_used == 3) { + struct mtk_raw_device *raw_dev_sub2 = + get_sub2_raw_dev(cam, ctx->pipe); + mtk_cam_raw_initialize(raw_dev_sub2, 1); + } + } + } + + spin_lock(&ctx->streaming_lock); + if (!cam->streaming_ctx && cam->debug_fs) + need_dump_mem = true; + + streaming_ctx_latch = cam->streaming_ctx; + ctx->streaming = true; + cam->streaming_ctx |= 1 << ctx->stream_id; + spin_unlock(&ctx->streaming_lock); + + if (need_dump_mem) + cam->debug_fs->ops->reinit(cam->debug_fs, ctx->stream_id); + else + dev_dbg(cam->dev, + "No need to alloc mem for ctx: streaming_ctx(0x%x), debug_fs(%p)\n", + streaming_ctx_latch, cam->debug_fs); + ret = mtk_camsys_ctrl_start(ctx); + if (ret) + goto fail_streaming_off; + + mutex_lock(&cam->queue_lock); + mtk_cam_dev_req_try_queue(cam); /* request moved into working list */ + mutex_unlock(&cam->queue_lock); + + if (watchdog_scenario(ctx)) + mtk_ctx_watchdog_start(ctx, 4); + + dev_dbg(cam->dev, "streamed on camsys ctx:%d\n", ctx->stream_id); + + return 0; + +fail_streaming_off: + spin_lock(&ctx->streaming_lock); + ctx->streaming = false; + cam->streaming_ctx &= ~(1 << ctx->stream_id); + spin_unlock(&ctx->streaming_lock); + + if (!mtk_cam_is_m2m(ctx)) + v4l2_subdev_call(ctx->seninf, video, s_stream, 0); +fail_pipe_off: + for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) + v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0); + + return ret; +} + +int mtk_cam_ctx_stream_off(struct mtk_cam_ctx *ctx, struct mtk_cam_video_device *node) +{ + struct mtk_cam_device *cam = ctx->cam; + struct device *dev; + struct mtk_raw_device *raw_dev; + unsigned int i; + int ret; + + if (!ctx->streaming) { + dev_dbg(cam->dev, "ctx-%d is already streaming off\n", + ctx->stream_id); + return 0; + } + + if (watchdog_scenario(ctx)) + mtk_ctx_watchdog_stop(ctx); + + dev_info(cam->dev, "%s: ctx-%d: composer_cnt:%d, streaming_pipe:0x%x\n", + __func__, ctx->stream_id, cam->composer_cnt, ctx->streaming_pipe); + + spin_lock(&ctx->streaming_lock); + ctx->streaming = false; + cam->streaming_ctx &= ~(1 << ctx->stream_id); + spin_unlock(&ctx->streaming_lock); + + if (ctx->synced) + ctx->synced = 0; + + if (!mtk_cam_is_m2m(ctx)) { + ret = v4l2_subdev_call(ctx->seninf, video, s_stream, 0); + if (ret) { + dev_err(cam->dev, "failed to stream off %s:%d\n", + ctx->seninf->name, ret); + return -EPERM; + } + } + + if (ctx->used_raw_num) { + dev = mtk_cam_find_raw_dev(cam, ctx->used_raw_dev); + if (!dev) { + dev_info(cam->dev, "streamoff raw device not found\n"); + goto fail_stream_off; + } + raw_dev = dev_get_drvdata(dev); + mtk_cam_raw_stream_on(raw_dev, 0); + /* Twin */ + if (ctx->pipe->res_config.raw_num_used != 1) { + struct mtk_raw_device *raw_dev_sub = + get_sub_raw_dev(cam, ctx->pipe); + mtk_cam_raw_stream_on(raw_dev_sub, 0); + + if (ctx->pipe->res_config.raw_num_used == 3) { + struct mtk_raw_device *raw_dev_sub2 = + get_sub2_raw_dev(cam, ctx->pipe); + mtk_cam_raw_stream_on(raw_dev_sub2, 0); + } + } + } + + for (i = 0; i < MAX_PIPES_PER_STREAM && ctx->pipe_subdevs[i]; i++) { + ret = v4l2_subdev_call(ctx->pipe_subdevs[i], video, s_stream, 0); + if (ret) { + dev_err(cam->dev, "failed to stream off %s: %d\n", + ctx->pipe_subdevs[i]->name, ret); + return -EPERM; + } + } + + if (ctx->img_buf_pool.working_img_buf_size > 0) { + if (is_yuv_node(node->desc.id)) + dev = cam->raw.yuvs[0]; + else + dev = cam->raw.devs[0]; + + mtk_cam_img_working_buf_pool_release(ctx, dev); + } + + mtk_camsys_ctrl_stop(ctx); + +fail_stream_off: + if (ctx->used_raw_num) + isp_composer_destroy_session(ctx); + + dev_dbg(cam->dev, "streamed off camsys ctx:%d\n", ctx->stream_id); + + return 0; +} + +static int config_bridge_pad_links(struct mtk_cam_device *cam, + struct v4l2_subdev *seninf) +{ + struct media_entity *pipe_entity; + unsigned int i; + int ret; + + for (i = MTKCAM_SUBDEV_RAW_START; + i < MTKCAM_SUBDEV_RAW_START + cam->num_raw_devices; i++) { + pipe_entity = &cam->raw.pipelines[i].subdev.entity; + + dev_info(cam->dev, "create pad link %s %s\n", + seninf->entity.name, pipe_entity->name); + + ret = media_create_pad_link(&seninf->entity, + MTK_CAM_CIO_PAD_SRC, + pipe_entity, + MTK_CAM_CIO_PAD_SINK, + MEDIA_LNK_FL_DYNAMIC); + + if (ret) { + dev_warn(cam->dev, + "failed to create pad link %s %s err:%d\n", + seninf->entity.name, pipe_entity->name, + ret); + return ret; + } + } + + return 0; +} + +static int mtk_cam_create_links(struct mtk_cam_device *cam) +{ + struct v4l2_subdev *sd; + int ret = 0; + + v4l2_device_for_each_subdev(sd, &cam->v4l2_dev) { + if (sd->entity.function == MEDIA_ENT_F_VID_IF_BRIDGE) + ret = config_bridge_pad_links(cam, sd); + } + + return ret; +} + +static int mtk_cam_master_register(struct device *dev) +{ + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + struct media_device *media_dev = &cam_dev->media_dev; + int ret; + + dev_info(dev, "camsys | start %s\n", __func__); + + media_dev->dev = cam_dev->dev; + strscpy(media_dev->model, dev_driver_string(dev), + sizeof(media_dev->model)); + snprintf(media_dev->bus_info, sizeof(media_dev->bus_info), + "platform:%s", dev_name(dev)); + media_dev->hw_revision = 0; + media_dev->ops = &mtk_cam_dev_ops; + media_device_init(media_dev); + + cam_dev->v4l2_dev.mdev = media_dev; + ret = v4l2_device_register(cam_dev->dev, &cam_dev->v4l2_dev); + if (ret) { + dev_dbg(dev, "Failed to register V4L2 device: %d\n", ret); + goto fail_media_device_cleanup; + } + + ret = media_device_register(media_dev); + if (ret) { + dev_dbg(dev, "Failed to register media device: %d\n", + ret); + goto fail_v4l2_device_unreg; + } + + dev_info(dev, "%s success\n", __func__); + return 0; + +fail_v4l2_device_unreg: + v4l2_device_unregister(&cam_dev->v4l2_dev); + +fail_media_device_cleanup: + media_device_cleanup(&cam_dev->media_dev); + + return ret; +} + +static void mtk_cam_master_unregister(struct device *dev) +{ + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + + dev_info(dev, "camsys | start %s\n", __func__); + + media_device_unregister(&cam_dev->media_dev); + v4l2_device_unregister(&cam_dev->v4l2_dev); + media_device_cleanup(&cam_dev->media_dev); +} + +static int mtk_cam_async_add_by_driver(struct device *dev, + struct platform_driver *drv, + struct v4l2_async_notifier *notifier) +{ + struct fwnode_handle *fwnode; + struct device *p; + struct v4l2_async_connection *asc; + int dev_num = 0; + + p = platform_find_device_by_driver(NULL, &drv->driver); + while (p) { + dev_info(dev, "camsys | %s add %s\n", __func__, p->kobj.name); + + fwnode = dev_fwnode(p); + asc = v4l2_async_nf_add_fwnode(notifier, fwnode, + struct v4l2_async_connection); + put_device(p); + + if (IS_ERR(asc)) { + dev_info(dev, "%s add fwnode fail %ld\n", __func__, + PTR_ERR(asc)); + + return PTR_ERR(asc); + } + ++dev_num; + + p = platform_find_device_by_driver(p, &drv->driver); + } + + return dev_num; +} + +static int mtk_cam_async_subdev_add(struct device *dev) +{ + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + struct v4l2_async_notifier *notifier = &cam_dev->notifier; + int raw_num, yuv_num, seninf_num; + + raw_num = mtk_cam_async_add_by_driver(dev, &mtk_cam_raw_driver, + notifier); + yuv_num = mtk_cam_async_add_by_driver(dev, &mtk_cam_yuv_driver, + notifier); + seninf_num = mtk_cam_async_add_by_driver(dev, &seninf_pdrv, notifier); + + if (raw_num < 0 || yuv_num < 0 || seninf_num < 0) { + dev_err(dev, "%s failed\n", __func__); + return -ENODEV; + } + + cam_dev->num_raw_devices = raw_num; + cam_dev->num_seninf_devices = seninf_num; + dev_info(dev, "dependent module #: raw %d, yuv %d, seninf %d\n", + cam_dev->num_raw_devices, yuv_num, + cam_dev->num_seninf_devices); + + return 0; +} + +static void mtk_cam_ctx_init(struct mtk_cam_ctx *ctx, + struct mtk_cam_device *cam, + unsigned int stream_id) +{ + ctx->cam = cam; + ctx->stream_id = stream_id; + ctx->sensor = NULL; + + ctx->streaming_pipe = 0; + ctx->streaming_node_cnt = 0; + + ctx->used_raw_num = 0; + ctx->used_raw_dev = 0; + ctx->processing_buffer_list.cnt = 0; + ctx->composed_buffer_list.cnt = 0; + ctx->is_first_cq_done = 0; + ctx->cq_done_status = 0; + ctx->session_created = 0; + + INIT_LIST_HEAD(&ctx->using_buffer_list.list); + INIT_LIST_HEAD(&ctx->composed_buffer_list.list); + INIT_LIST_HEAD(&ctx->processing_buffer_list.list); + INIT_LIST_HEAD(&ctx->processing_img_buffer_list.list); + spin_lock_init(&ctx->using_buffer_list.lock); + spin_lock_init(&ctx->composed_buffer_list.lock); + spin_lock_init(&ctx->processing_buffer_list.lock); + spin_lock_init(&ctx->streaming_lock); + spin_lock_init(&ctx->first_cq_lock); + spin_lock_init(&ctx->processing_img_buffer_list.lock); + + mtk_ctx_watchdog_init(ctx); +} + +int mtk_cam_link_validate(struct v4l2_subdev *sd, + struct media_link *link, + struct v4l2_subdev_format *source_fmt, + struct v4l2_subdev_format *sink_fmt) +{ + int ret = 0; + + /* The width, height and code must match. */ + if (source_fmt->format.width != sink_fmt->format.width) { + dev_err(sd->entity.graph_obj.mdev->dev, + "%s: width does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.width, sink_fmt->format.width); + ret = -EPIPE; + } + + if (source_fmt->format.height != sink_fmt->format.height) { + dev_err(sd->entity.graph_obj.mdev->dev, + "%s: height does not match (source %u, sink %u)\n", + __func__, + source_fmt->format.height, sink_fmt->format.height); + ret = -EPIPE; + } + + if (source_fmt->format.code != sink_fmt->format.code) { + dev_err(sd->entity.graph_obj.mdev->dev, + "%s: warn: media bus code does not match (source 0x%8.8x, sink 0x%8.8x)\n", + __func__, + source_fmt->format.code, sink_fmt->format.code); + ret = -EPIPE; + } + + dev_dbg(sd->entity.graph_obj.mdev->dev, + "%s: link was \"%s\":%u -> \"%s\":%u\n", __func__, + link->source->entity->name, link->source->index, + link->sink->entity->name, link->sink->index); + + if (ret) + dev_info(sd->v4l2_dev->dev, + "%s: link validate failed pad/code/w/h: SRC(%d/0x%x/%d/%d), SINK(%d:0x%x/%d/%d)\n", + sd->name, source_fmt->pad, source_fmt->format.code, + source_fmt->format.width, source_fmt->format.height, + sink_fmt->pad, sink_fmt->format.code, + sink_fmt->format.width, sink_fmt->format.height); + + return ret; +} + +static int mtk_cam_debug_fs_init(struct mtk_cam_device *cam) +{ + /** + * The dump buffer size depdends on the meta buffer size + * which is variable among devices using different type of sensors + * , e.g. PD's statistic buffers. + */ + u32 dump_mem_size = MTK_CAM_DEBUG_DUMP_HEADER_MAX_SIZE + + CQ_BUF_SIZE + + camsys_get_meta_size(MTKCAM_IPI_RAW_META_STATS_CFG) + + RAW_STATS_CFG_VARIOUS_SIZE + + sizeof(struct mtkcam_ipi_frame_param) + + sizeof(struct mtkcam_ipi_config_param) * + RAW_PIPELINE_NUM; + + cam->debug_fs = mtk_cam_get_debugfs(); + if (!cam->debug_fs) + return 0; + + cam->debug_fs->ops->init(cam->debug_fs, cam, dump_mem_size); + cam->debug_wq = alloc_ordered_workqueue(dev_name(cam->dev), + __WQ_LEGACY | WQ_MEM_RECLAIM | + WQ_FREEZABLE); + if (!cam->debug_wq) + return -EINVAL; + + cam->debug_exception_wq = alloc_ordered_workqueue(dev_name(cam->dev), + __WQ_LEGACY | + WQ_MEM_RECLAIM | + WQ_FREEZABLE); + if (!cam->debug_exception_wq) { + destroy_workqueue(cam->debug_wq); + return -EINVAL; + } + + init_waitqueue_head(&cam->debug_exception_waitq); + + return 0; +} + +static void mtk_cam_debug_fs_deinit(struct mtk_cam_device *cam) +{ + if (!cam->debug_fs) + return; + + drain_workqueue(cam->debug_wq); + destroy_workqueue(cam->debug_wq); + drain_workqueue(cam->debug_exception_wq); + destroy_workqueue(cam->debug_exception_wq); + cam->debug_fs->ops->deinit(cam->debug_fs); +} + +static int register_sub_drivers(struct device *dev) +{ + int ret; + + ret = platform_driver_register(&seninf_pdrv); + if (ret) { + dev_info(dev, "%s seninf_pdrv fail\n", __func__); + goto REGISTER_SENINF_FAIL; + } + + ret = platform_driver_register(&seninf_core_pdrv); + if (ret) { + dev_info(dev, "%s seninf_core_pdrv fail\n", __func__); + goto REGISTER_SENINF_CORE_FAIL; + } + + ret = platform_driver_register(&mtk_cam_raw_driver); + if (ret) { + dev_info(dev, "%s mtk_cam_raw_driver fail\n", __func__); + goto REGISTER_RAW_FAIL; + } + + ret = platform_driver_register(&mtk_cam_yuv_driver); + if (ret) { + dev_info(dev, "%s mtk_cam_raw_driver fail\n", __func__); + goto REGISTER_YUV_FAIL; + } + + ret = mtk_cam_master_register(dev); + if (ret) { + dev_err(dev, "%s mtk_cam_master_register fail\n", __func__); + goto ADD_CAM_MASTER_FAIL; + } + + return 0; + +ADD_CAM_MASTER_FAIL: + platform_driver_unregister(&mtk_cam_yuv_driver); + +REGISTER_YUV_FAIL: + platform_driver_unregister(&mtk_cam_raw_driver); + +REGISTER_RAW_FAIL: + platform_driver_unregister(&seninf_core_pdrv); + +REGISTER_SENINF_CORE_FAIL: + platform_driver_unregister(&seninf_pdrv); + +REGISTER_SENINF_FAIL: + return ret; +} + +static void unregister_sub_drivers(struct device *dev) +{ + mtk_cam_master_unregister(dev); + + platform_driver_unregister(&mtk_cam_yuv_driver); + platform_driver_unregister(&mtk_cam_raw_driver); + platform_driver_unregister(&seninf_core_pdrv); + platform_driver_unregister(&seninf_pdrv); +} + +static int mtk_cam_master_complete(struct v4l2_async_notifier *notifier) +{ + struct mtk_cam_device *cam_dev = + container_of(notifier, struct mtk_cam_device, notifier); + struct device *dev = cam_dev->dev; + int ret; + + dev_info(dev, "cmasys | trigger %s\n", __func__); + + /* set raw and yuv internal */ + ret = mtk_cam_raw_setup_dependencies(&cam_dev->raw); + if (ret) { + dev_err(dev, "Failed to mtk_cam_raw_setup_dependencies: %d\n", ret); + goto fail_unbind_all; + } + + /* register raw subdev */ + ret = mtk_cam_raw_register_entities(&cam_dev->raw, &cam_dev->v4l2_dev); + if (ret) { + dev_err(dev, "Failed to init raw subdevs: %d\n", ret); + goto fail_remove_dependencies; + } + + mtk_cam_create_links(cam_dev); + + /* Expose all subdev's nodes */ + ret = v4l2_device_register_subdev_nodes(&cam_dev->v4l2_dev); + if (ret) { + dev_err(dev, "Failed to register subdev nodes\n"); + goto fail_unreg_raw_entities; + } + + dev_info(dev, "%s success\n", __func__); + + return 0; + +fail_unreg_raw_entities: + mtk_cam_raw_unregister_entities(&cam_dev->raw); + +fail_remove_dependencies: + /* nothing to do for now */ + +fail_unbind_all: + return ret; +} + +static int mtk_cam_master_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct mtk_cam_device *cam_dev = + container_of(notifier, struct mtk_cam_device, notifier); + struct mtk_raw *raw = &cam_dev->raw; + struct device *cam = cam_dev->dev; + struct device *dev = subdev->dev; + + dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__); + + if (strcmp(dev_driver_string(dev), "seninf") == 0) { + dev_dbg(cam, "%s@(seninf) done\n", __func__); + } else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) { + struct mtk_raw_device *raw_dev = dev_get_drvdata(dev); + + raw_dev->cam = cam_dev; + raw->devs[raw_dev->id] = dev; + raw->cam_dev = cam_dev->dev; + dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__); + } else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) { + struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev); + + raw->yuvs[yuv_dev->id] = dev; + dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__); + } else { + dev_warn(cam, "%s got unrecongized device\n", __func__); + } + + return 0; +} + +static void mtk_cam_master_unbound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct mtk_cam_device *cam_dev = + container_of(notifier, struct mtk_cam_device, notifier); + struct mtk_raw *raw = &cam_dev->raw; + struct device *cam = cam_dev->dev; + struct device *dev = subdev->dev; + + dev_info(cam, "cmasys | %s trigger %s\n", subdev->name, __func__); + + if (strcmp(dev_driver_string(dev), "seninf") == 0) { + dev_dbg(cam, "%s@(seninf) done\n", __func__); + } else if (strcmp(dev_driver_string(dev), "mtk-cam raw") == 0) { + struct mtk_raw_device *raw_dev = dev_get_drvdata(dev); + + mtk_cam_raw_unregister_entities(&cam_dev->raw); + + raw_dev->cam = NULL; + raw->devs[raw_dev->id] = NULL; + raw->cam_dev = NULL; + dev_dbg(cam, "%s@(mtk-cam raw) done\n", __func__); + } else if (strcmp(dev_driver_string(dev), "mtk-cam yuv") == 0) { + struct mtk_yuv_device *yuv_dev = dev_get_drvdata(dev); + + raw->yuvs[yuv_dev->id] = NULL; + dev_dbg(cam, "%s@(mtk-cam yuv) done\n", __func__); + } else { + dev_warn(cam, "%s got unrecongized device\n", __func__); + } +} + +static const struct v4l2_async_notifier_operations mtk_cam_async_nf_ops = { + .complete = mtk_cam_master_complete, + .bound = mtk_cam_master_bound, + .unbind = mtk_cam_master_unbound, +}; + +static int mtk_cam_probe(struct platform_device *pdev) +{ + struct mtk_cam_device *cam_dev; + struct device *dev = &pdev->dev; + struct resource *res; + int ret; + unsigned int i; + + dev_dbg(dev, "camsys | start %s\n", __func__); + + /* initialize structure */ + cam_dev = devm_kzalloc(dev, sizeof(*cam_dev), GFP_KERNEL); + if (!cam_dev) + return -ENOMEM; + + if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(34))) { + dev_err(dev, "%s: No suitable DMA available\n", __func__); + return -EIO; + } + + if (!dev->dma_parms) { + dev->dma_parms = + devm_kzalloc(dev, sizeof(*dev->dma_parms), GFP_KERNEL); + if (!dev->dma_parms) + return -ENOMEM; + } + + dma_set_max_seg_size(dev, UINT_MAX); + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "failed to get mem\n"); + return -ENODEV; + } + + cam_dev->base = devm_ioremap_resource(dev, res); + if (IS_ERR(cam_dev->base)) { + dev_err(dev, "failed to map register base\n"); + return PTR_ERR(cam_dev->base); + } + + cam_dev->dev = dev; + dev_set_drvdata(dev, cam_dev); + + cam_dev->composer_cnt = 0; + cam_dev->num_seninf_devices = 0; + + cam_dev->max_stream_num = MTKCAM_SUBDEV_MAX; + cam_dev->ctxs = devm_kcalloc(dev, cam_dev->max_stream_num, + sizeof(*cam_dev->ctxs), GFP_KERNEL); + if (!cam_dev->ctxs) + return -ENOMEM; + + cam_dev->streaming_ctx = 0; + for (i = 0; i < cam_dev->max_stream_num; i++) + mtk_cam_ctx_init(cam_dev->ctxs + i, cam_dev, i); + + cam_dev->running_job_count = 0; + spin_lock_init(&cam_dev->pending_job_lock); + spin_lock_init(&cam_dev->running_job_lock); + INIT_LIST_HEAD(&cam_dev->pending_job_list); + INIT_LIST_HEAD(&cam_dev->running_job_list); + + cam_dev->dma_processing_count = 0; + spin_lock_init(&cam_dev->dma_pending_lock); + spin_lock_init(&cam_dev->dma_processing_lock); + INIT_LIST_HEAD(&cam_dev->dma_pending); + INIT_LIST_HEAD(&cam_dev->dma_processing); + + mutex_init(&cam_dev->queue_lock); + + pm_runtime_enable(dev); + + ret = mtk_cam_of_rproc(cam_dev, pdev); + if (ret) + goto fail_destroy_mutex; + + ret = register_sub_drivers(dev); + if (ret) { + dev_err(dev, "fail to register_sub_drivers\n"); + goto fail_destroy_mutex; + } + + /* register mtk_cam as all isp subdev async parent */ + cam_dev->notifier.ops = &mtk_cam_async_nf_ops; + v4l2_async_nf_init(&cam_dev->notifier, &cam_dev->v4l2_dev); + ret = mtk_cam_async_subdev_add(dev); /* wait all isp sub drivers */ + if (ret) { + dev_err(dev, "%s failed mtk_cam_async_subdev_add\n", __func__); + goto fail_unregister_sub_drivers; + } + + ret = v4l2_async_nf_register(&cam_dev->notifier); + if (ret) { + dev_err(dev, "%s async_nf_register ret:%d\n", __func__, ret); + v4l2_async_nf_cleanup(&cam_dev->notifier); + goto fail_unregister_sub_drivers; + } + + ret = mtk_cam_debug_fs_init(cam_dev); + if (ret < 0) + goto fail_unregister_async_nf; + + dev_info(dev, "camsys | [%s] success\n", __func__); + + return 0; + +fail_unregister_async_nf: + v4l2_async_nf_unregister(&cam_dev->notifier); + +fail_unregister_sub_drivers: + unregister_sub_drivers(dev); + +fail_destroy_mutex: + mutex_destroy(&cam_dev->queue_lock); + + return ret; +} + +static void mtk_cam_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct mtk_cam_device *cam_dev = dev_get_drvdata(dev); + + pm_runtime_disable(dev); + + mtk_cam_debug_fs_deinit(cam_dev); + + v4l2_async_nf_unregister(&cam_dev->notifier); + + unregister_sub_drivers(dev); + + mutex_destroy(&cam_dev->queue_lock); +} + +static const struct dev_pm_ops mtk_cam_pm_ops = { + SET_RUNTIME_PM_OPS(mtk_cam_runtime_suspend, mtk_cam_runtime_resume, + NULL) +}; + +static struct platform_driver mtk_cam_driver = { + .probe = mtk_cam_probe, + .remove = mtk_cam_remove, + .driver = { + .name = "mtk-cam", + .of_match_table = of_match_ptr(mtk_cam_of_ids), + .pm = &mtk_cam_pm_ops, + } +}; + +module_platform_driver(mtk_cam_driver); + +MODULE_DESCRIPTION("MediaTek camera ISP driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h new file mode 100644 index 000000000000..46342624c198 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam.h @@ -0,0 +1,733 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_H +#define __MTK_CAM_H + +#include +#include +#include +#include +#include +#include +#include + +#include "mtk_cam-raw.h" +#include "mtk_cam-ipi.h" +#include "kd_imgsensor_define_v4l2.h" +#include "mtk_cam-seninf-def.h" +#include "mtk_cam-seninf-drv.h" +#include "mtk_cam-seninf-if.h" +#include "mtk_cam-ctrl.h" +#include "mtk_cam-debug.h" +#include "mtk_cam-plat-util.h" + +/* for SCP internal working buffers, need to align it with SCP */ +#define SIZE_OF_RAW_PRIV 20788 +#define SIZE_OF_RAW_WORKBUF 18600 +#define SIZE_OF_SESSION 22596 + +#define IPI_FRAME_BUF_SIZE ALIGN(sizeof(struct mtkcam_ipi_frame_param), SZ_1K) + +/* for cq working buffers */ +#define CQ_BUF_SIZE 0x8000 /* ISP7_1 */ +#define CAM_CQ_BUF_NUM 16 +#define CAM_IMG_BUF_NUM 6 +#define MAX_PIPES_PER_STREAM 5 +#define MTK_CAM_CTX_WATCHDOG_INTERVAL 100 +#define MTK_CAM_REQ_MAX_S_DATA 2 + +#define SENSOR_FMT_MASK 0xFFFF + +/* flags of mtk_cam_request */ +#define MTK_CAM_REQ_FLAG_SENINF_CHANGED BIT(0) +#define MTK_CAM_REQ_FLAG_SENINF_IMMEDIATE_UPDATE BIT(1) + +/* flags of mtk_cam_request_stream_data */ +#define MTK_CAM_REQ_S_DATA_FLAG_TG_FLASH BIT(0) + +#define MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT BIT(1) + +#define MTK_CAM_REQ_S_DATA_FLAG_SINK_FMT_UPDATE BIT(2) +/* Apply sensor mode and the timing is 1 vsync before */ +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_MODE_UPDATE_T1 BIT(3) + +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN BIT(4) + +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN BIT(5) + +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE BIT(6) + +#define MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE BIT(7) + +#define MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED BIT(8) + +struct mtk_cam_request; +struct mtk_cam_debug_fs; +struct mtk_cam_device; +struct mtk_raw_pipeline; + +struct mtk_cam_working_buf { + void *va; + dma_addr_t iova; + dma_addr_t scp_addr; + unsigned int size; +}; + +struct mtk_cam_msg_buf { + void *va; + dma_addr_t scp_addr; + unsigned int size; +}; + +struct mtk_cam_working_buf_entry { + struct mtk_cam_ctx *ctx; + struct mtk_cam_request_stream_data *s_data; + struct mtk_cam_working_buf buffer; + struct mtk_cam_msg_buf msg_buffer; + struct list_head list_entry; + int cq_desc_offset; + unsigned int cq_desc_size; + int sub_cq_desc_offset; + unsigned int sub_cq_desc_size; +}; + +struct mtk_cam_img_working_buf_entry { + struct mtk_cam_ctx *ctx; + struct mtk_cam_request_stream_data *s_data; + struct mtk_cam_working_buf img_buffer; + struct list_head list_entry; +}; + +struct mtk_cam_working_buf_list { + struct list_head list; + u32 cnt; + spinlock_t lock; /* protect this list and cnt */ +}; + +struct mtk_cam_req_work { + struct work_struct work; + struct mtk_cam_request_stream_data *s_data; + struct list_head list; + atomic_t is_queued; +}; + +struct mtk_cam_req_feature { + int raw_feature; + bool switch_prev_frame_done; + bool switch_curr_setting_done; + bool switch_done; +}; + +struct mtk_cam_sensor_work { + struct kthread_work work; + atomic_t is_queued; +}; + +/* + * struct mtk_cam_request_stream_data - per stream members of a request + * + * @pad_fmt: pad format configurtion for sensor switch. + * @frame_params: The frame info. & address info. of enabled DMA nodes. + * @frame_work: work queue entry for frame transmission to SCP. + * @working_buf: command queue buffer associated to this request + * @deque_list_node: the entry node of s_data for deque + * @cleanup_list_node: the entry node of s_data for cleanup + */ +struct mtk_cam_request_stream_data { + u32 index; + struct mtk_cam_request *req; + struct mtk_cam_ctx *ctx; + u32 pipe_id; + u32 frame_seq_no; + u32 flags; + unsigned long raw_dmas; + u64 timestamp; + u64 timestamp_mono; + atomic_t buf_state; /* default: -1 */ + struct mtk_cam_buffer *bufs[MTK_RAW_TOTAL_NODES]; + struct v4l2_subdev *sensor; + struct media_request_object *sensor_hdl_obj; + struct media_request_object *raw_hdl_obj; + struct v4l2_subdev_format seninf_fmt; + struct v4l2_subdev_format pad_fmt[MTK_RAW_PIPELINE_PADS_NUM]; + struct v4l2_rect pad_selection[MTK_RAW_PIPELINE_PADS_NUM]; + struct v4l2_format vdev_fmt[MTK_RAW_TOTAL_NODES]; + struct v4l2_selection vdev_selection[MTK_RAW_TOTAL_NODES]; + struct mtkcam_ipi_frame_param frame_params; + struct mtk_cam_sensor_work sensor_work; + struct mtk_cam_req_work seninf_s_fmt_work; + struct mtk_cam_req_work frame_work; + struct mtk_cam_req_work meta1_done_work; + struct mtk_cam_req_work frame_done_work; + struct mtk_camsys_ctrl_state state; + struct mtk_cam_working_buf_entry *working_buf; + unsigned int no_frame_done_cnt; + atomic_t seninf_dump_state; + struct mtk_cam_req_feature feature; + struct mtk_cam_req_dbg_work dbg_work; + struct mtk_cam_req_dbg_work dbg_exception_work; + struct list_head deque_list_node; + struct list_head cleanup_list_node; + atomic_t first_setting_check; +}; + +struct mtk_cam_req_pipe { + int s_data_num; + int req_seq; + struct mtk_cam_request_stream_data s_data[MTK_CAM_REQ_MAX_S_DATA]; +}; + +enum mtk_cam_request_state { + MTK_CAM_REQ_STATE_PENDING, + MTK_CAM_REQ_STATE_RUNNING, + MTK_CAM_REQ_STATE_DELETING, + MTK_CAM_REQ_STATE_COMPLETE, + MTK_CAM_REQ_STATE_CLEANUP, + NR_OF_MTK_CAM_REQ_STATE, +}; + +enum mtk_cam_pixel_mode { + PXL_MOD_1 = 0, + PXL_MOD_2, + PXL_MOD_4, + PXL_MOD_8, +}; + +/* + * mtk_cam_frame_sync: the frame sync state of one request + * + * @target: the num of ctx(sensor) which should be synced + * @on_cnt: the count of frame sync on called by ctx + * @off_cnt: the count of frame sync off called by ctx + * @op_lock: protect frame sync state variables + */ +struct mtk_cam_frame_sync { + unsigned int target; + unsigned int on_cnt; + unsigned int off_cnt; + struct mutex op_lock; /* sync operation lock */ +}; + +struct mtk_cam_req_raw_pipe_data { + struct mtk_cam_resource res; + int enabled_raw; +}; + +/* + * struct mtk_cam_request - MTK camera request. + * + * @req: Embedded struct media request. + * @pipe_used: pipe used in this request. Two or more pipes may share + * the same context. + * @ctx_used: context used in this request. + * @done_status: Record context done status. + * @done_status_lock: Spinlock for context done status. + * @fs: the frame sync state. + * @list: List entry of the object for pending_job_list or running_job_list. + * @cleanup_list: List entry of the request to cleanup. + * @p_data: restore stream request data in a pipe. + * @p_data: restore raw pipe resource data. + * @sync_id: frame sync index. + */ +struct mtk_cam_request { + struct media_request req; + unsigned int pipe_used; + unsigned int ctx_used; + unsigned int done_status; + spinlock_t done_status_lock; /* protect done_status */ + atomic_t state; + struct mtk_cam_frame_sync fs; + struct list_head list; + struct list_head cleanup_list; + struct mtk_cam_req_pipe p_data[MTKCAM_SUBDEV_MAX]; + struct mtk_cam_req_raw_pipe_data raw_pipe_data[MTKCAM_SUBDEV_RAW_END - + MTKCAM_SUBDEV_RAW_START]; + s64 sync_id; + atomic_t ref_cnt; +}; + +struct mtk_cam_working_buf_pool { + struct mtk_cam_ctx *ctx; + + struct dma_buf *working_buf_dmabuf; + void *working_buf_va; + dma_addr_t working_buf_iova; + dma_addr_t working_buf_scp_addr; + unsigned int working_buf_size; + + void *msg_buf_va; + dma_addr_t msg_buf_scp_addr; + unsigned int msg_buf_size; + + void *raw_workbuf_va; + dma_addr_t raw_workbuf_scp_addr; + unsigned int raw_workbuf_size; + + void *priv_workbuf_va; + dma_addr_t priv_workbuf_scp_addr; + unsigned int priv_workbuf_size; + + void *session_buf_va; + dma_addr_t session_buf_scp_addr; + unsigned int session_buf_size; + + struct mtk_cam_working_buf_entry working_buf[CAM_CQ_BUF_NUM]; + struct mtk_cam_working_buf_list cam_freelist; +}; + +struct mtk_cam_img_working_buf_pool { + struct mtk_cam_ctx *ctx; + struct dma_buf *working_img_buf_dmabuf; + void *working_img_buf_va; + dma_addr_t working_img_buf_iova; + dma_addr_t working_img_buf_scp_addr; + unsigned int working_img_buf_size; + struct mtk_cam_img_working_buf_entry img_working_buf[CAM_IMG_BUF_NUM]; + struct mtk_cam_working_buf_list cam_freeimglist; +}; + +struct mtk_cam_ctx { + struct mtk_cam_device *cam; + unsigned int stream_id; + unsigned int streaming; + unsigned int synced; + struct media_pipeline pipeline; + struct mtk_raw_pipeline *pipe; + unsigned int enabled_node_cnt; + unsigned int streaming_pipe; + unsigned int streaming_node_cnt; + unsigned int is_first_cq_done; + unsigned int cq_done_status; + atomic_t running_s_data_cnt; + struct v4l2_subdev *sensor; + struct v4l2_subdev *seninf; + struct v4l2_subdev *pipe_subdevs[MAX_PIPES_PER_STREAM]; + struct mtk_camsys_sensor_ctrl sensor_ctrl; + + unsigned int used_raw_num; + unsigned int used_raw_dev; + + struct task_struct *sensor_worker_task; + struct kthread_worker sensor_worker; + struct workqueue_struct *composer_wq; + struct workqueue_struct *frame_done_wq; + + struct completion session_complete; + struct completion m2m_complete; + int session_created; + + struct mtk_cam_working_buf_pool buf_pool; + struct mtk_cam_working_buf_list using_buffer_list; + struct mtk_cam_working_buf_list composed_buffer_list; + struct mtk_cam_working_buf_list processing_buffer_list; + + /* sensor image buffer pool handling from kernel */ + struct mtk_cam_img_working_buf_pool img_buf_pool; + struct mtk_cam_working_buf_list processing_img_buffer_list; + + atomic_t enqueued_frame_seq_no; + unsigned int composed_frame_seq_no; + unsigned int dequeued_frame_seq_no; + + spinlock_t streaming_lock; /* protect streaming */ + spinlock_t first_cq_lock; /* protect is_first_cq_done */ + + /* watchdog */ + int watchdog_timeout_tg; + atomic_t watchdog_dump; + atomic_long_t watchdog_prev; + struct timer_list watchdog_timer; + struct work_struct watchdog_work; + + /* support debug dump */ + struct mtkcam_ipi_config_param config_params; +}; + +struct mtk_cam_device { + struct device *dev; + + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + struct media_device media_dev; + void __iomem *base; + + struct mtk_scp *scp; + struct device *smem_dev; + phandle rproc_phandle; + struct rproc *rproc_handle; + + unsigned int composer_cnt; + + unsigned int num_seninf_devices; + unsigned int num_raw_devices; + unsigned int num_larb_devices; + + /* raw_pipe controller subdev */ + struct mtk_raw raw; + struct mutex queue_lock; /* protect queue request */ + + unsigned int max_stream_num; + unsigned int streaming_ctx; + unsigned int streaming_pipe; + struct mtk_cam_ctx *ctxs; + + /* request related */ + struct list_head pending_job_list; + spinlock_t pending_job_lock; /* protect pending_job_list */ + struct list_head running_job_list; + unsigned int running_job_count; + spinlock_t running_job_lock; /* protect running_job_list */ + + /* standard v4l2 buffer control */ + struct list_head dma_pending; + spinlock_t dma_pending_lock; /* protect dma_pending_list */ + struct list_head dma_processing; + spinlock_t dma_processing_lock; /* protect dma_processing_list and dma_processing_count */ + unsigned int dma_processing_count; + + struct mtk_cam_debug_fs *debug_fs; + struct workqueue_struct *debug_wq; + struct workqueue_struct *debug_exception_wq; + wait_queue_head_t debug_exception_waitq; +}; + +static inline struct mtk_cam_request_stream_data * +mtk_cam_req_work_get_s_data(struct mtk_cam_req_work *work) +{ + return work->s_data; +} + +static inline struct mtk_cam_request_stream_data * +mtk_cam_ctrl_state_to_req_s_data(struct mtk_camsys_ctrl_state *state) +{ + return container_of(state, struct mtk_cam_request_stream_data, state); +} + +static inline struct mtk_cam_request * +mtk_cam_ctrl_state_get_req(struct mtk_camsys_ctrl_state *state) +{ + struct mtk_cam_request_stream_data *request_stream_data; + + request_stream_data = mtk_cam_ctrl_state_to_req_s_data(state); + return request_stream_data->req; +} + +static inline u32 +mtk_cam_req_get_num_s_data(struct mtk_cam_request *req, u32 pipe_id) +{ + if (pipe_id >= MTKCAM_SUBDEV_MAX) + return 0; + + return req->p_data[pipe_id].s_data_num; +} + +/** + * Be used operation between request reinit and enqueue. + * For example, request-based set fmt and selection. + */ +static inline struct mtk_cam_request_stream_data * +mtk_cam_req_get_s_data_no_chk(struct mtk_cam_request *req, u32 pipe_id, u32 idx) +{ + return &req->p_data[pipe_id].s_data[idx]; +} + +static inline struct mtk_cam_request_stream_data * +mtk_cam_req_get_s_data(struct mtk_cam_request *req, u32 pipe_id, u32 idx) +{ + if (!req || pipe_id >= MTKCAM_SUBDEV_MAX) + return NULL; + + if (idx >= req->p_data[pipe_id].s_data_num) + return NULL; + + return mtk_cam_req_get_s_data_no_chk(req, pipe_id, idx); +} + +static inline struct mtk_cam_ctx * +mtk_cam_s_data_get_ctx(struct mtk_cam_request_stream_data *s_data) +{ + if (!s_data) + return NULL; + + return s_data->ctx; +} + +static inline char * +mtk_cam_s_data_get_dbg_str(struct mtk_cam_request_stream_data *s_data) +{ + return s_data->req->req.debug_str; +} + +static inline struct mtk_cam_request * +mtk_cam_s_data_get_req(struct mtk_cam_request_stream_data *s_data) +{ + if (!s_data) + return NULL; + + return s_data->req; +} + +static inline struct mtk_cam_req_raw_pipe_data * +mtk_cam_s_data_get_raw_pipe_data(struct mtk_cam_request_stream_data *s_data) +{ + if (!is_raw_subdev(s_data->pipe_id)) + return NULL; + + return &s_data->req->raw_pipe_data[s_data->pipe_id]; +} + +static inline struct mtk_cam_resource * +mtk_cam_s_data_get_res(struct mtk_cam_request_stream_data *s_data) +{ + if (!s_data) + return NULL; + + if (!is_raw_subdev(s_data->pipe_id)) + return NULL; + + return &s_data->req->raw_pipe_data[s_data->pipe_id].res; +} + +static inline int +mtk_cam_s_data_get_res_feature(struct mtk_cam_request_stream_data *s_data) +{ + return (!s_data || !is_raw_subdev(s_data->pipe_id)) ? + 0 : s_data->req->raw_pipe_data[s_data->pipe_id].res.raw_res.feature; +} + +static inline int +mtk_cam_s_data_get_vbuf_idx(struct mtk_cam_request_stream_data *s_data, int node_id) +{ + if (s_data->pipe_id >= MTKCAM_SUBDEV_RAW_START && + s_data->pipe_id < MTKCAM_SUBDEV_RAW_END) + return node_id - MTK_RAW_SINK_NUM; + + return -1; +} + +static inline void +mtk_cam_s_data_set_vbuf(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_buffer *buf, + int node_id) +{ + int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id); + + if (idx >= 0) + s_data->bufs[idx] = buf; +} + +static inline struct mtk_cam_buffer * +mtk_cam_s_data_get_vbuf(struct mtk_cam_request_stream_data *s_data, int node_id) +{ + int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id); + + if (idx >= 0) + return s_data->bufs[idx]; + return NULL; +} + +static inline struct v4l2_format * +mtk_cam_s_data_get_vfmt(struct mtk_cam_request_stream_data *s_data, int node_id) +{ + int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id); + + if (idx >= 0) + return &s_data->vdev_fmt[idx]; + + return NULL; +} + +static inline struct v4l2_mbus_framefmt * +mtk_cam_s_data_get_pfmt(struct mtk_cam_request_stream_data *s_data, int pad) +{ + if (pad >= 0) + return &s_data->pad_fmt[pad].format; + + return NULL; +} + +static inline struct v4l2_selection * +mtk_cam_s_data_get_vsel(struct mtk_cam_request_stream_data *s_data, int node_id) +{ + int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id); + + if (idx >= 0) + return &s_data->vdev_selection[idx]; + + return NULL; +} + +static inline void +mtk_cam_s_data_reset_vbuf(struct mtk_cam_request_stream_data *s_data, int node_id) +{ + int idx = mtk_cam_s_data_get_vbuf_idx(s_data, node_id); + + if (idx >= 0) + s_data->bufs[idx] = NULL; +} + +static inline void +mtk_cam_s_data_set_wbuf(struct mtk_cam_request_stream_data *s_data, + struct mtk_cam_working_buf_entry *buf_entry) +{ + buf_entry->s_data = s_data; + s_data->working_buf = buf_entry; +} + +static inline void +mtk_cam_s_data_reset_wbuf(struct mtk_cam_request_stream_data *s_data) +{ + if (!s_data->working_buf) + return; + + s_data->working_buf->s_data = NULL; + s_data->working_buf = NULL; +} + +static inline bool +mtk_cam_s_data_set_buf_state(struct mtk_cam_request_stream_data *s_data, + enum vb2_buffer_state state) +{ + if (!s_data) + return false; + + if (-1 == atomic_cmpxchg(&s_data->buf_state, -1, state)) + return true; + + return false; +} + +int mtk_cam_s_data_raw_select(struct mtk_cam_request_stream_data *s_data, + struct mtkcam_ipi_input_param *cfg_in_param); + +static inline struct mtk_cam_request_stream_data * +mtk_cam_sensor_work_to_s_data(struct kthread_work *work) +{ + return container_of(work, struct mtk_cam_request_stream_data, + sensor_work.work); +} + +static inline struct mtk_cam_seninf_dump_work * +to_mtk_cam_seninf_dump_work(struct work_struct *work) +{ + return container_of(work, struct mtk_cam_seninf_dump_work, work); +} + +static inline struct mtk_cam_request * +to_mtk_cam_req(struct media_request *__req) +{ + return container_of(__req, struct mtk_cam_request, req); +} + +static inline void +mtk_cam_pad_fmt_enable(struct v4l2_mbus_framefmt *framefmt) +{ + framefmt->flags |= V4L2_MBUS_FRAMEFMT_PAD_ENABLE; +} + +static inline void +mtk_cam_pad_fmt_disable(struct v4l2_mbus_framefmt *framefmt) +{ + framefmt->flags &= ~V4L2_MBUS_FRAMEFMT_PAD_ENABLE; +} + +static inline bool +mtk_cam_is_pad_fmt_enable(struct v4l2_mbus_framefmt *framefmt) +{ + return framefmt->flags & V4L2_MBUS_FRAMEFMT_PAD_ENABLE; +} + +static inline void mtk_cam_fs_reset(struct mtk_cam_frame_sync *fs) +{ + fs->target = 0; + fs->on_cnt = 0; + fs->off_cnt = 0; +} + +static inline struct device * +mtk_cam_find_raw_dev(struct mtk_cam_device *cam, unsigned int raw_mask) +{ + unsigned int i; + + for (i = 0; i < cam->num_raw_devices; i++) + if (raw_mask & (1 << i)) + return cam->raw.devs[i]; + + return NULL; +} + +void mtk_cam_buf_try_queue(struct mtk_cam_ctx *ctx); + +struct mtk_cam_ctx *mtk_cam_find_ctx(struct mtk_cam_device *cam, + struct media_entity *entity); +struct mtk_cam_ctx *mtk_cam_start_ctx(struct mtk_cam_device *cam, + struct mtk_cam_video_device *node); +void mtk_cam_stop_ctx(struct mtk_cam_ctx *ctx, + struct mtk_cam_video_device *node); +int mtk_cam_ctx_stream_on(struct mtk_cam_ctx *ctx, + struct mtk_cam_video_device *node); +int mtk_cam_ctx_stream_off(struct mtk_cam_ctx *ctx, + struct mtk_cam_video_device *node); +void mtk_cam_complete_raw_hdl(struct mtk_cam_request_stream_data *s_data); +void mtk_cam_complete_sensor_hdl(struct mtk_cam_request_stream_data *s_data); + +bool watchdog_scenario(struct mtk_cam_ctx *ctx); +void mtk_ctx_watchdog_kick(struct mtk_cam_ctx *ctx); + +int mtk_cam_call_seninf_set_pixelmode(struct mtk_cam_ctx *ctx, + struct v4l2_subdev *sd, + int pad_id, int pixel_mode); +void mtk_cam_dev_req_enqueue(struct mtk_cam_device *cam, + struct mtk_cam_request *req); +void mtk_cam_dev_req_cleanup(struct mtk_cam_ctx *ctx, int pipe_id, + int buf_state); +void mtk_cam_dev_req_clean_pending(struct mtk_cam_device *cam, int pipe_id, + int buf_state); + +void mtk_cam_req_get(struct mtk_cam_request *req, int pipe_id); +bool mtk_cam_req_put(struct mtk_cam_request *req, int pipe_id); + +void mtk_cam_dev_req_try_queue(struct mtk_cam_device *cam); + +void mtk_cam_s_data_update_timestamp(struct mtk_cam_buffer *buf, + struct mtk_cam_request_stream_data *s_data); + +int mtk_cam_dequeue_req_frame(struct mtk_cam_ctx *ctx, + unsigned int dequeued_frame_seq_no, + int pipe_id); + +void mtk_cam_dev_job_done(struct mtk_cam_ctx *ctx, + struct mtk_cam_request *req, + int pipe_id, + enum vb2_buffer_state state); + +void mtk_cam_apply_pending_dev_config(struct mtk_cam_request_stream_data *s_data); + +int mtk_cam_link_validate(struct v4l2_subdev *sd, + struct media_link *link, + struct v4l2_subdev_format *source_fmt, + struct v4l2_subdev_format *sink_fmt); + +struct mtk_cam_request *mtk_cam_get_req(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no); +struct mtk_cam_request_stream_data * +mtk_cam_get_req_s_data(struct mtk_cam_ctx *ctx, unsigned int pipe_id, + unsigned int frame_seq_no); + +struct mtk_raw_pipeline *mtk_cam_dev_get_raw_pipeline(struct mtk_cam_device *cam, + unsigned int id); + +struct mtk_raw_device *get_main_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe); +struct mtk_raw_device *get_sub_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe); +struct mtk_raw_device *get_sub2_raw_dev(struct mtk_cam_device *cam, + struct mtk_raw_pipeline *pipe); + +int isp_composer_create_session(struct mtk_cam_ctx *ctx); +void isp_composer_destroy_session(struct mtk_cam_ctx *ctx); + +#endif /*__MTK_CAM_H */ From patchwork Wed Oct 9 11:15:47 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: 13828184 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 A97D9CF0454 for ; Wed, 9 Oct 2024 11:21:45 +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=0VuqLarItLYDrY4ulRpQt6clWO5FgklO7PyHifwu5X0=; b=ivbuTN28+mkMsVVuRfdQ0e3c6h K7qeDXes101R5//kxwZMkSPpAnkvHhDvw1pHodnSLpdABIcKPemsb7D0Jcs9FJkfe4RDL861E5N01 13hSAo9PTVKJnubcbGR6cZQ2czzNe+/0tkd829VQ0fchpFa6/OFE6rJNpu6bZDiQiKQXNZHx/1Ls0 b2t/pJxQ9Wc6ouOH70QAvShLaJJEqRv93e5bqB85y6N36YaTSKZrpx1FFKZ3UH6Ko+V5akQAs5n5A yTMuGaW4qzFe0yHZnQ+ZlSBV4KdvfxLEuzHVvx/d0KXVOzENx2YDQMSRoLL7xjU+WEljebzXoOo3E B8husYUg==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUlE-000000092O1-1Nn7; Wed, 09 Oct 2024 11:21:44 +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 1syUgM-000000091OK-25w6 for linux-mediatek@bombadil.infradead.org; Wed, 09 Oct 2024 11:16:43 +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=0VuqLarItLYDrY4ulRpQt6clWO5FgklO7PyHifwu5X0=; b=ZO5Dx6vRw3PfqPWwsBcVGhPCKC DubdlzrWRrhNmQM9TA2QfRIxGwFE5DxeqImk9Jbl15xJqGc4sU1i/vU3eKv269C/tmcl20ysGqUFH c+zbE3xBaciUiklNqNy0XVaASRaJleKBYzm416Lw40H+zJ1kgDb+eVeT8WHvzmuZU4e2DDkdUGwVi mBSMHxW+61ZnQ3jxdzkDmFsrGwpHRQRY0+iD1bAdk8cRB2/mztBieYdRQ5Ul/8lXJAYHbvvBDlzcq dhw1HYdgA2sSJ4axO5m3blrtBrMAQOvkdnLFLtVDWaK38GR0vY+VZD+aO6yP//xxP1c9YzUsg7tGQ mksorfQw==; Received: from mailgw02.mediatek.com ([216.200.240.185]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgG-00000004v7i-3kJ9 for linux-mediatek@lists.infradead.org; Wed, 09 Oct 2024 11:16:41 +0000 X-UUID: e3bae304862f11efba0aef63c0775dbf-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=0VuqLarItLYDrY4ulRpQt6clWO5FgklO7PyHifwu5X0=; b=WTLLc3/vwpcE2aZvNfkQBDkuVik1RQ7oAef22xTEFLorYZaTjIS7Neaa5PNHY+aFHPfgBndBFT+4zE86auoqs4p93RZB9wbzuj76ojsnUtxa+eXQA6REqnX8CbYMKKwPkBI/FFvA3PPLsLuENNfIRERC1E0HLAn5OxIoiFiVKpM=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:14adb57e-0aaf-4f6b-811b-b265229b5236,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:338a0041-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|NGT X-CID-BAS: 2,OSH|NGT,0,_ X-CID-FACTOR: TF_CID_SPAM_SNR X-UUID: e3bae304862f11efba0aef63c0775dbf-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 1126053070; Wed, 09 Oct 2024 04:16:11 -0700 Received: from mtkmbs13n2.mediatek.inc (172.21.101.108) by MTKMBS14N1.mediatek.inc (172.21.101.75) 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 06/10] media: platform: mediatek: add isp_7x utility Date: Wed, 9 Oct 2024 19:15:47 +0800 Message-ID: <20241009111551.27052-7-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--22.759400-8.000000 X-TMASE-MatchedRID: z3tGnJ59QgwjC5wW0aMJWG3NvezwBrVmNNuh+5zmS69fGNbhMhMRcpqb MiXJH8nx00qMv6F9X+6haDFxW9qw7zP6pt+J6m1m0C5BWPk1/EF1ZrYdf6+oJN9RlPzeVuQQkVx Pq+4YGBEtIcNCL+1lT7L0CwDGT5MlADAYgCjdKFvU3m2KoscyC7LiLKO9VZOi8rXw7/nLp58HiC Fmyfp2MIMsP+XBS+etzsaP39ElYThq+Lkur34drWxxOjnyr8CbFk73i4rVVIFBQfUgydCNn174o 4FL+8GyQOM0NwAMF4k4FWFUYgGHGBF4l1oN/bmOB7TqRAYVohbbKTxp3+WtIDb9TB28UbkiEWEB IibfYRLZoTly3PGW4HNLZaN7B77MoT61G3YSs7mVOwZbcOalSwreImldQ5BDfc8MDDp7ngeEY2+ qvfbJSbPFJkbfigk4TdO3nD4mIn8DcLqIJgk0tyYRREGYqtmUjiWciALpTNMY0A95tjAn+1UUam jc+3TC1KN/0FTZ6dFvKnkxoTqLSpLwwU+EaJP04RtSDjG+z7Auhg66Itb65ci9AjK6C8p1t9zUw xhckRFv/6+1g7VW3j0v5c2s0m9MAzA5lRc6UniHZXNSWjgdUzcah+QZUHeOOu8B7pM3AuUQtsfG 305+H9gjcRUxmHvDjxdoJIBed+Um4SY1UdFN+Y+YSzwl92XTz+tKvxV+YbATb/3sT17MXM1Xk2r 63LS+xkNDM5+z4N0t7QCTmkVcWc0C5Uci3F0GwVaayvK71l/QpOLaYmAnSNiQJkdS260msqi63S rtewlNZmYh6DtgzcfGGslQqEob932fm8yB1Z6eAiCmPx4NwGmRqNBHmBveg6X7YSXnSlqZv9WvR V/RbgtuKBGekqUpOlxBO2IcOBaUTGVAhB5EbQ== X-TM-AS-User-Approved-Sender: No X-TM-AS-User-Blocked-Sender: No X-TMASE-Result: 10--22.759400-8.000000 X-TMASE-Version: SMEX-14.0.0.3152-9.1.1006-23728.005 X-TM-SNTS-SMTP: 6D027AF76D068496F2B10E0E0B54BEED2A883E61A9E9DDB663CE0E552F10514F2000:8 X-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Introduces utility files for the MediaTek ISP7.x camsys driver. These utilities provide essential platform definitions, debugging tools, and management functions to support ISP operations and SCP communication. Key functionalities include: 1.Hardware pipeline and register definitions for managing image processing modules. 2.DMA debugging utilities and buffer management functions. 3.Definitions of supported image formats for proper data handling. 4.IPI and SCP communication structures for module state management and configuring ISP. 5.Metadata parameters for configuring image processing. Signed-off-by: Shu-hsiang Yang --- .../mediatek/isp/isp_7x/camsys/mtk_cam-defs.h | 168 ++ .../isp/isp_7x/camsys/mtk_cam-dmadbg.h | 721 +++++ .../mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h | 87 + .../mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h | 233 ++ .../isp/isp_7x/camsys/mtk_cam-meta-mt8188.h | 2436 +++++++++++++++++ .../isp/isp_7x/camsys/mtk_cam-plat-util.c | 207 ++ .../isp/isp_7x/camsys/mtk_cam-plat-util.h | 16 + .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.c | 393 +++ .../mediatek/isp/isp_7x/camsys/mtk_cam-pool.h | 28 + .../isp/isp_7x/camsys/mtk_cam-regs-mt8188.h | 382 +++ 10 files changed, 4671 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-dmadbg.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h new file mode 100644 index 000000000000..7d4ad189b9fc --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-defs.h @@ -0,0 +1,168 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTKCAM_DEFS_H +#define __MTKCAM_DEFS_H +/** + * This definition is for the following version: + * + * MTK_CAM_IPI_VERSION_MAJOR: 0 + * MTK_CAM_IPI_VERSION_MINOR: 1 + */ + +#include +#include "mtk_cam-fmt.h" + +/* + * Note: + * Following definitions are used in IPI-messaging. + * Values are used in software control flow only and cannot be applied to + * hw registers directly. + */ + +/* camsys hw pipelines */ +enum mtkcam_pipe_subdev { + MTKCAM_SUBDEV_RAW_START = 0, + MTKCAM_SUBDEV_RAW_0 = MTKCAM_SUBDEV_RAW_START, + MTKCAM_SUBDEV_RAW_1, + MTKCAM_SUBDEV_RAW_2, + MTKCAM_SUBDEV_RAW_END, + MTKCAM_SUBDEV_MAX = MTKCAM_SUBDEV_RAW_END, +}; + +#define MTKCAM_SUBDEV_RAW_MASK (BIT(MTKCAM_SUBDEV_RAW_0) | \ + BIT(MTKCAM_SUBDEV_RAW_1) | \ + BIT(MTKCAM_SUBDEV_RAW_2)) + +static inline int is_raw_subdev(unsigned char subdev_id) +{ + return (subdev_id == MTKCAM_SUBDEV_RAW_0 || + subdev_id == MTKCAM_SUBDEV_RAW_1 || + subdev_id == MTKCAM_SUBDEV_RAW_2); +} + +enum mtkcam_pipe_dev { + MTKCAM_PIPE_RAW_A = 0, + MTKCAM_PIPE_RAW_B, + MTKCAM_PIPE_RAW_C, + MTKCAM_PIPE_MAX +}; + +enum mtkcam_ipi_raw_video_id { + MTKCAM_IPI_RAW_ID_UNKNOWN = 0, + MTKCAM_IPI_RAW_RAWI_2, /* RAWI_R2 */ + MTKCAM_IPI_RAW_RAWI_3, /* RAWI_R3 */ + MTKCAM_IPI_RAW_RAWI_5, /* RAWI_R5 */ + MTKCAM_IPI_RAW_RAWI_6, /* RAWI_R6 */ + MTKCAM_IPI_RAW_IMGO, /* IMGO_R1 */ + MTKCAM_IPI_RAW_UFEO, /* UFEO_R1 */ + MTKCAM_IPI_RAW_RRZO, /* RRZO_R1 */ + MTKCAM_IPI_RAW_UFGO, /* UFGO_R1 */ + MTKCAM_IPI_RAW_YUVO_1, /* YUVO_R1 */ + MTKCAM_IPI_RAW_YUVO_2, /* YUVO_R2 */ + MTKCAM_IPI_RAW_YUVO_3, /* YUVO_R3 */ + MTKCAM_IPI_RAW_YUVO_4, /* YUVO_R4 */ + MTKCAM_IPI_RAW_YUVO_5, /* YUVO_R5 */ + MTKCAM_IPI_RAW_RZH1N2TO_2, /* RZH1N2TO_R2 */ + MTKCAM_IPI_RAW_DRZS4NO_1, /* DRZS4NO_R1 */ + MTKCAM_IPI_RAW_DRZS4NO_2, /* DRZS4NO_R2 */ + MTKCAM_IPI_RAW_DRZS4NO_3, /* DRZS4NO_R3 */ + MTKCAM_IPI_RAW_RZH1N2TO_3, /* RZH1N2TO_R3 */ + MTKCAM_IPI_RAW_RZH1N2TO_1, /* RZH1N2TO_R1 */ + MTKCAM_IPI_RAW_META_STATS_CFG, /* All settings */ + MTKCAM_IPI_RAW_META_STATS_0, /* statistics */ + + /* + * MTKCAM_IPI_RAW_META_STATS_1 is for AFO only, the buffer can be + * dequeued once we got the dma done. + */ + MTKCAM_IPI_RAW_META_STATS_1, + + /* statistics may be pass to DIP */ + MTKCAM_IPI_RAW_META_STATS_2, + MTKCAM_IPI_RAW_ID_MAX, +}; + +/* Supported bayer pixel order */ +enum mtkcam_ipi_bayer_pxl_id { + MTKCAM_IPI_BAYER_PXL_ID_B = 0, + MTKCAM_IPI_BAYER_PXL_ID_GB = 1, + MTKCAM_IPI_BAYER_PXL_ID_GR = 2, + MTKCAM_IPI_BAYER_PXL_ID_R = 3, + MTKCAM_IPI_BAYER_PXL_ID_UNKNOWN = 4, +}; + +/* special input patterns */ +enum mtkcam_ipi_sensor_pattern { + MTKCAM_IPI_SENSOR_PATTERN_NORMAL = 0, + MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX = 1, + MTKCAM_IPI_SENSOR_PATTERN_QUADCODE = 2, + MTKCAM_IPI_SENSOR_PATTERN_4CELL = 3, + MTKCAM_IPI_SENSOR_PATTERN_MONO = 4, + MTKCAM_IPI_SENSOR_PATTERN_IVHDR = 5, + MTKCAM_IPI_SENSOR_PATTERN_ZVHDR = 6, + MTKCAM_IPI_SENSOR_PATTERN_4CELL_IVHDR = 7, + MTKCAM_IPI_SENSOR_PATTERN_4CELL_ZVHDR = 8, + MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX_IVHDR = 9, + MTKCAM_IPI_SENSOR_PATTERN_DUAL_PIX_ZVHDR = 10, + MTKCAM_IPI_SENSOR_PATTERN_YUV = 11, + MTKCAM_IPI_SENSOR_PATTERN_NORMAL_PD = 12, +}; + +enum mtkcam_ipi_raw_path_control { + MTKCAM_IPI_IMGO_UNPROCESSED = 0, + MTKCAM_IPI_IMGO_AFTER_BPC, + MTKCAM_IPI_IMGO_AFTER_FRZ, + MTKCAM_IPI_IMGO_AFTER_FUS, + MTKCAM_IPI_IMGO_AFTER_DGN, + MTKCAM_IPI_IMGO_AFTER_LSC, + MTKCAM_IPI_IMGO_AFTER_HLR, + MTKCAM_IPI_IMGO_AFTER_LTM, + MTKCAM_IPI_IMGO_FULLY_PROCESSED = MTKCAM_IPI_IMGO_AFTER_LTM, +}; + +/* For LBIT_MODE G2 */ +enum mtkcam_ipi_sw_feature_control { + MTKCAM_IPI_SW_FEATURE_NORMAL = 0, + /* Normal */ +}; + +enum mtkcam_ipi_hw_path_control { + MTKCAM_IPI_HW_PATH_ON_THE_FLY = 0, + /* TG direct link */ + MTKCAM_IPI_HW_PATH_ON_THE_FLY_M2M = 1, + /* On device tuning */ + MTKCAM_IPI_HW_PATH_OFFLINE_M2M = 7, + /* SW trigger rawi */ +}; + +enum mtkcam_ipi_meta_valid_num_control { + MTKCAM_IPI_FBCX_AAO = 0, + MTKCAM_IPI_FBCX_AAHO, + MTKCAM_IPI_FBCX_AFO, + MTKCAM_IPI_FBCX_TSFSO_1, + MTKCAM_IPI_FBCX_TSFSO_2, + MTKCAM_IPI_FBCX_LTMSO, + MTKCAM_IPI_FBCX_FLKO, + MTKCAM_IPI_FBCX_ACTSO, + MTKCAM_IPI_FBCX_PDO, + MTKCAM_IPI_FBCX_TNCSYO, + MTKCAM_IPI_FBCX_RZH1N2TO_R1, + MTKCAM_IPI_FBCX_RZH1N2TO_R2, + MTKCAM_IPI_FBCX_RZH1N2TO_R3, + MTKCAM_IPI_FBCX_LAST, +}; + +enum { + BIN_AUTO = 0, + BIN_OFF = BIN_AUTO, + BIN_ON = (1 << 0), + CBN_2X2_ON = (1 << 4), + CBN_3X3_ON = (1 << 5), + CBN_4X4_ON = (1 << 6), + QBND_ON = (1 << 8) +}; + +#endif /* __MTKCAM_DEFS_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-dmadbg.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-dmadbg.h new file mode 100644 index 000000000000..83e92316add6 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-dmadbg.h @@ -0,0 +1,721 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_RAW_DMADBG_H +#define __MTK_CAM_RAW_DMADBG_H + +#include "mtk_cam-raw_debug.h" + +static __maybe_unused struct dma_debug_item dbg_RAWI_R2[] = { + {0x00000000, "rawi_r2 32(hex) 0000"}, + {0x00000100, "rawi_r2 state_checksum"}, + {0x00000200, "rawi_r2 line_pix_cnt_tmp"}, + {0x00000300, "rawi_r2 line_pix_cnt"}, + {0x00000500, "rawi_r2 smi_debug_data (case 0)"}, + {0x00010600, "rawi_r2 aff(fifo)_debug_data (case 1)"}, + {0x00030600, "rawi_r2 aff(fifo)_debug_data (case 3)"}, + {0x01000040, "rawi_r2_smi / plane-0 / data-crc"}, + {0x01000041, "rawi_r2_smi / plane-0 / addr-crc"}, + {0x00000080, "rawi_r2_smi / smi_latency_mon output"}, + {0x000000A0, "rawi_r2_smi / plane-0 / { len-cnt, dle-cnt }"}, + {0x000000C0, "rawi_r2_smi / plane-0 / maddr_max record"}, + {0x000000C1, "rawi_r2_smi / plane-0 / maddr_min record"}, +}; + +static __maybe_unused struct dma_debug_item dbg_RAWI_R2_UFD[] = { + {0x00000001, "rawi_r2 ufd 32(hex) 0000"}, + {0x00000101, "rawi_r2 ufd state_checksum"}, + {0x00000201, "rawi_r2 ufd line_pix_cnt_tmp"}, + {0x00000301, "rawi_r2 ufd line_pix_cnt"}, +}; + +static __maybe_unused struct dma_debug_item dbg_RAWI_R3[] = { + {0x00000003, "rawi_r3 32(hex) 0000"}, + {0x00000103, "rawi_r3 state_checksum"}, + {0x00000203, "rawi_r3 line_pix_cnt_tmp"}, + {0x00000303, "rawi_r3 line_pix_cnt"}, + {0x00000503, "rawi_r3 smi_debug_data (case 0)"}, + {0x00010603, "rawi_r3 aff(fifo)_debug_data (case 1)"}, + {0x00030603, "rawi_r3 aff(fifo)_debug_data (case 3)"}, + {0x01000043, "rawi_r3_smi / plane-0 / data-crc"}, + {0x01000044, "rawi_r3_smi / plane-0 / addr-crc"}, + {0x00000082, "rawi_r3_smi / smi_latency_mon output"}, + {0x000000A2, "rawi_r3_smi / plane-0 / { len-cnt, dle-cnt }"}, + {0x000002C0, "rawi_r3_smi / plane-0 / maddr_max record"}, + {0x000002C1, "rawi_r3_smi / plane-0 / maddr_min record"}, +}; + +static __maybe_unused struct dma_debug_item dbg_IMGO_R1[] = { + {0x00000019, "imgo_r1 32(hex) 0000"}, + {0x00000119, "imgo_r1 state_checksum"}, + {0x00000219, "imgo_r1 line_pix_cnt_tmp"}, + {0x00000319, "imgo_r1 line_pix_cnt"}, + {0x00000819, "imgo_r1 smi_debug_data (case 0)"}, + {0x00010719, "imgo_r1 aff(fifo)_debug_data (case 1)"}, + {0x00030719, "imgo_r1 aff(fifo)_debug_data (case 3)"}, + + {0x01000059, "imgo_r1_smi / plane-0 - imgo_r1 / data-crc"}, + + {0x0000008B, "imgo_r1_smi / smi_latency_mon output"}, + + {0x000000AB, "imgo_r1_smi / plane-0 / {len-cnt, dle-cnt}"}, + {0x000000AC, "imgo_r1_smi / plane-0 / {load_com-cnt, bvalid-cnt}"}, + + {0x000013C0, "imgo_r1_smi / plane-0 / maddr_max record"}, + {0x000013C1, "imgo_r1_smi / plane-0 / maddr_min record"}, +}; + +static __maybe_unused struct dma_debug_item dbg_AAHO_R1[] = { + {0x0000001B, "32(hex) 0000"}, + {0x0000011B, "state_checksum"}, + {0x0000021B, "line_pix_cnt_tmp"}, + {0x0000031B, "line_pix_cnt"}, + {0x0000081B, "smi_debug_data (case 0)"}, + {0x0001071B, "aff(fifo)_debug_data (case 1)"}, + {0x0003071B, "aff(fifo)_debug_data (case 3)"}, + + {0x0100005B, "fho_r1_smi / plane-1 - aaho_r1 / data-crc"}, + + {0x000000AD, "fho_r1_smi / plane-0 - fho_r1 / len-cnt, dle-cnt"}, + {0x000000AE, "fho_r1_smi / plane-0 - fho_r1 / load_com-cnt, bvalid-cnt"}, + {0x000000AF, "fho_r1_smi / plane-1 - aaho_r1 / len-cnt, dle-cnt"}, + {0x000000B0, "fho_r1_smi / plane-1 - aaho_r1 / load_com-cnt, bvalid-cnt"}, + {0x000000B1, "fho_r1_smi / plane-2 - pdo_r1 / len-cnt, dle-cnt"}, + {0x000000B2, "fho_r1_smi / plane-2 - pdo_r1 / load_com-cnt, bvalid-cnt"}, +}; + +static __maybe_unused struct dma_debug_item dbg_PDO_R1[] = { + {0x0000001C, "32(hex) 0000"}, + {0x0000011C, "state_checksum"}, + {0x0000021C, "line_pix_cnt_tmp"}, + {0x0000031C, "line_pix_cnt"}, + {0x0000081C, "smi_debug_data (case 0)"}, + {0x0001071C, "aff(fifo)_debug_data (case 1)"}, + {0x0003071C, "aff(fifo)_debug_data (case 3)"}, + + {0x000000AD, "fho_r1_smi / plane-0 - fho_r1 / len-cnt, dle-cnt"}, + {0x000000AE, "fho_r1_smi / plane-0 - fho_r1 / load_com-cnt, bvalid-cnt"}, + {0x000000AF, "fho_r1_smi / plane-1 - aaho_r1 / len-cnt, dle-cnt"}, + {0x000000B0, "fho_r1_smi / plane-1 - aaho_r1 / load_com-cnt, bvalid-cnt"}, + {0x000000B1, "fho_r1_smi / plane-2 - pdo_r1 / len-cnt, dle-cnt"}, + {0x000000B2, "fho_r1_smi / plane-2 - pdo_r1 / load_com-cnt, bvalid-cnt"}, +}; + +static __maybe_unused struct dma_debug_item dbg_PDI_R1[] = { + {0x00000014, "pdi_r1 32(hex) 0000"}, + {0x00000114, "pdi_r1 state_checksum"}, + {0x00000214, "pdi_r1 line_pix_cnt_tmp"}, + {0x00000314, "pdi_r1 line_pix_cnt"}, + {0x00000414, "pdi_r1 important_status"}, + {0x00000514, "pdi_r1 cmd_data_cnt"}, + {0x00000614, "pdi_r1 tilex_byte_cnt"}, + {0x00000714, "pdi_r1 tiley_cnt"}, + {0x00000814, "pdi_r1 burst_line_cnt"}, +}; + +// M4U_PORT CAM3_YUVO_R1: yuvo_r1 + yuvbo_r1 +static __maybe_unused struct dma_debug_item dbg_YUVO_R1[] = { + {0x00000000, "yuvo_r1 32(hex) 0000"}, + {0x00000100, "yuvo_r1 state_checksum"}, + {0x00000200, "yuvo_r1 line_pix_cnt_tmp"}, + {0x00000300, "yuvo_r1 line_pix_cnt"}, + {0x00000800, "yuvo_r1 smi_debug_data (case 0)"}, + {0x00010700, "yuvo_r1 aff(fifo)_debug_data (case 1)"}, + {0x00030700, "yuvo_r1 aff(fifo)_debug_data (case 3)"}, + + {0x00000001, "yuvbo_r1 32(hex) 0000"}, + {0x00000101, "yuvbo_r1 state_checksum"}, + {0x00000201, "yuvbo_r1 line_pix_cnt_tmp"}, + {0x00000301, "yuvbo_r1 line_pix_cnt"}, + {0x00000801, "yuvbo_r1 smi_debug_data (case 0)"}, + {0x00010701, "yuvbo_r1 aff(fifo)_debug_data (case 1)"}, + {0x00030701, "yuvbo_r1 aff(fifo)_debug_data (case 3)"}, + + {0x01000040, "yuvo_r1_smi / plane-0 - yuvo_r1 / data-crc"}, + {0x01000041, "yuvo_r1_smi / plane-1 - yuvbo_r1 / data-crc"}, + + {0x00000080, "yuvo_r1_smi / smi_latency_mon output"}, + + {0x000000AD, "yuvo_r1_smi / plane-0 - yuvo_r1 / { len-cnt, dle-cnt }"}, + {0x000000AE, "yuvo_r1_smi / plane-0 - yuvo_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000AF, "yuvo_r1_smi / plane-1 - yuvbo_r1 / { len-cnt, dle-cnt }"}, + {0x000000B0, "yuvo_r1_smi / plane-1 - yuvbo_r1 / { load_com-cnt, bvalid-cnt }"}, + + {0x000000C0, + "yuvo_r1_smi / plane-0 - yuvo_r1_smi / plane-0 - yuvo_r1 / maddr_max"}, + {0x000000C1, + "yuvo_r1_smi / plane-0 - yuvo_r1_smi / plane-0 - yuvo_r1 / maddr_min"}, + {0x000001C0, + "yuvo_r1_smi / plane-1 - yuvo_r1_smi / plane-0 - yuvbo_r1 / maddr_max"}, + {0x000001C1, + "yuvo_r1_smi / plane-1 - yuvo_r1_smi / plane-0 - yuvbo_r1 / maddr_min"}, +}; + +// M4U_PORT CAM3_YUVO_R3: yuvo_r3 + yuvbo_r3 +static __maybe_unused struct dma_debug_item dbg_YUVO_R3[] = { + {0x00000004, "yuvo_r3 32(hex) 0000"}, + {0x00000104, "yuvo_r3 state_checksum"}, + {0x00000204, "yuvo_r3 line_pix_cnt_tmp"}, + {0x00000304, "yuvo_r3 line_pix_cnt"}, + {0x00000804, "smi_debug_data (case 0)"}, + {0x00010704, "aff(fifo)_debug_data (case 1)"}, + {0x00030704, "aff(fifo)_debug_data (case 3)"}, + + {0x00000005, "yuvbo_r3 32(hex) 0000"}, + {0x00000105, "yuvbo_r3 state_checksum"}, + {0x00000205, "yuvbo_r3 line_pix_cnt_tmp"}, + {0x00000305, "yuvbo_r3 line_pix_cnt"}, + {0x00000805, "yuvbo_r3 smi_debug_data (case 0)"}, + {0x00010705, "yuvbo_r3 aff(fifo)_debug_data (case 1)"}, + {0x00030705, "yuvbo_r3 aff(fifo)_debug_data (case 3)"}, + + {0x01000042, "yuvo_r3_smi / plane-0 - yuvo_r3 / data-crc"}, + {0x01000043, "yuvo_r3_smi / plane-1 - yuvbo_r1 / data-crc"}, + + {0x00000081, "yuvo_r3_smi / smi_latency_mon output"}, + + {0x000000B1, "yuvo_r3_smi / plane-0 - yuvo_r3 / { len-cnt, dle-cnt }"}, + {0x000000B2, "yuvo_r3_smi / plane-0 - yuvo_r3 / { load_com-cnt, bvalid-cnt }"}, + {0x000000B3, "yuvo_r3_smi / plane-1 - yuvbo_r3 / { len-cnt, dle-cnt }"}, + {0x000000B4, "yuvo_r3_smi / plane-1 - yuvbo_r3 / { load_com-cnt, bvalid-cnt }"}, + + {0x000002C0, + "yuvo_r3_smi / plane-0 - yuvo_r3_smi / plane-0 - yuvo_r3 / maddr_max"}, + {0x000002C1, + "yuvo_r3_smi / plane-0 - yuvo_r3_smi / plane-0 - yuvo_r3 / maddr_min"}, + {0x000003C0, + "yuvo_r3_smi / plane-1 - yuvo_r3_smi / plane-0 - yuvbo_r3 / maddr_max"}, + {0x000003C1, + "yuvo_r3_smi / plane-1 - yuvo_r3_smi / plane-0 - yuvbo_r3 / maddr_min"}, +}; + +// M4U_PORT CAM3_YUVCO_R1: yuvco_r1 + yuvdo_r1 + yuvco_r3 + yuvdo_r3 +static __maybe_unused struct dma_debug_item dbg_YUVCO_R1[] = { + {0x00000002, "yuvco_r1 32(hex) 0000"}, + {0x00000102, "yuvco_r1 state_checksum"}, + {0x00000202, "yuvco_r1 line_pix_cnt_tmp"}, + {0x00000302, "yuvco_r1 line_pix_cnt"}, + {0x00000802, "yuvco_r1 smi_debug_data (case 0)"}, + {0x00010702, "yuvco_r1 aff(fifo)_debug_data (case 1)"}, + {0x00030702, "yuvco_r1 aff(fifo)_debug_data (case 3)"}, + + {0x00000003, "yuvdo_r1 32(hex) 0000"}, + {0x00000103, "yuvdo_r1 state_checksum"}, + {0x00000203, "yuvdo_r1 line_pix_cnt_tmp"}, + {0x00000303, "yuvdo_r1 line_pix_cnt"}, + {0x00000803, "yuvdo_r1 smi_debug_data (case 0)"}, + {0x00010703, "yuvdo_r1 aff(fifo)_debug_data (case 1)"}, + {0x00030703, "yuvdo_r1 aff(fifo)_debug_data (case 3)"}, + + {0x01000044, "yuvco_r1_smi / plane-0 - yuvco_r1 / data-crc"}, + {0x01000045, "yuvco_r1_smi / plane-1 - yuvco_r1 / data-crc"}, + {0x01000046, "yuvco_r1_smi / plane-2 - yuvco_r1 / data-crc"}, + {0x01000047, "yuvco_r1_smi / plane-3 - yuvco_r1 / data-crc"}, + + {0x00000082, "yuvco_r1_smi / smi_latency_mon output"}, + + {0x000004C0, + "yuvco_r1_smi / plane-0 - yuvco_r1_smi / plane-0 - yuvco_r1 / maddr_max"}, + {0x000004C1, + "yuvco_r1_smi / plane-0 - yuvco_r1_smi / plane-0 - yuvco_r1 / maddr_min"}, + {0x000005C0, + "yuvco_r1_smi / plane-1 - yuvco_r1_smi / plane-0 - yuvdo_r1 / maddr_max"}, + {0x000005C1, + "yuvco_r1_smi / plane-1 - yuvco_r1_smi / plane-0 - yuvdo_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_YUVCO_R3[] = { + {0x00000006, "yuvco_r3 32(hex) 0000"}, + {0x00000106, "yuvco_r3 state_checksum"}, + {0x00000206, "yuvco_r3 line_pix_cnt_tmp"}, + {0x00000306, "yuvco_r3 line_pix_cnt"}, + {0x00000806, "yuvco_r3 smi_debug_data (case 0)"}, + {0x00010706, "yuvco_r3 aff(fifo)_debug_data (case 1)"}, + {0x00030706, "yuvco_r3 aff(fifo)_debug_data (case 3)"}, + + {0x00000007, "yuvdo_r3 32(hex) 0000"}, + {0x00000107, "yuvdo_r3 state_checksum"}, + {0x00000207, "yuvdo_r3 line_pix_cnt_tmp"}, + {0x00000307, "yuvdo_r3 line_pix_cnt"}, + {0x00000807, "yuvdo_r3 smi_debug_data (case 0)"}, + {0x00010707, "yuvdo_r3 aff(fifo)_debug_data (case 1)"}, + {0x00030707, "yuvdo_r3 aff(fifo)_debug_data (case 3)"}, + + {0x01000044, "yuvco_r1_smi / plane-0 - yuvco_r1 / data-crc"}, + {0x01000045, "yuvco_r1_smi / plane-1 - yuvco_r1 / data-crc"}, + {0x01000046, "yuvco_r1_smi / plane-2 - yuvco_r1 / data-crc"}, + {0x01000047, "yuvco_r1_smi / plane-3 - yuvco_r1 / data-crc"}, + + {0x00000082, "yuvco_r1_smi / smi_latency_mon output"}, + + {0x000006C0, + "yuvco_r1_smi / plane-2 - yuvco_r1_smi / plane-0 - yuvco_r3 / maddr_max"}, + {0x000006C1, + "yuvco_r1_smi / plane-2 - yuvco_r1_smi / plane-0 - yuvco_r3 / maddr_max"}, + {0x000007C0, + "yuvco_r1_smi / plane-3 - yuvco_r1_smi / plane-0 - yuvdo_r3 / maddr_max"}, + {0x000007C1, + "yuvco_r1_smi / plane-3 - yuvco_r1_smi / plane-0 - yuvdo_r3 / maddr_min"}, +}; + +// M4U_PORT CAM3_YUVO_R2: yuvo_r2 + yuvbo_r2 + yuvo_r4 + yuvbo_r4 + yuvo_r5 + yuvbo_r5 +static __maybe_unused struct dma_debug_item dbg_YUVO_R2[] = { + {0x00000008, "yuvo_r2 32(hex) 0000"}, + {0x00000108, "yuvo_r2 state_checksum"}, + {0x00000208, "yuvo_r2 line_pix_cnt_tmp"}, + {0x00000308, "yuvo_r2 line_pix_cnt"}, + {0x00000408, "yuvo_r2 important_status"}, + {0x00000508, "yuvo_r2 cmd_data_cnt"}, + {0x00000608, "yuvo_r2 cmd_cnt_for_bvalid_phase"}, + {0x00000708, "yuvo_r2 input_h_cnt"}, + {0x00000808, "yuvo_r2 input_v_cnt"}, + {0x00000908, "yuvo_r2 xfer_y_cnt"}, + + {0x00000009, "yuvbo_r2 32(hex) 0000"}, + {0x00000109, "yuvbo_r2 state_checksum"}, + {0x00000209, "yuvbo_r2 line_pix_cnt_tmp"}, + {0x00000309, "yuvbo_r2 line_pix_cnt"}, + {0x00000409, "yuvbo_r2 important_status"}, + {0x00000509, "yuvbo_r2 cmd_data_cnt"}, + {0x00000609, "yuvbo_r2 cmd_cnt_for_bvalid_phase"}, + {0x00000709, "yuvbo_r2 input_h_cnt"}, + {0x00000809, "yuvbo_r2 input_v_cnt"}, + {0x00000909, "yuvbo_r2 xfer_y_cnt"}, + + {0x01000048, "yuvo_r2_smi / plane-0 - yuvo_r2 / data-crc"}, + {0x01000049, "yuvo_r2_smi / plane-1 - yuvbo_r2 / data-crc"}, + + {0x00000083, "yuvo_r2_smi / smi_latency_mon output"}, + + {0x000008C0, + "yuvo_r2_smi / plane-0 - yuvo_r2_smi / plane-1 - cqi_r3 / maddr_max"}, + {0x000008C1, + "yuvo_r2_smi / plane-0 - yuvo_r2_smi / plane-1 - cqi_r3 / maddr_min"}, + {0x000009C0, + "yuvo_r2_smi / plane-1 - yuvo_r2_smi / plane-1 - cqi_r4 / maddr_max"}, + {0x000009C1, + "yuvo_r2_smi / plane-1 - yuvo_r2_smi / plane-1 - cqi_r4 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_YUVO_R4[] = { + {0x0000000A, "yuvo_r4 32(hex) 0000"}, + {0x0000010A, "yuvo_r4 state_checksum"}, + {0x0000020A, "yuvo_r4 line_pix_cnt_tmp"}, + {0x0000030A, "yuvo_r4 line_pix_cnt"}, + {0x0000040A, "yuvo_r4 important_status"}, + {0x0000050A, "yuvo_r4 cmd_data_cnt"}, + {0x0000060A, "yuvo_r4 cmd_cnt_for_bvalid_phase"}, + {0x0000070A, "yuvo_r4 input_h_cnt"}, + {0x0000080A, "yuvo_r4 input_v_cnt"}, + {0x0000090A, "yuvo_r4 xfer_y_cnt"}, + + {0x0000000B, "yuvbo_r4 32(hex) 0000"}, + {0x0000010B, "yuvbo_r4 state_checksum"}, + {0x0000020B, "yuvbo_r4 line_pix_cnt_tmp"}, + {0x0000030B, "yuvbo_r4 line_pix_cnt"}, + {0x0000040B, "yuvbo_r4 important_status"}, + {0x0000050B, "yuvbo_r4 cmd_data_cnt"}, + {0x0000060B, "yuvbo_r4 cmd_cnt_for_bvalid_phase"}, + {0x0000070B, "yuvbo_r4 input_h_cnt"}, + {0x0000080B, "yuvbo_r4 input_v_cnt"}, + {0x0000090B, "yuvbo_r4 xfer_y_cnt"}, + + {0x0100004A, "yuvo_r2_smi / plane-2 - yuvo_r4 / data-crc"}, + {0x0100004B, "yuvo_r2_smi / plane-3 - yuvbo_r4 / data-crc"}, + + {0x00000083, "yuvo_r2_smi / smi_latency_mon output"}, + + {0x00000AC0, + "yuvo_r2_smi / plane-2 - yuvo_r2_smi / plane-0 - lsci_r1 / maddr_max"}, + {0x00000AC1, + "yuvo_r2_smi / plane-2 - yuvo_r2_smi / plane-0 - lsci_r1 / maddr_min"}, + {0x00000BC0, + "yuvo_r2_smi / plane-3 - yuvo_r2_smi / plane-0 - bpci_r1 / maddr_max"}, + {0x00000BC1, + "yuvo_r2_smi / plane-3 - yuvo_r2_smi / plane-0 - bpci_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_YUVO_R5[] = { + {0x0000000C, "yuvo_r5 32(hex) 0000"}, + {0x0000010C, "yuvo_r5 state_checksum"}, + {0x0000020C, "yuvo_r5 line_pix_cnt_tmp"}, + {0x0000030C, "yuvo_r5 line_pix_cnt"}, + {0x0000040C, "yuvo_r5 important_status"}, + {0x0000050C, "yuvo_r5 cmd_data_cnt"}, + {0x0000060C, "yuvo_r5 cmd_cnt_for_bvalid_phase"}, + {0x0000070C, "yuvo_r5 input_h_cnt"}, + {0x0000080C, "yuvo_r5 input_v_cnt"}, + {0x0000090C, "yuvo_r5 xfer_y_cnt"}, + + {0x0000000D, "yuvbo_r5 32(hex) 0000"}, + {0x0000010D, "yuvbo_r5 state_checksum"}, + {0x0000020D, "yuvbo_r5 line_pix_cnt_tmp"}, + {0x0000030D, "yuvbo_r5 line_pix_cnt"}, + {0x0000040D, "yuvbo_r5 important_status"}, + {0x0000050D, "yuvbo_r5 cmd_data_cnt"}, + {0x0000060D, "yuvbo_r5 cmd_cnt_for_bvalid_phase"}, + {0x0000070D, "yuvbo_r5 input_h_cnt"}, + {0x0000080D, "yuvbo_r5 input_v_cnt"}, + {0x0000090D, "yuvbo_r5 xfer_y_cnt"}, + + {0x0100004C, "yuvo_r2_smi / plane-4 - yuvo_r5 / data-crc"}, + {0x0100004D, "yuvo_r2_smi / plane-5 - yuvbo_r5 / data-crc"}, + + {0x00000083, "yuvo_r2_smi / smi_latency_mon output"}, + + {0x00000CC0, + "yuvo_r2_smi / plane-4 - yuvo_r2_smi / plane-1 - bpci_r2 / maddr_max"}, + {0x00000CC1, + "yuvo_r2_smi / plane-4 - yuvo_r2_smi / plane-1 - bpci_r2 / maddr_min"}, + {0x00000DC0, + "yuvo_r2_smi / plane-5 - yuvo_r2_smi / plane-2 - bpci_r3 / maddr_max"}, + {0x00000DC1, + "yuvo_r2_smi / plane-5 - yuvo_r2_smi / plane-2 - bpci_r3 / maddr_min"}, +}; + +// M4U_PORT CAM3_RZH1N2TO_R1: rzh1n2to_r1 + rzh1n2tbo_r1 + rzh1n2to_r2 + rzh1n2to_r3 + rzh1n2tbo_r3 +static __maybe_unused struct dma_debug_item dbg_RZH1N2TO_R1[] = { + {0x0000000E, "rzh1n2to_r1 32(hex) 0000"}, + {0x0000010E, "rzh1n2to_r1 state_checksum"}, + {0x0000020E, "rzh1n2to_r1 line_pix_cnt_tmp"}, + {0x0000030E, "rzh1n2to_r1 line_pix_cnt"}, + {0x0000040E, "rzh1n2to_r1 important_status"}, + {0x0000050E, "rzh1n2to_r1 cmd_data_cnt"}, + {0x0000060E, "rzh1n2to_r1 cmd_cnt_for_bvalid_phase"}, + {0x0000070E, "rzh1n2to_r1 input_h_cnt"}, + {0x0000080E, "rzh1n2to_r1 input_v_cnt"}, + {0x0000090E, "rzh1n2to_r1 xfer_y_cnt"}, + + {0x0000000F, "rzh1n2tbo_r1 32(hex) 0000"}, + {0x0000010F, "rzh1n2tbo_r1 state_checksum"}, + {0x0000020F, "rzh1n2tbo_r1 line_pix_cnt_tmp"}, + {0x0000030F, "rzh1n2tbo_r1 line_pix_cnt"}, + {0x0000040F, "rzh1n2tbo_r1 important_status"}, + {0x0000050F, "rzh1n2tbo_r1 cmd_data_cnt"}, + {0x0000060F, "rzh1n2tbo_r1 cmd_cnt_for_bvalid_phase"}, + {0x0000070F, "rzh1n2tbo_r1 input_h_cnt"}, + {0x0000080F, "rzh1n2tbo_r1 input_v_cnt"}, + {0x0000090F, "rzh1n2tbo_r1 xfer_y_cnt"}, + + {0x00000084, "rzh1n2to_r1_smi / smi_latency_mon output"}, + + {0x00000EC0, + "rzh1n2to_r1_smi / plane-0 - rzh1n2to_r1_smi / plane-3 - rzh1n2to_r1 / maddr_max"}, + {0x00000EC1, + "rzh1n2to_r1_smi / plane-0 - rzh1n2to_r1_smi / plane-3 - rzh1n2to_r1 / maddr_min"}, + {0x00000FC0, + "rzh1n2to_r1_smi / plane-1 - rzh1n2to_r1_smi / plane-4 - rzh1n2tbo_r1 / maddr_max"}, + {0x00000FC1, + "rzh1n2to_r1_smi / plane-1 - rzh1n2to_r1_smi / plane-4 - rzh1n2tbo_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_RZH1N2TO_R2[] = { + {0x00000010, "rzh1n2to_r2 32(hex) 0000"}, + {0x00000110, "rzh1n2to_r2 state_checksum"}, + {0x00000210, "rzh1n2to_r2 line_pix_cnt_tmp"}, + {0x00000310, "rzh1n2to_r2 line_pix_cnt"}, + {0x00000410, "rzh1n2to_r2 important_status"}, + {0x00000510, "rzh1n2to_r2 cmd_data_cnt"}, + {0x00000610, "rzh1n2to_r2 cmd_cnt_for_bvalid_phase"}, + {0x00000710, "rzh1n2to_r2 input_h_cnt"}, + {0x00000810, "rzh1n2to_r2 input_v_cnt"}, + {0x00000910, "rzh1n2to_r2 xfer_y_cnt"}, + + {0x01000050, "rzh1n2to_r1_smi / plane-2 - rzh1n2to_r2 / data-crc"}, + + {0x00000084, "rzh1n2to_r1_smi / smi_latency_mon output"}, + + {0x000010C0, + "rzh1n2to_r1_smi / plane-2 - rzh1n2to_r1_smi / plane-0 - rzh1n2to_r2 / maddr_max"}, + {0x000010C1, + "rzh1n2to_r1_smi / plane-2 - rzh1n2to_r1_smi / plane-0 - rzh1n2to_r2 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_RZH1N2TO_R3[] = { + {0x00000011, "rzh1n2to_r3 32(hex) 0000"}, + {0x00000111, "rzh1n2to_r3 state_checksum"}, + {0x00000211, "rzh1n2to_r3 line_pix_cnt_tmp"}, + {0x00000311, "rzh1n2to_r3 line_pix_cnt"}, + {0x00000411, "rzh1n2to_r3 important_status"}, + {0x00000511, "rzh1n2to_r3 cmd_data_cnt"}, + {0x00000611, "rzh1n2to_r3 cmd_cnt_for_bvalid_phase"}, + {0x00000711, "rzh1n2to_r3 input_h_cnt"}, + {0x00000811, "rzh1n2to_r3 input_v_cnt"}, + {0x00000911, "rzh1n2to_r3 xfer_y_cnt"}, + + {0x00000012, "rzh1n2tbo_r3 32(hex) 0000"}, + {0x00000112, "rzh1n2tbo_r3 state_checksum"}, + {0x00000212, "rzh1n2tbo_r3 line_pix_cnt_tmp"}, + {0x00000312, "rzh1n2tbo_r3 line_pix_cnt"}, + {0x00000412, "rzh1n2tbo_r3 important_status"}, + {0x00000512, "rzh1n2tbo_r3 cmd_data_cnt"}, + {0x00000612, "rzh1n2tbo_r3 cmd_cnt_for_bvalid_phase"}, + {0x00000712, "rzh1n2tbo_r3 input_h_cnt"}, + {0x00000812, "rzh1n2tbo_r3 input_v_cnt"}, + {0x00000912, "rzh1n2tbo_r3 xfer_y_cnt"}, + + {0x01000051, "rzh1n2to_r1_smi / plane-3 - rzh1n2to_r3 / data-crc"}, + {0x01000052, "rzh1n2to_r1_smi / plane-4 - rzh1n2tbo_r3 / data-crc"}, + + {0x00000084, "rzh1n2to_r1_smi / smi_latency_mon output"}, + + {0x000011C0, + "rzh1n2to_r1_smi / plane-3 - rzh1n2to_r1_smi / plane-1 - rzh1n2to_r3 / maddr_max"}, + {0x000011C1, + "rzh1n2to_r1_smi / plane-3 - rzh1n2to_r1_smi / plane-1 - rzh1n2to_r3 / maddr_min"}, + {0x000012C0, + "rzh1n2to_r1_smi / plane-4 - rzh1n2to_r1_smi / plane-2 - rzh1n2tbo_r3 / maddr_max"}, + {0x000012C1, + "rzh1n2to_r1_smi / plane-4 - rzh1n2to_r1_smi / plane-2 - rzh1n2tbo_r3 / maddr_min"}, +}; + +// M4U_PORT CAM3_DRZS4NO_R1: drzs4no_r1 + drzs4no_r2 + drzs4no_r3 + lmvo_r1 + actso_r1 +static __maybe_unused struct dma_debug_item dbg_DRZS4NO_R1[] = { + {0x00000013, "drzs4no_r1 32(hex) 0000"}, + {0x00000113, "drzs4no_r1 state_checksum"}, + {0x00000213, "drzs4no_r1 line_pix_cnt_tmp"}, + {0x00000313, "drzs4no_r1 line_pix_cnt"}, + {0x00000413, "drzs4no_r1 important_status"}, + {0x00000513, "drzs4no_r1 cmd_data_cnt"}, + {0x00000613, "drzs4no_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000713, "drzs4no_r1 input_h_cnt"}, + {0x00000813, "drzs4no_r1 input_v_cnt"}, + {0x00000913, "drzs4no_r1 xfer_y_cnt"}, + + {0x01000053, "drzs4no_r1_smi / plane-0 - drzs4no_r1 / data-crc"}, + + {0x00000085, "drzs4no_r1_smi / smi_latency_mon output"}, + + {0x000013C0, + "drzs4no_r1_smi / plane-0 - drzs4no_r1_smi / plane-0 - drzs4no_r1 / maddr_max"}, + {0x000013C1, + "drzs4no_r1_smi / plane-0 - drzs4no_r1_smi / plane-0 - drzs4no_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_DRZS4NO_R2[] = { + {0x00000014, "drzs4no_r2 32(hex) 0000"}, + {0x00000114, "drzs4no_r2 state_checksum"}, + {0x00000214, "drzs4no_r2 line_pix_cnt_tmp"}, + {0x00000314, "drzs4no_r2 line_pix_cnt"}, + {0x00000414, "drzs4no_r2 important_status"}, + {0x00000514, "drzs4no_r2 cmd_data_cnt"}, + {0x00000614, "drzs4no_r2 cmd_cnt_for_bvalid_phase"}, + {0x00000714, "drzs4no_r2 input_h_cnt"}, + {0x00000814, "drzs4no_r2 input_v_cnt"}, + {0x00000914, "drzs4no_r2 xfer_y_cnt"}, + + {0x01000054, "drzs4no_r1_smi / plane-1 - drzs4no_r2 / data-crc"}, + + {0x00000085, "drzs4no_r1_smi / smi_latency_mon output"}, + + {0x000014C0, + "drzs4no_r1_smi / plane-1 - drzs4no_r1_smi / plane-0 - drzs4no_r2 / maddr_max"}, + {0x000014C1, + "drzs4no_r1_smi / plane-1 - drzs4no_r1_smi / plane-0 - drzs4no_r2 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_DRZS4NO_R3[] = { + {0x00000015, "drzs4no_r3 32(hex) 0000"}, + {0x00000115, "drzs4no_r3 state_checksum"}, + {0x00000215, "drzs4no_r3 line_pix_cnt_tmp"}, + {0x00000315, "drzs4no_r3 line_pix_cnt"}, + {0x00000415, "drzs4no_r3 important_status"}, + {0x00000515, "drzs4no_r3 cmd_data_cnt"}, + {0x00000615, "drzs4no_r3 cmd_cnt_for_bvalid_phase"}, + {0x00000715, "drzs4no_r3 input_h_cnt"}, + {0x00000815, "drzs4no_r3 input_v_cnt"}, + {0x00000915, "drzs4no_r3 xfer_y_cnt"}, + + {0x01000055, "drzs4no_r1_smi / plane-2 - drzs4no_r3 / data-crc"}, + + {0x00000085, "drzs4no_r1_smi / smi_latency_mon output"}, + + {0x000015C0, + "drzs4no_r1_smi / plane-2 - drzs4no_r1_smi / plane-1 - drzs4no_r3 / maddr_max record"}, + {0x000015C1, + "drzs4no_r1_smi / plane-2 - drzs4no_r1_smi / plane-1 - drzs4no_r3 / maddr_min record"}, +}; + +static __maybe_unused struct dma_debug_item dbg_LMVO_R1[] = { + {0x00000016, "lmvo_r1 32(hex) 0000"}, + {0x00000116, "lmvo_r1 state_checksum"}, + {0x00000216, "lmvo_r1 line_pix_cnt_tmp"}, + {0x00000316, "lmvo_r1 line_pix_cnt"}, + {0x00000416, "lmvo_r1 important_status"}, + {0x00000516, "lmvo_r1 cmd_data_cnt"}, + {0x00000616, "lmvo_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000716, "lmvo_r1 input_h_cnt"}, + {0x00000816, "lmvo_r1 input_v_cnt"}, + {0x00000916, "lmvo_r1 xfer_y_cnt"}, + + {0x01000056, "drzs4no_r1_smi / plane-3 - lmvo_r1 / data-crc"}, + + {0x00000085, "drzs4no_r1_smi / smi_latency_mon output"}, + + {0x000016C0, + "drzs4no_r1_smi / plane-3 - drzs4no_r1_smi / plane-2 - lmvo_r1 / maddr_max"}, + {0x000016C1, + "drzs4no_r1_smi / plane-3 - drzs4no_r1_smi / plane-2 - lmvo_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_ACTSO_R1[] = { + {0x00000017, "actso_r1 32(hex) 0000"}, + {0x00000117, "actso_r1 state_checksum"}, + {0x00000217, "actso_r1 line_pix_cnt_tmp"}, + {0x00000317, "actso_r1 line_pix_cnt"}, + {0x00000417, "actso_r1 important_status"}, + {0x00000517, "actso_r1 cmd_data_cnt"}, + {0x00000617, "actso_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000717, "actso_r1 input_h_cnt"}, + {0x00000817, "actso_r1 input_v_cnt"}, + {0x00000917, "actso_r1 xfer_y_cnt"}, + + {0x01000057, "drzs4no_r1_smi / plane-4 - actso_r1) / data-crc"}, + + {0x00000085, "drzs4no_r1_smi / smi_latency_mon output"}, + + {0x000017C0, + "drzs4no_r1_smi / plane-4 - drzs4no_r1_smi / plane-0 - actsoo_r1 / maddr_max record"}, + {0x000017C1, + "drzs4no_r1_smi / plane-4 - drzs4no_r1_smi / plane-0 - actsoo_r1 / maddr_min record"}, +}; + +// M4U_PORT CAM3_TNCSO_R1: tncso_r1 + tncsbo_r1 + tncsho_r1 + tncsyo_r1 +static __maybe_unused struct dma_debug_item dbg_TNCSO_R1[] = { + {0x00000018, "tncso_r1 32(hex) 0000"}, + {0x00000118, "tncso_r1 state_checksum"}, + {0x00000218, "tncso_r1 line_pix_cnt_tmp"}, + {0x00000318, "tncso_r1 line_pix_cnt"}, + {0x00000418, "tncso_r1 important_status"}, + {0x00000518, "tncso_r1 cmd_data_cnt"}, + {0x00000618, "tncso_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000718, "tncso_r1 input_h_cnt"}, + {0x00000818, "tncso_r1 input_v_cnt"}, + {0x00000918, "tncso_r1 xfer_y_cnt"}, + + {0x01000058, "tncso_r1_smi / plane-0 - tncso_r1) / data-crc"}, + + {0x00000086, "tncso_r1_smi / smi_latency_mon output"}, + + {0x000018C0, + "tncso_r1_smi / plane-0 - tncso_r1_smi / plane-1 - tncso_r1 / maddr_max record"}, + {0x000018C1, + "tncso_r1_smi / plane-0 - tncso_r1_smi / plane-1 - tncso_r1 / maddr_min record"}, +}; + +static __maybe_unused struct dma_debug_item dbg_TNCSBO_R1[] = { + {0x00000019, "tncsbo_r1 32(hex) 0000"}, + {0x00000119, "tncsbo_r1 state_checksum"}, + {0x00000219, "tncsbo_r1 line_pix_cnt_tmp"}, + {0x00000319, "tncsbo_r1 line_pix_cnt"}, + {0x00000419, "tncsbo_r1 important_status"}, + {0x00000519, "tncsbo_r1 cmd_data_cnt"}, + {0x00000619, "tncsbo_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000719, "tncsbo_r1 input_h_cnt"}, + {0x00000819, "tncsbo_r1 input_v_cnt"}, + {0x00000919, "tncsbo_r1 xfer_y_cnt"}, + + {0x01000059, "tncso_r1_smi / plane-1 - tncsbo_r1 / data-crc"}, + + {0x00000086, "tncso_r1_smi / smi_latency_mon output"}, + + {0x000019C0, + "tncso_r1_smi / plane-1 - tncso_r1_smi / plane-0 - tncsbo_r1 / maddr_max"}, + {0x000019C1, + "tncso_r1_smi / plane-1 - tncso_r1_smi / plane-0 - tncsbo_r1 / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_TNCSHO_R1[] = { + {0x0000001A, "tncsho_r1 32(hex) 0000"}, + {0x0000011A, "tncsho_r1 state_checksum"}, + {0x0000021A, "tncsho_r1 line_pix_cnt_tmp"}, + {0x0000031A, "tncsho_r1 line_pix_cnt"}, + {0x0000041A, "tncsho_r1 important_status"}, + {0x0000051A, "tncsho_r1 cmd_data_cnt"}, + {0x0000061A, "tncsho_r1 cmd_cnt_for_bvalid_phase"}, + {0x0000071A, "tncsho_r1 input_h_cnt"}, + {0x0000081A, "tncsho_r1 input_v_cnt"}, + {0x0000091A, "tncsho_r1 xfer_y_cnt"}, + + {0x0100005A, "tncso_r1_smi / plane-2 - tncsho_r1 / data-crc"}, + + {0x00000086, "tncso_r1_smi / smi_latency_mon output"}, + + {0x00001AC0, + "tncso_r1_smi / plane-2 - tncso_r1_smi / plane-1 - tncsho_r1 / maddr_max"}, + {0x00001AC1, + "tncso_r1_smi / plane-2 - tncso_r1_smi / plane-1 - tncsho_r1 / maddr_max"}, +}; + +static __maybe_unused struct dma_debug_item dbg_TNCSYO_R1[] = { + {0x0000001B, "tncsyo_r1 32(hex) 0000"}, + {0x0000011B, "tncsyo_r1 state_checksum"}, + {0x0000021B, "tncsyo_r1 line_pix_cnt_tmp"}, + {0x0000031B, "tncsyo_r1 line_pix_cnt"}, + {0x0000041B, "tncsyo_r1 important_status"}, + {0x0000051B, "tncsyo_r1 cmd_data_cnt"}, + {0x0000061B, "tncsyo_r1 cmd_cnt_for_bvalid_phase"}, + {0x0000071B, "tncsyo_r1 input_h_cnt"}, + {0x0000081B, "tncsyo_r1 input_v_cnt"}, + {0x0000091B, "tncsyo_r1 xfer_y_cnt"}, + + {0x0100005B, "tncso_r1_smi / plane-3 - tncsyo_r1 / data-crc"}, + + {0x00000086, "tncso_r1_smi / smi_latency_mon output"}, + + {0x00001BC0, + "tncso_r1_smi / plane-3 - tncso_r1_smi / plane-2 - tncsyo_r1) / maddr_max"}, + {0x00001BC0, + "tncso_r1_smi / plane-3 - tncso_r1_smi / plane-2 - tncsyo_r1) / maddr_min"}, +}; + +static __maybe_unused struct dma_debug_item dbg_ulc_cmd_cnt[] = { + {0x00000511, "bpci_r1 cmd_data_cnt"}, + {0x00000512, "bpci_r2 cmd_data_cnt"}, + {0x00000513, "bpci_r3 cmd_data_cnt"}, + {0x00000516, "aai_r1 cmd_data_cnt"}, + {0x00000518, "rawi_r6 cmd_data_cnt"}, + {0x0000051F, "tsfso_r1 cmd_data_cnt"}, + {0x0000061F, "tsfso_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000520, "ltmso_r1 cmd_data_cnt"}, + {0x00000620, "ltmso_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000521, "tsfso_r2 cmd_data_cnt"}, + {0x00000621, "tsfso_r2 cmd_cnt_for_bvalid_phase"}, + {0x00000522, "flko_r1 cmd_data_cnt"}, + {0x00000622, "flko_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000523, "ufeo_r1 cmd_data_cnt"}, + {0x00000623, "ufeo_r1 cmd_cnt_for_bvalid_phase"}, + {0x00000528, "bino_r1 cmd_data_cnt"}, + {0x00000628, "bino_r1 cmd_cnt_for_bvalid_phase"}, +}; + +static __maybe_unused struct dma_debug_item dbg_ori_cmd_cnt[] = { + {0x000000A0, "rawi_r2_smi / plane-0 - rawi_r2 / { len-cnt, dle-cnt }"}, + {0x000000A1, "ufdi_r2_smi / plane-0 - ufdi_r2 / { len-cnt, dle-cnt }"}, + {0x000000A2, "rawi_r3_smi / plane-0 - rawi_r3 / { len-cnt, dle-cnt }"}, + {0x000000A3, "ufdi_r3_smi / plane-0 - ufdi_r3 / { len-cnt, dle-cnt }"}, + {0x000000A4, "rawi_r4_smi / plane-0 - rawi_r4 / { len-cnt, dle-cnt }"}, + {0x000000A5, "rawi_r5_smi / plane-0 - rawi_r5 / { len-cnt, dle-cnt }"}, + {0x000000A6, "cqi_r1_smi / plane-0 - cqi_r1 / { len-cnt, dle-cnt }"}, + {0x000000A7, "cqi_r1_smi / plane-1 - cqi_r3 / { len-cnt, dle-cnt }"}, + {0x000000A8, "cqi_r2_smi / plane-0 - cqi_r2 / { len-cnt, dle-cnt }"}, + {0x000000A9, "cqi_r2_smi / plane-1 - cqi_r4 / { len-cnt, dle-cnt }"}, + {0x000000AA, "lsci_r1_smi / plane-0 - lsci_r1 / { len-cnt, dle-cnt }"}, + {0x000000AB, "imgo_r1_smi / plane-0 - imgo_r1 / { len-cnt, dle-cnt }"}, + {0x000000AC, "imgo_r1_smi / plane-0 - imgo_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000AD, "fho_r1_smi / plane-0 - fho_r1 / { len-cnt, dle-cnt }"}, + {0x000000AE, "fho_r1_smi / plane-0 - fho_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000AF, "fho_r1_smi / plane-1 - aaho_r1 / { len-cnt, dle-cnt }"}, + {0x000000B0, "fho_r1_smi / plane-1 - aaho_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000B1, "fho_r1_smi / plane-2 - pdo_r1 / { len-cnt, dle-cnt }"}, + {0x000000B2, "fho_r1_smi / plane-2 - pdo_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000B3, "aao_r1_smi / plane-0 - aao_r1 / { len-cnt, dle-cnt }"}, + {0x000000B4, "aao_r1_smi / plane-0 - aao_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000B5, "aao_r1_smi / plane-1 - afo_r1 / { len-cnt, dle-cnt }"}, + {0x000000B6, "aao_r1_smi / plane-1 - afo_r1 / { load_com-cnt, bvalid-cnt }"}, + {0x000000B7, "ufdi_r5_smi / plane-0 - ufdi_r5 / { len-cnt, dle-cnt }"}, +}; + +#endif /*__MTK_CAM_RAW_DMADBG_H*/ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h new file mode 100644 index 000000000000..2eb54a2332ef --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-fmt.h @@ -0,0 +1,87 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTKCAM_FMT_H +#define __MTKCAM_FMT_H + +/* camsys supported format */ +enum mtkcam_ipi_fmt { + MTKCAM_IPI_IMG_FMT_UNKNOWN = -1, + MTKCAM_IPI_IMG_FMT_BAYER8 = 0, + MTKCAM_IPI_IMG_FMT_BAYER10 = 1, + MTKCAM_IPI_IMG_FMT_BAYER12 = 2, + MTKCAM_IPI_IMG_FMT_BAYER14 = 3, + MTKCAM_IPI_IMG_FMT_BAYER16 = 4, + MTKCAM_IPI_IMG_FMT_BAYER10_UNPACKED = 5, + MTKCAM_IPI_IMG_FMT_BAYER12_UNPACKED = 6, + MTKCAM_IPI_IMG_FMT_BAYER14_UNPACKED = 7, + MTKCAM_IPI_IMG_FMT_RGB565 = 8, + MTKCAM_IPI_IMG_FMT_RGB888 = 9, + MTKCAM_IPI_IMG_FMT_JPEG = 10, + MTKCAM_IPI_IMG_FMT_FG_BAYER8 = 11, + MTKCAM_IPI_IMG_FMT_FG_BAYER10 = 12, + MTKCAM_IPI_IMG_FMT_FG_BAYER12 = 13, + MTKCAM_IPI_IMG_FMT_FG_BAYER14 = 14, + MTKCAM_IPI_IMG_FMT_YUYV = 15, + MTKCAM_IPI_IMG_FMT_YVYU = 16, + MTKCAM_IPI_IMG_FMT_UYVY = 17, + MTKCAM_IPI_IMG_FMT_VYUY = 18, + MTKCAM_IPI_IMG_FMT_YUV_422_2P = 19, + MTKCAM_IPI_IMG_FMT_YVU_422_2P = 20, + MTKCAM_IPI_IMG_FMT_YUV_422_3P = 21, + MTKCAM_IPI_IMG_FMT_YVU_422_3P = 22, + MTKCAM_IPI_IMG_FMT_YUV_420_2P = 23, + MTKCAM_IPI_IMG_FMT_YVU_420_2P = 24, + MTKCAM_IPI_IMG_FMT_YUV_420_3P = 25, + MTKCAM_IPI_IMG_FMT_YVU_420_3P = 26, + MTKCAM_IPI_IMG_FMT_Y8 = 27, + MTKCAM_IPI_IMG_FMT_YUYV_Y210 = 28, + MTKCAM_IPI_IMG_FMT_YVYU_Y210 = 29, + MTKCAM_IPI_IMG_FMT_UYVY_Y210 = 30, + MTKCAM_IPI_IMG_FMT_VYUY_Y210 = 31, + MTKCAM_IPI_IMG_FMT_YUYV_Y210_PACKED = 32, + MTKCAM_IPI_IMG_FMT_YVYU_Y210_PACKED = 33, + MTKCAM_IPI_IMG_FMT_UYVY_Y210_PACKED = 34, + MTKCAM_IPI_IMG_FMT_VYUY_Y210_PACKED = 35, + MTKCAM_IPI_IMG_FMT_YUV_P210 = 36, + MTKCAM_IPI_IMG_FMT_YVU_P210 = 37, + MTKCAM_IPI_IMG_FMT_YUV_P010 = 38, + MTKCAM_IPI_IMG_FMT_YVU_P010 = 39, + MTKCAM_IPI_IMG_FMT_YUV_P210_PACKED = 40, + MTKCAM_IPI_IMG_FMT_YVU_P210_PACKED = 41, + MTKCAM_IPI_IMG_FMT_YUV_P010_PACKED = 42, + MTKCAM_IPI_IMG_FMT_YVU_P010_PACKED = 43, + MTKCAM_IPI_IMG_FMT_YUV_P212 = 44, + MTKCAM_IPI_IMG_FMT_YVU_P212 = 45, + MTKCAM_IPI_IMG_FMT_YUV_P012 = 46, + MTKCAM_IPI_IMG_FMT_YVU_P012 = 47, + MTKCAM_IPI_IMG_FMT_YUV_P212_PACKED = 48, + MTKCAM_IPI_IMG_FMT_YVU_P212_PACKED = 49, + MTKCAM_IPI_IMG_FMT_YUV_P012_PACKED = 50, + MTKCAM_IPI_IMG_FMT_YVU_P012_PACKED = 51, + MTKCAM_IPI_IMG_FMT_RGB_8B_3P = 52, + MTKCAM_IPI_IMG_FMT_RGB_10B_3P = 53, + MTKCAM_IPI_IMG_FMT_RGB_12B_3P = 54, + MTKCAM_IPI_IMG_FMT_RGB_10B_3P_PACKED = 55, + MTKCAM_IPI_IMG_FMT_RGB_12B_3P_PACKED = 56, + MTKCAM_IPI_IMG_FMT_FG_BAYER8_3P = 57, + MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P = 58, + MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P = 59, + MTKCAM_IPI_IMG_FMT_FG_BAYER10_3P_PACKED = 60, + MTKCAM_IPI_IMG_FMT_FG_BAYER12_3P_PACKED = 61, + MTKCAM_IPI_IMG_FMT_UFBC_NV12 = 62, + MTKCAM_IPI_IMG_FMT_UFBC_NV21 = 63, + MTKCAM_IPI_IMG_FMT_UFBC_YUV_P010 = 64, + MTKCAM_IPI_IMG_FMT_UFBC_YVU_P010 = 65, + MTKCAM_IPI_IMG_FMT_UFBC_YUV_P012 = 66, + MTKCAM_IPI_IMG_FMT_UFBC_YVU_P012 = 67, + MTKCAM_IPI_IMG_FMT_UFBC_BAYER8 = 68, + MTKCAM_IPI_IMG_FMT_UFBC_BAYER10 = 69, + MTKCAM_IPI_IMG_FMT_UFBC_BAYER12 = 70, + MTKCAM_IPI_IMG_FMT_UFBC_BAYER14 = 71, + MTKCAM_IPI_IMG_FMT_BAYER10_MIPI = 72 +}; + +#endif /* __MTKCAM_FMT_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h new file mode 100644 index 000000000000..f3401287ca6e --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ipi.h @@ -0,0 +1,233 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_IPI_H__ +#define __MTK_CAM_IPI_H__ + +#define MTK_CAM_IPI_VERSION_MAJOR (0) +#define MTK_CAM_IPI_VERSION_MINOR (1) + +#include +#include "mtk_cam-defs.h" + +#define MTK_CAM_MAX_RUNNING_JOBS (3) +#define CAM_MAX_PLANENUM (3) +#define CAM_MAX_SUBSAMPLE (32) +#define MTK_CAM_MAX_PROCESSING_BUFS (2) + +/* + * struct mtkcam_ipi_point - Point + * + * @x: x-coordinate of the point (zero-based). + * @y: y-coordinate of the point (zero-based). + */ +struct mtkcam_ipi_point { + u16 x; + u16 y; +} __packed; + +/* + * struct mtkcam_ipi_size - Size + * + * @w: width (in pixels). + * @h: height (in pixels). + */ +struct mtkcam_ipi_size { + u16 w; + u16 h; +} __packed; + +/* + * struct mtkcam_ipi_fract - fraction + * + * @numerator: numerator part of the fraction. + * @denominator: denominator part of the fraction. + */ +struct mtkcam_ipi_fract { + u8 numerator; + u8 denominator; +}; + +/* + * struct mtkcam_ipi_sw_buffer + * - Shared buffer between cam-device and co-processor. + * + * @iova: DMA address for CAM DMA device. isp7_1: u64. + * @scp_addr: SCP address for external co-processor unit. + * @size: buffer size. + */ +struct mtkcam_ipi_sw_buffer { + u64 iova; + u32 scp_addr; + u32 size; +} __packed; + +/* + * struct mtkcam_ipi_hw_buffer - DMA buffer for CAM DMA device. + * + * @iova: DMA address for CAM DMA device. isp7_1: u64. + * @size: buffer size. + */ +struct mtkcam_ipi_hw_buffer { + u64 iova; + u32 size; +} __packed; + +struct mtkcam_ipi_pix_fmt { + u32 format; + struct mtkcam_ipi_size s; + u16 stride[CAM_MAX_PLANENUM]; +} __packed; + +struct mtkcam_ipi_crop { + struct mtkcam_ipi_point p; + struct mtkcam_ipi_size s; +} __packed; + +struct mtkcam_ipi_uid { + u8 pipe_id; + u8 id; +} __packed; + +struct mtkcam_ipi_img_input { + struct mtkcam_ipi_uid uid; + struct mtkcam_ipi_pix_fmt fmt; + struct mtkcam_ipi_sw_buffer buf[CAM_MAX_PLANENUM]; +} __packed; + +struct mtkcam_ipi_img_output { + struct mtkcam_ipi_uid uid; + struct mtkcam_ipi_pix_fmt fmt; + struct mtkcam_ipi_sw_buffer buf[CAM_MAX_SUBSAMPLE][CAM_MAX_PLANENUM]; + struct mtkcam_ipi_crop crop; +} __packed; + +struct mtkcam_ipi_meta_input { + struct mtkcam_ipi_uid uid; + struct mtkcam_ipi_sw_buffer buf; +} __packed; + +struct mtkcam_ipi_meta_output { + struct mtkcam_ipi_uid uid; + struct mtkcam_ipi_sw_buffer buf; +} __packed; + +struct mtkcam_ipi_input_param { + u32 fmt; + u8 raw_pixel_id; + u8 data_pattern; + u8 pixel_mode; + u8 subsample; + struct mtkcam_ipi_crop in_crop; +} __packed; + +struct mtkcam_ipi_raw_frame_param { + u8 imgo_path_sel; /* mtkcam_ipi_raw_path_control */ + u8 hardware_scenario; + u32 bin_flag; + u8 exposure_num; + u8 previous_exposure_num; + struct mtkcam_ipi_fract frz_ratio; +} __packed; + +struct mtkcam_ipi_session_cookie { + u8 session_id; + u32 frame_no; +} __packed; + +struct mtkcam_ipi_session_param { + struct mtkcam_ipi_sw_buffer workbuf; + struct mtkcam_ipi_sw_buffer msg_buf; + struct mtkcam_ipi_sw_buffer raw_workbuf; + struct mtkcam_ipi_sw_buffer priv_workbuf; + struct mtkcam_ipi_sw_buffer session_buf; +} __packed; + +struct mtkcam_ipi_hw_mapping { + u8 pipe_id; /* ref. to mtkcam_pipe_subdev */ + u16 dev_mask; /* ref. to mtkcam_pipe_dev */ + u8 exp_order; +} __packed; + +/* Control flags of CAM_CMD_CONFIG */ +#define MTK_CAM_IPI_CONFIG_TYPE_INIT 0x0001 +#define MTK_CAM_IPI_CONFIG_TYPE_INPUT_CHANGE 0x0002 +#define MTK_CAM_IPI_CONFIG_TYPE_EXEC_TWICE 0x0004 +#define MTK_CAM_IPI_CONFIG_TYPE_SMVR_PREVIEW 0x0008 + +struct mtkcam_ipi_config_param { + u8 flags; + struct mtkcam_ipi_input_param input; + u8 n_maps; + /* maximum # of pipes per stream */ + struct mtkcam_ipi_hw_mapping maps[6]; + /* sub_ratio:8, valid number: 8 */ + u16 valid_numbers[MTKCAM_IPI_FBCX_LAST]; + u8 sw_feature; +} __packed; + +#define CAM_MAX_IMAGE_INPUT (5) +#define CAM_MAX_IMAGE_OUTPUT (15) +#define CAM_MAX_META_OUTPUT (4) +#define CAM_MAX_PIPE_USED (4) + +struct mtkcam_ipi_frame_param { + u32 cur_workbuf_offset; + u32 cur_workbuf_size; + + struct mtkcam_ipi_raw_frame_param raw_param; + struct mtkcam_ipi_img_input img_ins[CAM_MAX_IMAGE_INPUT]; + struct mtkcam_ipi_img_output img_outs[CAM_MAX_IMAGE_OUTPUT]; + struct mtkcam_ipi_meta_output meta_outputs[CAM_MAX_META_OUTPUT]; + struct mtkcam_ipi_meta_input meta_inputs[CAM_MAX_PIPE_USED]; +} __packed; + +struct mtkcam_ipi_frame_info { + u32 cur_msgbuf_offset; + u32 cur_msgbuf_size; +} __packed; + +struct mtkcam_ipi_frame_ack_result { + u32 cq_desc_offset; + u32 sub_cq_desc_offset; + u32 cq_desc_size; + u32 sub_cq_desc_size; +} __packed; + +struct mtkcam_ipi_ack_info { + u8 ack_cmd_id; + s32 ret; + struct mtkcam_ipi_frame_ack_result frame_result; +} __packed; + +/* + * The IPI command enumeration. + */ +enum mtkcam_ipi_cmds { + /* request for a new streaming: mtkcam_ipi_session_param */ + CAM_CMD_CREATE_SESSION, + /* config the stream: mtkcam_ipi_config_param */ + CAM_CMD_CONFIG, + /* per-frame: mtkcam_ipi_frame_param */ + CAM_CMD_FRAME, + /* release certain streaming: mtkcam_ipi_session_param */ + CAM_CMD_DESTROY_SESSION, + /* ack: mtkcam_ipi_ack_info */ + CAM_CMD_ACK, + CAM_CMD_RESERVED, +}; + +struct mtkcam_ipi_event { + struct mtkcam_ipi_session_cookie cookie; + u8 cmd_id; + union { + struct mtkcam_ipi_session_param session_data; + struct mtkcam_ipi_config_param config_data; + struct mtkcam_ipi_frame_info frame_data; + struct mtkcam_ipi_ack_info ack_data; + }; +} __packed; + +#endif /* __MTK_CAM_IPI_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h new file mode 100644 index 000000000000..656841f6ef57 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-meta-mt8188.h @@ -0,0 +1,2436 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_META_H__ +#define __MTK_CAM_META_H__ + +/* + * struct mtk_cam_uapi_meta_rect - rect info + * + * @left: The X coordinate of the left side of the rectangle + * @top: The Y coordinate of the left side of the rectangle + * @width: The width of the rectangle + * @height: The height of the rectangle + * + * rect containing the width and height fields. + * + */ +struct mtk_cam_uapi_meta_rect { + s32 left; + s32 top; + u32 width; + u32 height; +} __packed; + +/* + * struct mtk_cam_uapi_meta_size - size info + * + * @width: The width of the size + * @height: The height of the size + * + * size containing the width and height fields. + * + */ +struct mtk_cam_uapi_meta_size { + u32 width; + u32 height; +} __packed; + +/* + * A U T O E X P O S U R E + */ + +/* + * struct mtk_cam_uapi_ae_hist_cfg - histogram info for AE + * + * @hist_en: enable bit for current histogram, each histogram can + * be 0/1 (disabled/enabled) separately + * @hist_opt: color mode config for current histogram (0/1/2/3/4: + * R/G/B/RGB mix/Y) + * @hist_bin: bin mode config for current histogram (1/4: 256/1024 bin) + * @hist_y_hi: ROI Y range high bound for current histogram + * @hist_y_low: ROI Y range low bound for current histogram + * @hist_x_hi: ROI X range high bound for current histogram + * @hist_x_low: ROI X range low bound for current histogram + */ +struct mtk_cam_uapi_ae_hist_cfg { + s32 hist_en; + u8 hist_opt; + u8 hist_bin; + u16 hist_y_hi; + u16 hist_y_low; + u16 hist_x_hi; + u16 hist_x_low; + u16 rsv; +} __packed; + +#define MTK_CAM_UAPI_ROI_MAP_BLK_NUM (128 * 128) +/* + * struct mtk_cam_uapi_ae_param - parameters for AE configurtion + * + * @pixel_hist_win_cfg_le: window config for le histogram 0~5 + * separately, uAEHistBin shold be the same + * for these 6 histograms + * @pixel_hist_win_cfg_se: window config for se histogram 0~5 + * separately, uAEHistBin shold be the same + * for these 6 histograms + * @roi_hist_cfg_le : config for roi le histogram 0~3 + * color mode/enable + * @roi_hist_cfg_se : config for roi se histogram 0~3 + * color mode/enable + * @hdr_ratio: in HDR scenario, AE calculated hdr ratio + * (LE exp*iso/SE exp*iso*100) for current frame, + * default non-HDR scenario ratio=1000 + */ +struct mtk_cam_uapi_ae_param { + struct mtk_cam_uapi_ae_hist_cfg pixel_hist_win_cfg_le[6]; + struct mtk_cam_uapi_ae_hist_cfg pixel_hist_win_cfg_se[6]; + struct mtk_cam_uapi_ae_hist_cfg roi_hist_cfg_le[4]; + struct mtk_cam_uapi_ae_hist_cfg roi_hist_cfg_se[4]; + u8 aai_r1_enable; + u8 aai_roi_map[MTK_CAM_UAPI_ROI_MAP_BLK_NUM]; + u8 rsv; + u16 hdr_ratio; /* base 1 x= 1000 */ + u32 act_win_x_start; + u32 act_win_x_end; + u32 act_win_y_start; + u32 act_win_y_end; +} __packed; + +/* + * A U T O W H I T E B A L A N C E + */ + +/* Maximum blocks that MediaTek AWB supports */ +#define MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM (10) + +/* + * struct mtk_cam_uapi_awb_param - parameters for AWB configurtion + * + * @stat_en: AWB stat enable + * @windownum_x: Number of horizontal AWB windows + * @windownum_y: Number of vertical AWB windows + * @lowthreshold_r: Low threshold of R + * @lowthreshold_g: Low threshold of G + * @lowthreshold_b: Low threshold of B + * @highthreshold_r: High threshold of R + * @highthreshold_g: High threshold of G + * @highthreshold_b: High threshold of B + * @lightsrc_lowthreshold_r: Low threshold of R for light source estimation + * @lightsrc_lowthreshold_g: Low threshold of G for light source estimation + * @lightsrc_lowthreshold_b: Low threshold of B for light source estimation + * @lightsrc_highthreshold_r: High threshold of R for light source estimation + * @lightsrc_highthreshold_g: High threshold of G for light source estimation + * @lightsrc_highthreshold_b: High threshold of B for light source estimation + * @pregainlimit_r: Maximum limit clipping for R color + * @pregainlimit_g: Maximum limit clipping for G color + * @pregainlimit_b: Maximum limit clipping for B color + * @pregain_r: unit module compensation gain for R color + * @pregain_g: unit module compensation gain for G color + * @pregain_b: unit module compensation gain for B color + * @valid_datawidth: valid bits of statistic data + * @hdr_support_en: support HDR mode + * @stat_mode: Output format select <1>sum mode <0>average mode + * @error_ratio: Programmable error pixel count by AWB window size + * (base : 256) + * @awbxv_win_r: light area of right bound, the size is defined in + * MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM + * @awbxv_win_l: light area of left bound the size is defined in + * MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM + * @awbxv_win_d: light area of lower bound the size is defined in + * MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM + * @awbxv_win_u: light area of upper bound the size is defined in + * MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM + * @pregain2_r: white balance gain of R color + * @pregain2_g: white balance gain of G color + * @pregain2_b: white balance gain of B color + */ +struct mtk_cam_uapi_awb_param { + u32 stat_en; + u32 windownum_x; + u32 windownum_y; + u32 lowthreshold_r; + u32 lowthreshold_g; + u32 lowthreshold_b; + u32 highthreshold_r; + u32 highthreshold_g; + u32 highthreshold_b; + u32 lightsrc_lowthreshold_r; + u32 lightsrc_lowthreshold_g; + u32 lightsrc_lowthreshold_b; + u32 lightsrc_highthreshold_r; + u32 lightsrc_highthreshold_g; + u32 lightsrc_highthreshold_b; + u32 pregainlimit_r; + u32 pregainlimit_g; + u32 pregainlimit_b; + u32 pregain_r; + u32 pregain_g; + u32 pregain_b; + u32 valid_datawidth; + u32 hdr_support_en; + u32 stat_mode; + u32 format_shift; + u32 error_ratio; + u32 postgain_r; + u32 postgain_g; + u32 postgain_b; + u32 postgain2_hi_r; + u32 postgain2_hi_g; + u32 postgain2_hi_b; + u32 postgain2_med_r; + u32 postgain2_med_g; + u32 postgain2_med_b; + u32 postgain2_low_r; + u32 postgain2_low_g; + u32 postgain2_low_b; + s32 awbxv_win_r[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM]; + s32 awbxv_win_l[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM]; + s32 awbxv_win_d[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM]; + s32 awbxv_win_u[MTK_CAM_UAPI_AWB_MAX_LIGHT_AREA_NUM]; + u32 csc_ccm[9]; + u32 acc; + u32 med_region[4]; + u32 low_region[4]; + u32 pregain2_r; + u32 pregain2_g; + u32 pregain2_b; +} __packed; + +/* + * struct mtk_cam_uapi_dgn_param + * + * @gain: digital gain to increase image brightness, 1 x= 1024 + */ +struct mtk_cam_uapi_dgn_param { + u32 gain; +} __packed; + +/* + * struct mtk_cam_uapi_wb_param + * + * @gain_r: white balance gain of R channel + * @gain_g: white balance gain of G channel + * @gain_b: white balance gain of B channel + */ +struct mtk_cam_uapi_wb_param { + u32 gain_r; + u32 gain_g; + u32 gain_b; + u32 clip; +} __packed; + +/* + * A U T O F O C U S + */ + +/* + * struct mtk_cam_uapi_af_param - af statistic parameters + * @roi: AF roi rectangle (in pixel) for AF statistic covered, including + * x, y, width, height + * @th_sat_g: green channel pixel value saturation threshold (0~255) + * @th_h[3]: horizontal AF filters response threshold (0~50) for H0, H1, + * and H2 + * @th_v: vertical AF filter response threshold (0~50) + * @blk_pixel_xnum: horizontal number of pixel per block + * @blk_pixel_ynum: vertical number of pixel per block + * @fir_type: to select FIR filter by AF target type (0,1,2,3) + * @iir_type: to select IIR filter by AF target type (0,1,2,3) + * @data_gain[7]: gamma curve gain for AF source data + */ +struct mtk_cam_uapi_af_param { + struct mtk_cam_uapi_meta_rect roi; + u32 th_sat_g; + u32 th_h[3]; + u32 th_v; + u32 blk_pixel_xnum; + u32 blk_pixel_ynum; + u32 fir_type; + u32 iir_type; + u32 data_gain[7]; +} __packed; + +enum mtk_cam_uapi_flk_hdr_path_control { + MTKCAM_UAPI_FKLO_HDR_1ST_FRAME = 0, + MTKCAM_UAPI_FKLO_HDR_2ND_FRAME, + MTKCAM_UAPI_FKLO_HDR_3RD_FRAME, +} __packed; + +/* + * struct mtk_cam_uapi_flk_param + * + * @input_bit_sel: maximum pixel value of flicker statistic input + * @offset_y: initial position for flicker statistic calculation in y direction + * @crop_y: number of rows which will be cropped from bottom + * @sgg_val[8]: Simple Gain and Gamma for noise reduction, sgg_val[0] is + * gain and sgg_val[1] - sgg_val[7] are gamma table + * @noise_thr: the noise threshold of pixel value, pixel value lower than + * this value is considered as noise + * @saturate_thr: the saturation threshold of pixel value, pixel value + * higher than this value is considered as saturated + * @hdr_flk_src: flk source tap point selection + */ +struct mtk_cam_uapi_flk_param { + u32 input_bit_sel; + u32 offset_y; + u32 crop_y; + u32 sgg_val[8]; + u32 noise_thr; + u32 saturate_thr; + u32 hdr_flk_src; +} __packed; + +/* + * struct mtk_cam_uapi_tsf_param + * + * @horizontal_num: block number of horizontal direction + * @vertical_num: block number of vertical direction + */ +struct mtk_cam_uapi_tsf_param { + u32 horizontal_num; + u32 vertical_num; +} __packed; + +/* + * struct mtk_cam_uapi_pde_param + * + * @pdi_max_size: the max required memory size for pd table + * @pdo_max_size: the max required memory size for pd point output + * @pdo_x_size: the pd points out x size + * @pdo_y_size: the pd points out y size + * @pd_table_offset: the offset of pd table in the meta_cfg + */ +struct mtk_cam_uapi_pde_param { + u32 pdi_max_size; + u32 pdo_max_size; + u32 pdo_x_size; + u32 pdo_y_size; + u32 pd_table_offset; +} __packed; + +/* + * struct mtk_cam_uapi_meta_hw_buf - hardware buffer info + * + * @offset: offset from the start of the device memory associated to the + * v4l2 meta buffer + * @size: size of the buffer + * + * Some part of the meta buffers are read or written by statistic related + * hardware DMAs. The hardware buffers may have different size among + * difference pipeline. + */ +struct mtk_cam_uapi_meta_hw_buf { + u32 offset; + u32 size; +} __packed; + +/* + * struct mtk_cam_uapi_pdp_stats - statistics of pd + * + * @stats_src: source width and heitgh of the statistics. + * @stride: stride value used by + * @pdo_buf: The buffer for PD statistic hardware output. + * + * This is the PD statistic returned to user. + */ +struct mtk_cam_uapi_pdp_stats { + struct mtk_cam_uapi_meta_size stats_src; + u32 stride; + struct mtk_cam_uapi_meta_hw_buf pdo_buf; +} __packed; + +/* + * struct mtk_cam_uapi_cpi_stats - statistics of pd + * + * @stats_src: source width and heitgh of the statistics. + * @stride: stride value used by + * @pdo_buf: The buffer for PD statistic hardware output. + * + * This is the PD statistic returned to user. + */ +struct mtk_cam_uapi_cpi_stats { + struct mtk_cam_uapi_meta_size stats_src; + u32 stride; + struct mtk_cam_uapi_meta_hw_buf cpio_buf; +} __packed; + +/* + * struct mtk_cam_uapi_mqe_param + * + * @mqe_mode: + */ +struct mtk_cam_uapi_mqe_param { + u32 mqe_mode; +} __packed; + +/* + * struct mtk_cam_uapi_mobc_param + */ +struct mtk_cam_uapi_mobc_param { + u32 mobc_offst0; + u32 mobc_offst1; + u32 mobc_offst2; + u32 mobc_offst3; + u32 mobc_gain0; + u32 mobc_gain1; + u32 mobc_gain2; + u32 mobc_gain3; +} __packed; + +/* + * struct mtk_cam_uapi_lsc_param + */ +struct mtk_cam_uapi_lsc_param { + u32 lsc_ctl1; + u32 lsc_ctl2; + u32 lsc_ctl3; + u32 lsc_lblock; + u32 lsc_fblock; + u32 lsc_ratio; + u32 lsc_tpipe_ofst; + u32 lsc_tpipe_size; +} __packed; + +/* + * struct mtk_cam_uapi_sgg_param + */ +struct mtk_cam_uapi_sgg_param { + u32 sgg_pgn; + u32 sgg_gmrc_1; + u32 sgg_gmrc_2; +} __packed; + +/* + * struct mtk_cam_uapi_mbn_param + */ +struct mtk_cam_uapi_mbn_param { + u32 mbn_pow; + u32 mbn_dir; + u32 mbn_spar_hei; + u32 mbn_spar_pow; + u32 mbn_spar_fac; + u32 mbn_spar_con1; + u32 mbn_spar_con0; +} __packed; + +/* + * struct mtk_cam_uapi_cpi_param + */ +struct mtk_cam_uapi_cpi_param { + u32 cpi_th; + u32 cpi_pow; + u32 cpi_dir; + u32 cpi_spar_hei; + u32 cpi_spar_pow; + u32 cpi_spar_fac; + u32 cpi_spar_con1; + u32 cpi_spar_con0; +} __packed; + +/* + * struct mtk_cam_uapi_lsci_param + */ +struct mtk_cam_uapi_lsci_param { + u32 lsci_xsize; + u32 lsci_ysize; +} __packed; + +/* + * Common stuff for all statistics + */ + +#define MTK_CAM_UAPI_MAX_CORE_NUM (2) + +/* + * struct mtk_cam_uapi_pipeline_config - pipeline configuration + * + * @num_of_core: The number of isp cores + */ +struct mtk_cam_uapi_pipeline_config { + u32 num_of_core; + struct mtk_cam_uapi_meta_size core_data_size; + u32 core_pxl_mode_lg2; +} __packed; + +/* + * A U T O E X P O S U R E + */ + +/* please check the size of MTK_CAM_AE_HIST_MAX_BIN*/ +#define MTK_CAM_UAPI_AE_STATS_HIST_MAX_BIN (1024) + +/* + * A E A N D A W B + */ + +#define MTK_CAM_UAPI_AAO_BLK_SIZE (32) +#define MTK_CAM_UAPI_AAO_MAX_BLK_X (128) +#define MTK_CAM_UAPI_AAO_MAX_BLK_Y (128) +#define MTK_CAM_UAPI_AAO_MAX_BUF_SIZE (MTK_CAM_UAPI_AAO_BLK_SIZE \ + * MTK_CAM_UAPI_AAO_MAX_BLK_X \ + * MTK_CAM_UAPI_AAO_MAX_BLK_Y) + +#define MTK_CAM_UAPI_AHO_BLK_SIZE (3) +#define MTK_CAM_UAPI_AAHO_HIST_SIZE (6 * 1024 * MTK_CAM_UAPI_AHO_BLK_SIZE \ + + 14 * 256 * MTK_CAM_UAPI_AHO_BLK_SIZE) +#define MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE (MTK_CAM_UAPI_MAX_CORE_NUM * \ + MTK_CAM_UAPI_AAHO_HIST_SIZE) + +/* + * struct mtk_cam_uapi_ae_awb_stats - statistics of ae and awb + * + * @aao_buf: The buffer for AAHO statistic hardware output. + * The maximum size of the buffer is defined with + * MTK_CAM_UAPI_AAO_MAX_BUF_SIZE + * @aaho_buf: The buffer for AAHO statistic hardware output. + * The maximum size of the buffer is defined with + * MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE. + * + * This is the AE and AWB statistic returned to user. From our hardware's + * point of view, we can't separate the AE and AWB output result, so I use + * a struct to retutn them. + */ +struct mtk_cam_uapi_ae_awb_stats { + u32 awb_stat_en_status; + u32 awb_qbn_acc; + u32 ae_stat_en_status; + struct mtk_cam_uapi_meta_hw_buf aao_buf; + struct mtk_cam_uapi_meta_hw_buf aaho_buf; +} __packed; + +/* + * A U T O F O C U S + */ + +#define MTK_CAM_UAPI_AFO_BLK_SIZ (32) +#define MTK_CAM_UAPI_AFO_MAX_BLK_NUM (128 * 128) +#define MTK_CAM_UAPI_AFO_MAX_BUF_SIZE (MTK_CAM_UAPI_AFO_BLK_SIZ \ + * MTK_CAM_UAPI_AFO_MAX_BLK_NUM) + +/* + * struct mtk_cam_uapi_af_stats - af statistics + * + * @blk_num_x: block number of horizontal direction + * @blk_num_y: block number of vertical direction + * @afo_buf: the buffer for AAHO statistic hardware output. The maximum + * size of the buffer is defined with + * MTK_CAM_UAPI_AFO_MAX_BUF_SIZE. + */ +struct mtk_cam_uapi_af_stats { + u32 blk_num_x; + u32 blk_num_y; + struct mtk_cam_uapi_meta_hw_buf afo_buf; +} __packed; + +/* + * F L I C K E R + */ + +/* FLK's hardware output block size: 64 bits */ +#define MTK_CAM_UAPI_FLK_BLK_SIZE (8) + +/* Maximum block size (each line) of MediaTek flicker statistic */ +#define MTK_CAM_UAPI_FLK_MAX_STAT_BLK_NUM (6) + +/* Maximum height (in pixel) that driver can support */ +#define MTK_CAM_UAPI_FLK_MAX_FRAME_HEIGHT (9000) +#define MTK_CAM_UAPI_FLK_MAX_BUF_SIZE \ + (MTK_CAM_UAPI_FLK_BLK_SIZE * MTK_CAM_UAPI_FLK_MAX_STAT_BLK_NUM * \ + MTK_CAM_UAPI_FLK_MAX_FRAME_HEIGHT) + +/* + * struct mtk_cam_uapi_flk_stats + * + * @flko_buf: the buffer for FLKO statistic hardware output. The maximum + * size of the buffer is defined with MTK_CAM_UAPI_FLK_MAX_BUF_SIZE. + */ +struct mtk_cam_uapi_flk_stats { + struct mtk_cam_uapi_meta_hw_buf flko_buf; +} __packed; + +/* + * T S F + */ + +#define MTK_CAM_UAPI_TSFSO_SIZE (40 * 30 * 3 * 4) + +/* + * struct mtk_cam_uapi_tsf_stats - TSF statistic data + * + * @tsfo_buf: The buffer for tsf statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_TSFSO_SIZE. + * + * This output is for MediaTek proprietary algorithm + */ +struct mtk_cam_uapi_tsf_stats { + struct mtk_cam_uapi_meta_hw_buf tsfo_r1_buf; + struct mtk_cam_uapi_meta_hw_buf tsfo_r2_buf; +} __packed; + +/* + * struct mtk_cam_uapi_pd_stats - statistics of pd + * + * @stats_src: source width and heitgh of the statistics. + * @stride: stride value used by + * @pdo_buf: The buffer for PD statistic hardware output. + * + * This is the PD statistic returned to user. + */ +struct mtk_cam_uapi_pd_stats { + struct mtk_cam_uapi_meta_size stats_src; + u32 stride; + struct mtk_cam_uapi_meta_hw_buf pdo_buf; +} __packed; + +struct mtk_cam_uapi_timestamp { + u64 timestamp_buf[128]; +} __packed; + +/* + * T O N E + */ +#define MTK_CAM_UAPI_LTMSO_SIZE ((37 * 12 * 9 + 258) * 8) +#define MTK_CAM_UAPI_TNCSO_SIZE (680 * 510 * 2) +#define MTK_CAM_UAPI_TNCSHO_SIZE (1544) +#define MTK_CAM_UAPI_TNCSBO_SIZE (3888) +#define MTK_CAM_UAPI_TNCSYO_SIZE (68) + +/* + * struct mtk_cam_uapi_ltm_stats - Tone1 statistic data for + * MediaTek proprietary algorithm + * + * @ltmso_buf: The buffer for ltm statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_LTMSO_SIZE. + * @blk_num_x: block number of horizontal direction + * @blk_num_y: block number of vertical direction + */ +struct mtk_cam_uapi_ltm_stats { + struct mtk_cam_uapi_meta_hw_buf ltmso_buf; + u8 blk_num_x; + u8 blk_num_y; + u8 rsv[2]; +} __packed; + +/* + * struct mtk_cam_uapi_tnc_stats - Tone2 statistic data for + * MediaTek proprietary algorithm + * + * @tncso_buf: The buffer for tnc statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_TNCSO_SIZE (680*510*2) + */ +struct mtk_cam_uapi_tnc_stats { + struct mtk_cam_uapi_meta_hw_buf tncso_buf; +} __packed; + +/* + * struct mtk_cam_uapi_tnch_stats - Tone3 statistic data for MediaTek + * proprietary algorithm + * + * @tncsho_buf: The buffer for tnch statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_TNCSHO_SIZE (1544) + */ +struct mtk_cam_uapi_tnch_stats { + struct mtk_cam_uapi_meta_hw_buf tncsho_buf; +} __packed; + +/* + * struct mtk_cam_uapi_tncb_stats - Tone4 statistic data for MediaTek + * proprietary algorithm + * + * @tncsbo_buf: The buffer for tncb statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_TNCSBO_SIZE (3888) + */ +struct mtk_cam_uapi_tncb_stats { + struct mtk_cam_uapi_meta_hw_buf tncsbo_buf; +} __packed; + +/* + * struct mtk_cam_uapi_tncy_stats - Tone3 statistic data for MediaTek + * proprietary algorithm + * + * @tncsyo_buf: The buffer for tncy statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_TNCSYO_SIZE (68) + */ +struct mtk_cam_uapi_tncy_stats { + struct mtk_cam_uapi_meta_hw_buf tncsyo_buf; +} __packed; + +/* + * struct mtk_cam_uapi_act_stats - act statistic data for MediaTek + * proprietary algorithm + * + * @actso_buf: The buffer for tncy statistic hardware output. The buffer size + * is defined in MTK_CAM_UAPI_ACTSO_SIZE (768) + */ +#define MTK_CAM_UAPI_ACTSO_SIZE (768) +struct mtk_cam_uapi_act_stats { + struct mtk_cam_uapi_meta_hw_buf actso_buf; +} __packed; + +/* + * struct mtk_cam_uapi_awb_param_prot - AWB parameters + * + * @rot_cos: rotation matrix (cos part) + * @rot_sin: rotation matrix (sin part) + * + */ +struct mtk_cam_uapi_awb_param_prot { + s32 rot_cos; + s32 rot_sin; +} __packed; + +/* + * T U N I N G S + */ + +/* + * struct mtk_cam_uapi_bpc_param_prot - BPC parameters + * + */ +#define MTK_CAM_BPCI_TABLE_SIZE (32) +struct mtk_cam_uapi_bpc_param_prot { + u32 x_size; + u32 y_size; + u32 stride; + + u8 table[MTK_CAM_BPCI_TABLE_SIZE]; +} __packed; + +/* + * struct mtk_cam_uapi_drzs8t_param_prot + * + * @tbl_shift: adjust the computed table + * @tbl_min: use to limit the min table + */ +struct mtk_cam_uapi_drzs8t_param_prot { + u32 tbl_shift; + u32 tbl_min; +} __packed; + +/* + * struct mtk_cam_uapi_lsc_param_prot - LSC parameters + * + */ +#define MTK_CAM_LSCI_TABLE_SIZE (32768) +struct mtk_cam_uapi_lsc_param_prot { + u32 x_blk_num; + u32 y_blk_num; + u32 x_size; + u32 y_size; + u32 stride; + u8 table[MTK_CAM_LSCI_TABLE_SIZE]; +} __packed; + +/* * + * struct mtk_cam_uapi_slk_param_prot - slk tuning setting from userspace + * + */ +struct mtk_cam_uapi_slk_param_prot { + u32 center_x; + u32 center_y; + u32 radius_0; + u32 radius_1; + u32 radius_2; + u32 gain0; + u32 gain1; + u32 gain2; + u32 gain3; + u32 gain4; +} __packed; + +/* + * struct mtk_cam_uapi_wb_param_prot - WB parameters + * + */ +struct mtk_cam_uapi_wb_param_prot { + u32 debug_info[39]; +} __packed; + +/* + * struct mtk_cam_uapi_ltms_param_prot - LTMS parameters + * + * @ratio_x_start: adjusted start point of width related to original width + * @ratio_y_start: adjusted start point of height related to original height + * @ratio_x_end: adjusted end point of width related to original width + * @ratio_y_end: adjusted end point of height related to original height + */ +struct mtk_cam_uapi_ltms_param_prot { + u32 ltms_gamma_en; + u32 ratio_x_start; + u32 ratio_y_start; + u32 ratio_x_end; + u32 ratio_y_end; +} __packed; + +/* + * struct mtk_cam_uapi_yuvo_param_prot - YUVO parameters + * + * @drzh2n_fixed_down_ratio: down scale ratio + */ +struct mtk_cam_uapi_yuvo_param_prot { + u32 drzh2n_fixed_down_ratio; +} __packed; + +/* The following sw setting are generated by script */ +/* + * struct mtk_cam_uapi_ccm_param_prot - CCM parameters * + */ +struct mtk_cam_uapi_ccm_param_prot { + u32 ccm_acc; +} __packed; + +/* + * struct mtk_cam_uapi_drzh2n_param_prot - DRZH2N parameters * + */ +struct mtk_cam_uapi_drzh2n_param_prot { + u32 drzh2n_vert_tbl_sel; + u32 drzh2n_hori_tbl_sel; +} __packed; + +/* + * struct mtk_cam_uapi_drzs4n_param_prot - DRZS4N parameters * + */ +struct mtk_cam_uapi_drzs4n_param_prot { + u32 drzs4n_vert_tbl_sel; + u32 drzs4n_hori_tbl_sel; +} __packed; + +/* + * struct mtk_cam_uapi_tncs_param_prot - TNCS parameters * + */ +struct mtk_cam_uapi_tncs_param_prot { + u32 tncs_ggm_lnr; + u32 tncs_ggm_end_var; +} __packed; + +/* + * MediaTek camera bpc tuning setting + */ +struct mtk_cam_uapi_regmap_raw_bpc { + u32 bpc_func_con; + u32 rsv0[49]; +} __packed; + +/* + * MediaTek camera ccm tuning setting + */ +struct mtk_cam_uapi_regmap_raw_ccm { + u32 ccm_cnv_1; + u32 ccm_cnv_2; + u32 ccm_cnv_3; + u32 ccm_cnv_4; + u32 ccm_cnv_5; + u32 ccm_cnv_6; +} __packed; + +/* + * MediaTek camera dm tuning setting + */ +struct mtk_cam_uapi_regmap_raw_dm { + u32 rsv0; + u32 dm_intp_nat; + u32 rsv1[3]; + u32 dm_sl_ctl; + u32 rsv2; + u32 dm_nr_str; + u32 dm_nr_act; + u32 dm_hf_str; + u32 dm_hf_act1; + u32 dm_hf_act2; + u32 dm_clip; + u32 rsv3[8]; + u32 dm_ee; + u32 rsv4[4]; +} __packed; + +/* + * MediaTek camera g2c tuning setting + */ +struct mtk_cam_uapi_regmap_raw_g2c { + u32 g2c_conv_0a; + u32 g2c_conv_0b; + u32 g2c_conv_1a; + u32 g2c_conv_1b; + u32 g2c_conv_2a; + u32 g2c_conv_2b; +} __packed; + +#define MTK_CAM_UAPI_GGM_LUT (256) +/* + * MediaTek camera ggm tuning setting + */ +struct mtk_cam_uapi_regmap_raw_ggm { + u32 ggm_lut[MTK_CAM_UAPI_GGM_LUT]; + u32 ggm_ctrl; +} __packed; + +/* + * MediaTek camera lsc tuning setting + */ +struct mtk_cam_uapi_regmap_raw_lsc { + u32 lsc_ratio; +} __packed; + +#define MTK_CAM_UAPI_LTM_CURVE_SIZE_2 (1728) +#define MTK_CAM_UAPI_LTM_CLP_SIZE_2 (108) + +/* + * MediaTek camera ltm tuning setting + */ +struct mtk_cam_uapi_regmap_raw_ltm { + u32 ltm_ctrl; + u32 ltm_blk_num; + u32 ltm_max_div; + u32 ltm_clip; + u32 ltm_cfg; + u32 ltm_clip_th; + u32 ltm_gain_map; + u32 ltm_cvnode_grp0; + u32 ltm_cvnode_grp1; + u32 ltm_cvnode_grp2; + u32 ltm_cvnode_grp3; + u32 ltm_cvnode_grp4; + u32 ltm_cvnode_grp5; + u32 ltm_cvnode_grp6; + u32 ltm_cvnode_grp7; + u32 ltm_cvnode_grp8; + u32 ltm_cvnode_grp9; + u32 ltm_cvnode_grp10; + u32 ltm_cvnode_grp11; + u32 ltm_cvnode_grp12; + u32 ltm_cvnode_grp13; + u32 ltm_cvnode_grp14; + u32 ltm_cvnode_grp15; + u32 ltm_cvnode_grp16; + u32 ltm_out_str; + u32 ltm_act_win_x; + u32 ltm_act_win_y; + u32 ltmtc_curve[MTK_CAM_UAPI_LTM_CURVE_SIZE_2]; + u32 ltmtc_clp[MTK_CAM_UAPI_LTM_CLP_SIZE_2]; +} __packed; + +/* + * MediaTek camera ltms tuning setting + */ +struct mtk_cam_uapi_regmap_raw_ltms { + u32 ltms_max_div; + u32 ltms_blkhist_lb; + u32 ltms_blkhist_mb; + u32 ltms_blkhist_ub; + u32 ltms_blkhist_int; + u32 ltms_clip_th_cal; + u32 ltms_clip_th_lb; + u32 ltms_clip_th_hb; + u32 ltms_glbhist_int; +} __packed; + +/* + * MediaTek camera obc tuning setting + */ +struct mtk_cam_uapi_regmap_raw_obc { + u32 obc_dbs; + u32 obc_gray_bld_0; + u32 obc_gray_bld_1; + u32 obc_wbg_rb; + u32 obc_wbg_g; + u32 obc_wbig_rb; + u32 obc_wbig_g; + u32 obc_obg_rb; + u32 obc_obg_g; + u32 obc_offset_r; + u32 obc_offset_gr; + u32 obc_offset_gb; + u32 obc_offset_b; + u32 rsv1[2]; +} __packed; + +/* + * MediaTek camera tsfs tuning setting + */ +struct mtk_cam_uapi_regmap_raw_tsfs { + u32 tsfs_dgain; +} __packed; + +/* + * Usage example: To print value of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val" + * > printf("%x", GET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN)); + */ +#define GET_MTK_CAM(val, field) \ + (((val) & field##_MASK) >> field##_SHIFT) +/* + * Usage example: To set "val_of_bpc_lut_bit_extend_en" to bits + * of "MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN" in "val" + * > val = SET_MTK_CAM(val, MTK_CAM_BPC_BPC_FUNC_CON_BPC_BPC_LUT_BIT_EXTEND_EN, + * val_of_bpc_lut_bit_extend_en); + */ +#define SET_MTK_CAM(val, field, set_val) \ + (((val) & ~field##_MASK) | (((set_val) << field##_SHIFT) & field##_MASK)) + +/* + * Bit Feild of BPC_FUNC_CON: BPC_EN + * MTK_CAM_BPC_FUNC_CON_BPC_EN: [31, 31] + * Enable/disable for BPC Correction + * 1'd1: enable the function + * 1'd0: disable the function + */ +#define MTK_CAM_BPC_FUNC_CON_BPC_EN_MASK 0x80000000 +#define MTK_CAM_BPC_FUNC_CON_BPC_EN_SHIFT 31 + +/* + * Bit Feild of BPC_FUNC_CON: BPC_CT_EN + * MTK_CAM_BPC_FUNC_CON_BPC_CT_EN: [30, 30] + * Enable/disable for Cross-Talk compensation + * 1'd1: enable + * 1'd0: disable + */ +#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_MASK 0x40000000 +#define MTK_CAM_BPC_FUNC_CON_BPC_CT_EN_SHIFT 30 + +/* + * Bit Feild of BPC_FUNC_CON: BPC_PDC_EN + * MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN: [29, 29] + * Enable/disable for PDC correction + * 1'd1: enable + * 1'd0: disable + */ +#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_MASK 0x20000000 +#define MTK_CAM_BPC_FUNC_CON_BPC_PDC_EN_SHIFT 29 + +/* + * Bit Feild of BPC_FUNC_CON: BPC_LUT_EN + * MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN: [28, 28] + * Enable table lookup + * 1'd1: enable BPC with default table mode + * 1'd0: disable BPC with default table mode + */ +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_MASK 0x10000000 +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_EN_SHIFT 28 + +/* + * Bit Feild of BPC_FUNC_CON: BPC_LUT_BIT_EXTEND_EN + * MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN: [0, 0] + * Enable table 24 bits mode + * 1'd1: Table format to be 24 bits + * 1'd0: @ the original format, tbale to be 16 bits mode + */ +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_MASK 0x00000001 +#define MTK_CAM_BPC_FUNC_CON_BPC_LUT_BIT_EXTEND_EN_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_1: CCM_CNV_01 + * MTK_CAM_CCM_CNV_1_CCM_CNV_01: [16, 28] + * matrix 0,1 coefficient + */ +#define MTK_CAM_CCM_CNV_1_CCM_CNV_01_MASK 0x1fff0000 +#define MTK_CAM_CCM_CNV_1_CCM_CNV_01_SHIFT 16 + +/* + * Bit Feild of CCM_CNV_1: CCM_CNV_00 + * MTK_CAM_CCM_CNV_1_CCM_CNV_00: [0, 12] + * matrix 0,0 coefficient + */ +#define MTK_CAM_CCM_CNV_1_CCM_CNV_00_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_1_CCM_CNV_00_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_2: CCM_CNV_02 + * MTK_CAM_CCM_CNV_2_CCM_CNV_02: [0, 12] + * matrix 0,2 coefficient + */ +#define MTK_CAM_CCM_CNV_2_CCM_CNV_02_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_2_CCM_CNV_02_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_3: CCM_CNV_11 + * MTK_CAM_CCM_CNV_3_CCM_CNV_11: [16, 28] + * matrix 1,1 coefficient + */ +#define MTK_CAM_CCM_CNV_3_CCM_CNV_11_MASK 0x1fff0000 +#define MTK_CAM_CCM_CNV_3_CCM_CNV_11_SHIFT 16 + +/* + * Bit Feild of CCM_CNV_3: CCM_CNV_10 + * MTK_CAM_CCM_CNV_3_CCM_CNV_10: [0, 12] + * matrix 1,0 coefficient + */ +#define MTK_CAM_CCM_CNV_3_CCM_CNV_10_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_3_CCM_CNV_10_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_4: CCM_CNV_12 + * MTK_CAM_CCM_CNV_4_CCM_CNV_12: [0, 12] + * matrix 1,2 coefficient + */ +#define MTK_CAM_CCM_CNV_4_CCM_CNV_12_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_4_CCM_CNV_12_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_5: CCM_CNV_21 + * MTK_CAM_CCM_CNV_5_CCM_CNV_21: [16, 28] + * matrix 2,1 coefficient + */ +#define MTK_CAM_CCM_CNV_5_CCM_CNV_21_MASK 0x1fff0000 +#define MTK_CAM_CCM_CNV_5_CCM_CNV_21_SHIFT 16 + +/* + * Bit Feild of CCM_CNV_5: CCM_CNV_20 + * MTK_CAM_CCM_CNV_5_CCM_CNV_20: [0, 12] + * matrix 2,0 coefficient + */ +#define MTK_CAM_CCM_CNV_5_CCM_CNV_20_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_5_CCM_CNV_20_SHIFT 0 + +/* + * Bit Feild of CCM_CNV_6: CCM_CNV_22 + * MTK_CAM_CCM_CNV_6_CCM_CNV_22: [0, 12] + * matrix 2,2 coefficient + */ +#define MTK_CAM_CCM_CNV_6_CCM_CNV_22_MASK 0x00001fff +#define MTK_CAM_CCM_CNV_6_CCM_CNV_22_SHIFT 0 + +/* + * Bit Feild of DM_INTP_NAT: DM_L0_OFST + * MTK_CAM_DM_INTP_NAT_DM_L0_OFST: [12, 19] + * luma blending LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_INTP_NAT_DM_L0_OFST_MASK 0x000ff000 +#define MTK_CAM_DM_INTP_NAT_DM_L0_OFST_SHIFT 12 + +/* + * Bit Feild of DM_SL_CTL: DM_SL_Y1 + * MTK_CAM_DM_SL_CTL_DM_SL_Y1: [14, 21] + * shading link modulation LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_SL_CTL_DM_SL_Y1_MASK 0x003fc000 +#define MTK_CAM_DM_SL_CTL_DM_SL_Y1_SHIFT 14 + +/* + * Bit Feild of DM_SL_CTL: DM_SL_Y2 + * MTK_CAM_DM_SL_CTL_DM_SL_Y2: [6, 13] + * shading link modulation LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_SL_CTL_DM_SL_Y2_MASK 0x00003fc0 +#define MTK_CAM_DM_SL_CTL_DM_SL_Y2_SHIFT 6 + +/* + * Bit Feild of DM_SL_CTL: DM_SL_EN + * MTK_CAM_DM_SL_CTL_DM_SL_EN: [0, 0] + * shading link enable + * 0: disable SL + * 1: enable SL + */ +#define MTK_CAM_DM_SL_CTL_DM_SL_EN_MASK 0x00000001 +#define MTK_CAM_DM_SL_CTL_DM_SL_EN_SHIFT 0 + +/* + * Bit Feild of DM_NR_STR: DM_N0_STR + * MTK_CAM_DM_NR_STR_DM_N0_STR: [10, 14] + * noise reduction strength + * 0 ~ 16 + */ +#define MTK_CAM_DM_NR_STR_DM_N0_STR_MASK 0x00007c00 +#define MTK_CAM_DM_NR_STR_DM_N0_STR_SHIFT 10 + +/* + * Bit Feild of DM_NR_ACT: DM_N0_OFST + * MTK_CAM_DM_NR_ACT_DM_N0_OFST: [24, 31] + * noise reduction activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_NR_ACT_DM_N0_OFST_MASK 0xff000000 +#define MTK_CAM_DM_NR_ACT_DM_N0_OFST_SHIFT 24 + +/* + * Bit Feild of DM_HF_STR: DM_HA_STR + * MTK_CAM_DM_HF_STR_DM_HA_STR: [27, 31] + * overall high frequency strength + * 0 ~ 31 + */ +#define MTK_CAM_DM_HF_STR_DM_HA_STR_MASK 0xf8000000 +#define MTK_CAM_DM_HF_STR_DM_HA_STR_SHIFT 27 + +/* + * Bit Feild of DM_HF_STR: DM_H1_GN + * MTK_CAM_DM_HF_STR_DM_H1_GN: [22, 26] + * individual high frequency strength + * 0 ~ 31 + */ +#define MTK_CAM_DM_HF_STR_DM_H1_GN_MASK 0x07c00000 +#define MTK_CAM_DM_HF_STR_DM_H1_GN_SHIFT 22 + +/* + * Bit Feild of DM_HF_STR: DM_H2_GN + * MTK_CAM_DM_HF_STR_DM_H2_GN: [17, 21] + * individual high frequency strength + * 0 ~ 31 + */ +#define MTK_CAM_DM_HF_STR_DM_H2_GN_MASK 0x003e0000 +#define MTK_CAM_DM_HF_STR_DM_H2_GN_SHIFT 17 + +/* + * Bit Feild of DM_HF_STR: DM_H3_GN + * MTK_CAM_DM_HF_STR_DM_H3_GN: [12, 16] + * individual high frequency strength + * 0 ~ 31 + */ +#define MTK_CAM_DM_HF_STR_DM_H3_GN_MASK 0x0001f000 +#define MTK_CAM_DM_HF_STR_DM_H3_GN_SHIFT 12 + +/* + * Bit Feild of DM_HF_ACT1: DM_H1_LWB + * MTK_CAM_DM_HF_ACT1_DM_H1_LWB: [24, 31] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT1_DM_H1_LWB_MASK 0xff000000 +#define MTK_CAM_DM_HF_ACT1_DM_H1_LWB_SHIFT 24 + +/* + * Bit Feild of DM_HF_ACT1: DM_H1_UPB + * MTK_CAM_DM_HF_ACT1_DM_H1_UPB: [16, 23] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT1_DM_H1_UPB_MASK 0x00ff0000 +#define MTK_CAM_DM_HF_ACT1_DM_H1_UPB_SHIFT 16 + +/* + * Bit Feild of DM_HF_ACT1: DM_H2_LWB + * MTK_CAM_DM_HF_ACT1_DM_H2_LWB: [8, 15] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT1_DM_H2_LWB_MASK 0x0000ff00 +#define MTK_CAM_DM_HF_ACT1_DM_H2_LWB_SHIFT 8 + +/* + * Bit Feild of DM_HF_ACT1: DM_H2_UPB + * MTK_CAM_DM_HF_ACT1_DM_H2_UPB: [0, 7] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT1_DM_H2_UPB_MASK 0x000000ff +#define MTK_CAM_DM_HF_ACT1_DM_H2_UPB_SHIFT 0 + +/* + * Bit Feild of DM_HF_ACT2: DM_H3_LWB + * MTK_CAM_DM_HF_ACT2_DM_H3_LWB: [16, 23] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT2_DM_H3_LWB_MASK 0x00ff0000 +#define MTK_CAM_DM_HF_ACT2_DM_H3_LWB_SHIFT 16 + +/* + * Bit Feild of DM_HF_ACT2: DM_H3_UPB + * MTK_CAM_DM_HF_ACT2_DM_H3_UPB: [8, 15] + * high frequency activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_HF_ACT2_DM_H3_UPB_MASK 0x0000ff00 +#define MTK_CAM_DM_HF_ACT2_DM_H3_UPB_SHIFT 8 + +/* + * Bit Feild of DM_CLIP: DM_OV_TH + * MTK_CAM_DM_CLIP_DM_OV_TH: [16, 23] + * over/undershoot brightness LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_CLIP_DM_OV_TH_MASK 0x00ff0000 +#define MTK_CAM_DM_CLIP_DM_OV_TH_SHIFT 16 + +/* + * Bit Feild of DM_CLIP: DM_UN_TH + * MTK_CAM_DM_CLIP_DM_UN_TH: [8, 15] + * over/undershoot brightness LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_CLIP_DM_UN_TH_MASK 0x0000ff00 +#define MTK_CAM_DM_CLIP_DM_UN_TH_SHIFT 8 + +/* + * Bit Feild of DM_CLIP: DM_CLIP_TH + * MTK_CAM_DM_CLIP_DM_CLIP_TH: [0, 7] + * over/undershoot activity LUT + * 0 ~ 255 + */ +#define MTK_CAM_DM_CLIP_DM_CLIP_TH_MASK 0x000000ff +#define MTK_CAM_DM_CLIP_DM_CLIP_TH_SHIFT 0 + +/* + * Bit Feild of DM_EE: DM_HNEG_GN + * MTK_CAM_DM_EE_DM_HNEG_GN: [5, 9] + * edge enhancement negative gain + * 0~16 + */ +#define MTK_CAM_DM_EE_DM_HNEG_GN_MASK 0x000003e0 +#define MTK_CAM_DM_EE_DM_HNEG_GN_SHIFT 5 + +/* + * Bit Feild of DM_EE: DM_HPOS_GN + * MTK_CAM_DM_EE_DM_HPOS_GN: [0, 4] + * edge enhancement positive gain + * 0~16 + */ +#define MTK_CAM_DM_EE_DM_HPOS_GN_MASK 0x0000001f +#define MTK_CAM_DM_EE_DM_HPOS_GN_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_0A: G2C_CNV_01 + * MTK_CAM_G2C_CONV_0A_G2C_CNV_01: [16, 26] + * DIP RGB 2 YUV Matrix 0,1 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_0A_G2C_CNV_01_MASK 0x07ff0000 +#define MTK_CAM_G2C_CONV_0A_G2C_CNV_01_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_0A: G2C_CNV_00 + * MTK_CAM_G2C_CONV_0A_G2C_CNV_00: [0, 10] + * DIP RGB 2 YUV Matrix 0,0 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_0A_G2C_CNV_00_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_0A_G2C_CNV_00_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_0B: G2C_Y_OFST + * MTK_CAM_G2C_CONV_0B_G2C_Y_OFST: [16, 30] + * Y offset. Q1.10.0 (mobile) or Q1.14.0 (non-mobile) + */ +#define MTK_CAM_G2C_CONV_0B_G2C_Y_OFST_MASK 0x7fff0000 +#define MTK_CAM_G2C_CONV_0B_G2C_Y_OFST_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_0B: G2C_CNV_02 + * MTK_CAM_G2C_CONV_0B_G2C_CNV_02: [0, 10] + * DIP RGB 2 YUV Matrix 0,2 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_0B_G2C_CNV_02_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_0B_G2C_CNV_02_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_1A: G2C_CNV_11 + * MTK_CAM_G2C_CONV_1A_G2C_CNV_11: [16, 26] + * DIP RGB 2 YUV Matrix 1,1 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_1A_G2C_CNV_11_MASK 0x07ff0000 +#define MTK_CAM_G2C_CONV_1A_G2C_CNV_11_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_1A: G2C_CNV_10 + * MTK_CAM_G2C_CONV_1A_G2C_CNV_10: [0, 10] + * DIP RGB 2 YUV Matrix 1,0 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_1A_G2C_CNV_10_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_1A_G2C_CNV_10_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_1B: G2C_U_OFST + * MTK_CAM_G2C_CONV_1B_G2C_U_OFST: [16, 29] + * U offset. Q1.9.0 (mobile) or Q1.13.0 (non-mobile) + */ +#define MTK_CAM_G2C_CONV_1B_G2C_U_OFST_MASK 0x3fff0000 +#define MTK_CAM_G2C_CONV_1B_G2C_U_OFST_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_1B: G2C_CNV_12 + * MTK_CAM_G2C_CONV_1B_G2C_CNV_12: [0, 10] + * DIP RGB 2 YUV Matrix 1,2 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_1B_G2C_CNV_12_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_1B_G2C_CNV_12_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_2A: G2C_CNV_21 + * MTK_CAM_G2C_CONV_2A_G2C_CNV_21: [16, 26] + * DIP RGB 2 YUV Matrix 2,1 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_2A_G2C_CNV_21_MASK 0x07ff0000 +#define MTK_CAM_G2C_CONV_2A_G2C_CNV_21_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_2A: G2C_CNV_20 + * MTK_CAM_G2C_CONV_2A_G2C_CNV_20: [0, 10] + * DIP RGB 2 YUV Matrix 2,0 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_2A_G2C_CNV_20_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_2A_G2C_CNV_20_SHIFT 0 + +/* + * Bit Feild of G2C_CONV_2B: G2C_V_OFST + * MTK_CAM_G2C_CONV_2B_G2C_V_OFST: [16, 29] + * V offset. Q1.9.0 (mobile) or Q1.13.0 (non-mobile) + */ +#define MTK_CAM_G2C_CONV_2B_G2C_V_OFST_MASK 0x3fff0000 +#define MTK_CAM_G2C_CONV_2B_G2C_V_OFST_SHIFT 16 + +/* + * Bit Feild of G2C_CONV_2B: G2C_CNV_22 + * MTK_CAM_G2C_CONV_2B_G2C_CNV_22: [0, 10] + * DIP RGB 2 YUV Matrix 2,2 coefficient in Q1.1.9 + */ +#define MTK_CAM_G2C_CONV_2B_G2C_CNV_22_MASK 0x000007ff +#define MTK_CAM_G2C_CONV_2B_G2C_CNV_22_SHIFT 0 + +/* + * Bit Feild of GGM_LUT: GGM_LUT + * MTK_CAM_GGM_LUT_GGM_LUT: [0, 9] + * Gamma table entry + * Do NOT read/write this control register when GGM is + * enabled (ISP pipeline processing is on-going) or output + * data of GGM will be gated + */ +#define MTK_CAM_GGM_LUT_GGM_LUT_MASK 0x000003ff +#define MTK_CAM_GGM_LUT_GGM_LUT_SHIFT 0 + +/* + * Bit Feild of GGM_CTRL: GGM_LNR + * MTK_CAM_GGM_CTRL_GGM_LNR: [0, 0] + * Enable linear output + */ +#define MTK_CAM_GGM_CTRL_GGM_LNR_MASK 0x00000001 +#define MTK_CAM_GGM_CTRL_GGM_LNR_SHIFT 0 + +/* + * Bit Feild of GGM_CTRL: GGM_END_VAR + * MTK_CAM_GGM_CTRL_GGM_END_VAR: [1, 10] + * end point value + */ +#define MTK_CAM_GGM_CTRL_GGM_END_VAR_MASK 0x000007fe +#define MTK_CAM_GGM_CTRL_GGM_END_VAR_SHIFT 1 + +/* + * Bit Feild of GGM_CTRL: GGM_RMP_VAR + * MTK_CAM_GGM_CTRL_GGM_RMP_VAR: [16, 20] + * 5-bit: can support mapping to 14-bit output, (RMP_VAR+out limiter)/1024 + */ +#define MTK_CAM_GGM_CTRL_GGM_RMP_VAR_MASK 0x001f0000 +#define MTK_CAM_GGM_CTRL_GGM_RMP_VAR_SHIFT 16 + +/* + * Bit Feild of LSC_RATIO: LSC_RA00 + * MTK_CAM_LSC_RATIO_LSC_RA00: [0, 5] + * Shading ratio + */ +#define MTK_CAM_LSC_RATIO_LSC_RA00_MASK 0x0000003f +#define MTK_CAM_LSC_RATIO_LSC_RA00_SHIFT 0 + +/* + * Bit Feild of LTMS_MAX_DIV: LTMS_CLIP_TH_ALPHA_BASE + * MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE: [0, 9] + * Divider for Maxvalue + */ +#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_MASK 0x000003ff +#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT 0 + +/* + * Bit Feild of LTMS_MAX_DIV: LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT + * MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT: [16, 20] + * Divider for Maxvalue + */ +#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT_MASK 0x001f0000 +#define MTK_CAM_LTMS_MAX_DIV_LTMS_CLIP_TH_ALPHA_BASE_SHIFT_BIT_SHIFT 16 + +/* + * Bit Feild of LTMS_BLKHIST_LB: LTMS_BLKHIST_LB + * MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB: [0, 17] + * block histogram low bound, + * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB + */ +#define MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB_MASK 0x0003ffff +#define MTK_CAM_LTMS_BLKHIST_LB_LTMS_BLKHIST_LB_SHIFT 0 + +/* + * Bit Feild of LTMS_BLKHIST_MB: LTMS_BLKHIST_MB + * MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB: [0, 17] + * block histogram middle bound, + * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB + */ +#define MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB_MASK 0x0003ffff +#define MTK_CAM_LTMS_BLKHIST_MB_LTMS_BLKHIST_MB_SHIFT 0 + +/* + * Bit Feild of LTMS_BLKHIST_UB: LTMS_BLKHIST_UB + * MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB: [0, 17] + * block histogram up bound, + * BLKHIST_UB>=BLKHIST_MB>=BLKHIST_LB + */ +#define MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB_MASK 0x0003ffff +#define MTK_CAM_LTMS_BLKHIST_UB_LTMS_BLKHIST_UB_SHIFT 0 + +/* + * Bit Feild of LTMS_BLKHIST_INT: LTMS_BLKHIST_INT1 + * MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT1: [0, 13] + * block histogram interval 1 + */ +#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT1_MASK 0x00003fff +#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT1_SHIFT 0 + +/* + * Bit Feild of LTMS_BLKHIST_INT: LTMS_BLKHIST_INT2 + * MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2: [16, 29] + * block histogram interval 2 + */ +#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2_MASK 0x3fff0000 +#define MTK_CAM_LTMS_BLKHIST_INT_LTMS_BLKHIST_INT2_SHIFT 16 + +/* + * Bit Feild of LTMS_CLIP_TH_CAL: LTMS_CLP_HLTHD + * MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD: [0, 10] + * control percentage of histogram to calculate clip_th, 10-bits precision. + */ +#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD_MASK 0x000007ff +#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_HLTHD_SHIFT 0 + +/* + * Bit Feild of LTMS_CLIP_TH_CAL: LTMS_CLP_STARTBIN + * MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN: [16, 23] + * start bin of histogram. + */ +#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN_MASK 0x00ff0000 +#define MTK_CAM_LTMS_CLIP_TH_CAL_LTMS_CLP_STARTBIN_SHIFT 16 + +/* + * Bit Feild of LTMS_CLIP_TH_LB: LTMS_CLP_LB + * MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB: [0, 21] + * Low bound of clip threshold output. + */ +#define MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB_MASK 0x003fffff +#define MTK_CAM_LTMS_CLIP_TH_LB_LTMS_CLP_LB_SHIFT 0 + +/* + * Bit Feild of LTMS_CLIP_TH_HB: LTMS_CLP_HB + * MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB: [0, 21] + * High bound of clip threshold output. + */ +#define MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB_MASK 0x003fffff +#define MTK_CAM_LTMS_CLIP_TH_HB_LTMS_CLP_HB_SHIFT 0 + +/* + * Bit Feild of LTMS_GLBHIST_INT: LTMS_GLBHIST_INT + * MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT: [0, 14] + * Interval of global histogram + */ +#define MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT_MASK 0x00007fff +#define MTK_CAM_LTMS_GLBHIST_INT_LTMS_GLBHIST_INT_SHIFT 0 + +/* + * Bit Feild of LTMTC_CURVE: LTMTC_TONECURVE_LUT_L + * MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L: [0, 13] + * SRAM_PING_PONG + * [u8.6-bits]x12x9 + */ +#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L_MASK 0x00003fff +#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_L_SHIFT 0 + +/* + * Bit Feild of LTMTC_CURVE: LTMTC_TONECURVE_LUT_H + * MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H: [16, 29] + * SRAM_PING_PONG + * [u8.6-bits]x12x9 + */ +#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H_MASK 0x3fff0000 +#define MTK_CAM_LTMTC_CURVE_LTMTC_TONECURVE_LUT_H_SHIFT 16 + +/* + * Bit Feild of LTMTC_CLP: LTMTC_TONECURVE_CLP + * MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP: [0, 23] + * LTM block CT + */ +#define MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP_MASK 0x00ffffff +#define MTK_CAM_LTMTC_CLP_LTMTC_TONECURVE_CLP_SHIFT 0 + +/* + * Bit Feild of LTM_CTRL: LTM_GAMMA_EN + * MTK_CAM_LTM_CTRL_LTM_GAMMA_EN: [4, 4] + * Enable gamma domain + */ +#define MTK_CAM_LTM_CTRL_LTM_GAMMA_EN_MASK 0x00000010 +#define MTK_CAM_LTM_CTRL_LTM_GAMMA_EN_SHIFT 4 + +/* + * Bit Feild of LTM_CTRL: LTM_CURVE_CP_MODE + * MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE: [5, 5] + * Mode of curve control point, [0]: 33 fixed cp, [1]: 16 XY cp + */ +#define MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE_MASK 0x00000020 +#define MTK_CAM_LTM_CTRL_LTM_CURVE_CP_MODE_SHIFT 5 + +/* + * Bit Feild of LTM_BLK_NUM: LTM_BLK_X_NUM + * MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM: [0, 4] + * block X number supports 2~12 + */ +#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM_MASK 0x0000001f +#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_X_NUM_SHIFT 0 + +/* + * Bit Feild of LTM_BLK_NUM: LTM_BLK_Y_NUM + * MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM: [8, 12] + * block Y number supports 2~9 + */ +#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM_MASK 0x00001f00 +#define MTK_CAM_LTM_BLK_NUM_LTM_BLK_Y_NUM_SHIFT 8 + +/* + * Bit Feild of LTM_MAX_DIV: LTM_CLIP_TH_ALPHA_BASE + * MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE: [0, 9] + * Divider for Maxvalue + */ +#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_MASK 0x000003ff +#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT 0 + +/* + * Bit Feild of LTM_MAX_DIV: LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT + * MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT: [16, 20] + * Divider for Maxvalue + */ +#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT_MASK 0x001f0000 +#define MTK_CAM_LTM_MAX_DIV_LTM_CLIP_TH_ALPHA_BASE_SHIFT_BIT_SHIFT 16 + +/* + * Bit Feild of LTM_CLIP: LTM_GAIN_TH + * MTK_CAM_LTM_CLIP_LTM_GAIN_TH: [0, 5] + * Threshold to clip output gain + */ +#define MTK_CAM_LTM_CLIP_LTM_GAIN_TH_MASK 0x0000003f +#define MTK_CAM_LTM_CLIP_LTM_GAIN_TH_SHIFT 0 + +/* + * Bit Feild of LTM_CFG: LTM_ENGINE_EN + * MTK_CAM_LTM_CFG_LTM_ENGINE_EN: [0, 0] + * None + */ +#define MTK_CAM_LTM_CFG_LTM_ENGINE_EN_MASK 0x00000001 +#define MTK_CAM_LTM_CFG_LTM_ENGINE_EN_SHIFT 0 + +/* + * Bit Feild of LTM_CFG: LTM_CG_DISABLE + * MTK_CAM_LTM_CFG_LTM_CG_DISABLE: [4, 4] + * None + */ +#define MTK_CAM_LTM_CFG_LTM_CG_DISABLE_MASK 0x00000010 +#define MTK_CAM_LTM_CFG_LTM_CG_DISABLE_SHIFT 4 + +/* + * Bit Feild of LTM_CFG: LTM_CHKSUM_EN + * MTK_CAM_LTM_CFG_LTM_CHKSUM_EN: [28, 28] + * None + */ +#define MTK_CAM_LTM_CFG_LTM_CHKSUM_EN_MASK 0x10000000 +#define MTK_CAM_LTM_CFG_LTM_CHKSUM_EN_SHIFT 28 + +/* + * Bit Feild of LTM_CFG: LTM_CHKSUM_SEL + * MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL: [29, 30] + * None + */ +#define MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL_MASK 0x60000000 +#define MTK_CAM_LTM_CFG_LTM_CHKSUM_SEL_SHIFT 29 + +/* + * Bit Feild of LTM_CLIP_TH: LTM_CLIP_TH + * MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH: [0, 23] + * clipping threshold, enabled if #define LTM_USE_PREVIOUS_MAXVALUE=1 + */ +#define MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH_MASK 0x00ffffff +#define MTK_CAM_LTM_CLIP_TH_LTM_CLIP_TH_SHIFT 0 + +/* + * Bit Feild of LTM_CLIP_TH: LTM_WGT_BSH + * MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH: [24, 27] + * rightward bit shift for weighting data + */ +#define MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH_MASK 0x0f000000 +#define MTK_CAM_LTM_CLIP_TH_LTM_WGT_BSH_SHIFT 24 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_MAP_LOG_EN + * MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN: [0, 0] + * switch for map log + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN_MASK 0x00000001 +#define MTK_CAM_LTM_GAIN_MAP_LTM_MAP_LOG_EN_SHIFT 0 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_WGT_LOG_EN + * MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN: [1, 1] + * switch for weight log + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN_MASK 0x00000002 +#define MTK_CAM_LTM_GAIN_MAP_LTM_WGT_LOG_EN_SHIFT 1 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_NONTRAN_MAP_TYPE + * MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE: [4, 7] + * type of nontran map + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE_MASK 0x000000f0 +#define MTK_CAM_LTM_GAIN_MAP_LTM_NONTRAN_MAP_TYPE_SHIFT 4 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_TRAN_MAP_TYPE + * MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE: [8, 11] + * type of tran map + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE_MASK 0x00000f00 +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_MAP_TYPE_SHIFT 8 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_TRAN_WGT_TYPE + * MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_TYPE: [12, 13] + * type of tran weight + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_TYPE_MASK 0x00003000 +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_TYPE_SHIFT 12 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_TRAN_WGT + * MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT: [16, 20] + * static tran weight + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_MASK 0x001f0000 +#define MTK_CAM_LTM_GAIN_MAP_LTM_TRAN_WGT_SHIFT 16 + +/* + * Bit Feild of LTM_GAIN_MAP: LTM_RANGE_SCL + * MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL: [24, 29] + * scale of maxTran + */ +#define MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL_MASK 0x3f000000 +#define MTK_CAM_LTM_GAIN_MAP_LTM_RANGE_SCL_SHIFT 24 + +/* + * Bit Feild of LTM_CVNODE_GRP0: LTM_CVNODE_0 + * MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0: [0, 11] + * cvnode-0 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_0_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP0: LTM_CVNODE_1 + * MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1: [16, 27] + * cvnode-1 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP0_LTM_CVNODE_1_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP1: LTM_CVNODE_2 + * MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2: [0, 11] + * cvnode-2 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_2_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP1: LTM_CVNODE_3 + * MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3: [16, 27] + * cvnode-3 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP1_LTM_CVNODE_3_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP2: LTM_CVNODE_4 + * MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4: [0, 11] + * cvnode-4 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_4_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP2: LTM_CVNODE_5 + * MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5: [16, 27] + * cvnode-5 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP2_LTM_CVNODE_5_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP3: LTM_CVNODE_6 + * MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6: [0, 11] + * cvnode-6 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_6_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP3: LTM_CVNODE_7 + * MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7: [16, 27] + * cvnode-7 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP3_LTM_CVNODE_7_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP4: LTM_CVNODE_8 + * MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8: [0, 11] + * cvnode-8 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_8_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP4: LTM_CVNODE_9 + * MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9: [16, 27] + * cvnode-9 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP4_LTM_CVNODE_9_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP5: LTM_CVNODE_10 + * MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10: [0, 11] + * cvnode-10 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_10_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP5: LTM_CVNODE_11 + * MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11: [16, 27] + * cvnode-11 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP5_LTM_CVNODE_11_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP6: LTM_CVNODE_12 + * MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12: [0, 11] + * cvnode-12 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_12_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP6: LTM_CVNODE_13 + * MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13: [16, 27] + * cvnode-13 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP6_LTM_CVNODE_13_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP7: LTM_CVNODE_14 + * MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14: [0, 11] + * cvnode-14 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_14_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP7: LTM_CVNODE_15 + * MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15: [16, 27] + * cvnode-15 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP7_LTM_CVNODE_15_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP8: LTM_CVNODE_16 + * MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16: [0, 11] + * cvnode-16 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_16_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP8: LTM_CVNODE_17 + * MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17: [16, 27] + * cvnode-17 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP8_LTM_CVNODE_17_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP9: LTM_CVNODE_18 + * MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18: [0, 11] + * cvnode-18 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_18_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP9: LTM_CVNODE_19 + * MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19: [16, 27] + * cvnode-19 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP9_LTM_CVNODE_19_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP10: LTM_CVNODE_20 + * MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20: [0, 11] + * cvnode-20 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_20_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP10: LTM_CVNODE_21 + * MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21: [16, 27] + * cvnode-21 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP10_LTM_CVNODE_21_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP11: LTM_CVNODE_22 + * MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22: [0, 11] + * cvnode-22 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_22_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP11: LTM_CVNODE_23 + * MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23: [16, 27] + * cvnode-23 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP11_LTM_CVNODE_23_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP12: LTM_CVNODE_24 + * MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24: [0, 11] + * cvnode-24 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_24_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP12: LTM_CVNODE_25 + * MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25: [16, 27] + * cvnode-25 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP12_LTM_CVNODE_25_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP13: LTM_CVNODE_26 + * MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26: [0, 11] + * cvnode-26 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_26_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP13: LTM_CVNODE_27 + * MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27: [16, 27] + * cvnode-27 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP13_LTM_CVNODE_27_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP14: LTM_CVNODE_28 + * MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28: [0, 11] + * cvnode-28 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_28_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP14: LTM_CVNODE_29 + * MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29: [16, 27] + * cvnode-29 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP14_LTM_CVNODE_29_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP15: LTM_CVNODE_30 + * MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30: [0, 11] + * cvnode-30 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_30_SHIFT 0 + +/* + * Bit Feild of LTM_CVNODE_GRP15: LTM_CVNODE_31 + * MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31: [16, 27] + * cvnode-31 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31_MASK 0x0fff0000 +#define MTK_CAM_LTM_CVNODE_GRP15_LTM_CVNODE_31_SHIFT 16 + +/* + * Bit Feild of LTM_CVNODE_GRP16: LTM_CVNODE_32 + * MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32: [0, 11] + * cvnode-32 for gain map + */ +#define MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32_MASK 0x00000fff +#define MTK_CAM_LTM_CVNODE_GRP16_LTM_CVNODE_32_SHIFT 0 + +/* + * Bit Feild of LTM_OUT_STR: LTM_OUT_STR + * MTK_CAM_LTM_OUT_STR_LTM_OUT_STR: [0, 4] + * output strength + */ +#define MTK_CAM_LTM_OUT_STR_LTM_OUT_STR_MASK 0x0000001f +#define MTK_CAM_LTM_OUT_STR_LTM_OUT_STR_SHIFT 0 + +/* + * Bit Feild of LTM_ACT_WIN_X: LTM_ACT_WIN_X_START + * MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START: [0, 15] + * Horizontal setting for active window of AE debug + */ +#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START_MASK 0x0000ffff +#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_START_SHIFT 0 + +/* + * Bit Feild of LTM_ACT_WIN_X: LTM_ACT_WIN_X_END + * MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END: [16, 31] + * Horizontal setting for active window of AE debug + */ +#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END_MASK 0xffff0000 +#define MTK_CAM_LTM_ACT_WIN_X_LTM_ACT_WIN_X_END_SHIFT 16 + +/* + * Bit Feild of LTM_ACT_WIN_Y: LTM_ACT_WIN_Y_START + * MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START: [0, 15] + * Vertical setting for active window of AE debug + */ +#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START_MASK 0x0000ffff +#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_START_SHIFT 0 + +/* + * Bit Feild of LTM_ACT_WIN_Y: LTM_ACT_WIN_Y_END + * MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END: [16, 31] + * Vertical setting for active window of AE debug + */ +#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END_MASK 0xffff0000 +#define MTK_CAM_LTM_ACT_WIN_Y_LTM_ACT_WIN_Y_END_SHIFT 16 + +/* + * Bit Feild of OBC_DBS: OBC_DBS_RATIO + * MTK_CAM_OBC_DBS_OBC_DBS_RATIO: [0, 4] + * Ratio of "bias" being eliminated + */ +#define MTK_CAM_OBC_DBS_OBC_DBS_RATIO_MASK 0x0000001f +#define MTK_CAM_OBC_DBS_OBC_DBS_RATIO_SHIFT 0 + +/* + * Bit Feild of OBC_DBS: OBC_POSTTUNE_EN + * MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN: [8, 8] + * Enable gray-blending and LUT-subtraction processing + */ +#define MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN_MASK 0x00000100 +#define MTK_CAM_OBC_DBS_OBC_POSTTUNE_EN_SHIFT 8 + +/* + * Bit Feild of OBC_GRAY_BLD_0: OBC_LUMA_MODE + * MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE: [0, 0] + * Selection between max mode or mean mode for luma computation + */ +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE_MASK 0x00000001 +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_LUMA_MODE_SHIFT 0 + +/* + * Bit Feild of OBC_GRAY_BLD_0: OBC_GRAY_MODE + * MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE: [1, 2] + * Method of gray value computation + */ +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE_MASK 0x00000006 +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_GRAY_MODE_SHIFT 1 + +/* + * Bit Feild of OBC_GRAY_BLD_0: OBC_NORM_BIT + * MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT: [3, 7] + * Data scale to be normalized to 12-bit + */ +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT_MASK 0x000000f8 +#define MTK_CAM_OBC_GRAY_BLD_0_OBC_NORM_BIT_SHIFT 3 + +/* + * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_MXRT + * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT: [0, 7] + * (normal and LE)Maximum weight for gray blending + */ +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT_MASK 0x000000ff +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_MXRT_SHIFT 0 + +/* + * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_LOW + * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW: [8, 19] + * (normal and LE)Luma level below which the gray value is + * bleneded with the specified maximum weight. + */ +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW_MASK 0x000fff00 +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_LOW_SHIFT 8 + +/* + * Bit Feild of OBC_GRAY_BLD_1: OBC_BLD_SLP + * MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP: [20, 31] + * (normal and LE)Slope of the blending ratio curve between zero and maximum weight. + */ +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP_MASK 0xfff00000 +#define MTK_CAM_OBC_GRAY_BLD_1_OBC_BLD_SLP_SHIFT 20 + +/* + * Bit Feild of OBC_WBG_RB: OBC_PGN_R + * MTK_CAM_OBC_WBG_RB_OBC_PGN_R: [0, 12] + * WB gain for R channel + */ +#define MTK_CAM_OBC_WBG_RB_OBC_PGN_R_MASK 0x00001fff +#define MTK_CAM_OBC_WBG_RB_OBC_PGN_R_SHIFT 0 + +/* + * Bit Feild of OBC_WBG_RB: OBC_PGN_B + * MTK_CAM_OBC_WBG_RB_OBC_PGN_B: [16, 28] + * WB gain for R channel + */ +#define MTK_CAM_OBC_WBG_RB_OBC_PGN_B_MASK 0x1fff0000 +#define MTK_CAM_OBC_WBG_RB_OBC_PGN_B_SHIFT 16 + +/* + * Bit Feild of OBC_WBG_G: OBC_PGN_G + * MTK_CAM_OBC_WBG_G_OBC_PGN_G: [0, 12] + * WB gain for G channel + */ +#define MTK_CAM_OBC_WBG_G_OBC_PGN_G_MASK 0x00001fff +#define MTK_CAM_OBC_WBG_G_OBC_PGN_G_SHIFT 0 + +/* + * Bit Feild of OBC_WBIG_RB: OBC_IVGN_R + * MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R: [0, 9] + * Inverse WB gain for R channel + */ +#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R_MASK 0x000003ff +#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_R_SHIFT 0 + +/* + * Bit Feild of OBC_WBIG_RB: OBC_IVGN_B + * MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B: [16, 25] + * Inverse WB gain for B channel + */ +#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B_MASK 0x03ff0000 +#define MTK_CAM_OBC_WBIG_RB_OBC_IVGN_B_SHIFT 16 + +/* + * Bit Feild of OBC_WBIG_G: OBC_IVGN_G + * MTK_CAM_OBC_WBIG_G_OBC_IVGN_G: [0, 9] + * Inverse WB gain for G channel + */ +#define MTK_CAM_OBC_WBIG_G_OBC_IVGN_G_MASK 0x000003ff +#define MTK_CAM_OBC_WBIG_G_OBC_IVGN_G_SHIFT 0 + +/* + * Bit Feild of OBC_OBG_RB: OBC_GAIN_R + * MTK_CAM_OBC_OBG_RB_OBC_GAIN_R: [0, 11] + * OB gain for R channel + */ +#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_R_MASK 0x00000fff +#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_R_SHIFT 0 + +/* + * Bit Feild of OBC_OBG_RB: OBC_GAIN_B + * MTK_CAM_OBC_OBG_RB_OBC_GAIN_B: [16, 27] + * OB gain for B channel + */ +#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_B_MASK 0x0fff0000 +#define MTK_CAM_OBC_OBG_RB_OBC_GAIN_B_SHIFT 16 + +/* + * Bit Feild of OBC_OBG_G: OBC_GAIN_GR + * MTK_CAM_OBC_OBG_G_OBC_GAIN_GR: [0, 11] + * OB gain for Gr channel + */ +#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GR_MASK 0x00000fff +#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GR_SHIFT 0 + +/* + * Bit Feild of OBC_OBG_G: OBC_GAIN_GB + * MTK_CAM_OBC_OBG_G_OBC_GAIN_GB: [16, 27] + * OB gain for Gb channel + */ +#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GB_MASK 0x0fff0000 +#define MTK_CAM_OBC_OBG_G_OBC_GAIN_GB_SHIFT 16 + +/* + * Bit Feild of OBC_OFFSET_R: OBC_OFST_R + * MTK_CAM_OBC_OFFSET_R_OBC_OFST_R: [0, 21] + * OB offset for R channel + */ +#define MTK_CAM_OBC_OFFSET_R_OBC_OFST_R_MASK 0x003fffff +#define MTK_CAM_OBC_OFFSET_R_OBC_OFST_R_SHIFT 0 + +/* + * Bit Feild of OBC_OFFSET_GR: OBC_OFST_GR + * MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR: [0, 21] + * OB offset for Gr channel + */ +#define MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR_MASK 0x003fffff +#define MTK_CAM_OBC_OFFSET_GR_OBC_OFST_GR_SHIFT 0 + +/* + * Bit Feild of OBC_OFFSET_GB: OBC_OFST_GB + * MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB: [0, 21] + * OB offset for Gb channel + */ +#define MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB_MASK 0x003fffff +#define MTK_CAM_OBC_OFFSET_GB_OBC_OFST_GB_SHIFT 0 + +/* + * Bit Feild of OBC_OFFSET_B: OBC_OFST_B + * MTK_CAM_OBC_OFFSET_B_OBC_OFST_B: [0, 21] + * OB offset for B channel + */ +#define MTK_CAM_OBC_OFFSET_B_OBC_OFST_B_MASK 0x003fffff +#define MTK_CAM_OBC_OFFSET_B_OBC_OFST_B_SHIFT 0 + +/* + * Bit Feild of TSFS_DGAIN: TSFS_REGEN_Y_EN + * MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN: [0, 0] + * Digital gain control + */ +#define MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN_MASK 0x00000001 +#define MTK_CAM_TSFS_DGAIN_TSFS_REGEN_Y_EN_SHIFT 0 + +/* + * Bit Feild of TSFS_DGAIN: TSFS_GAIN + * MTK_CAM_TSFS_DGAIN_TSFS_GAIN: [1, 16] + * Digital gain + */ +#define MTK_CAM_TSFS_DGAIN_TSFS_GAIN_MASK 0x0001fffe +#define MTK_CAM_TSFS_DGAIN_TSFS_GAIN_SHIFT 1 + +/* + * V 4 L 2 M E T A B U F F E R L A Y O U T + */ + +/* + * struct mtk_cam_uapi_meta_raw_stats_cfg + * + * @ae_awb_enable: To indicate if AE and AWB should be enblaed or not. If + * it is 1, it means that we enable the following parts of + * hardware: + * (1) AE/AWB + * (2) aao + * (3) aaho + * @af_enable: To indicate if AF should be enabled or not. If it is 1, + * it means that the AF and afo is enabled. + * @dgn_enable: To indicate if dgn module should be enabled or not. + * @flk_enable: If it is 1, it means flk and flko is enable. If ie is 0, + * both flk and flko is disabled. + * @tsf_enable: If it is 1, it means tsfs and tsfso is enable. If ie is 0, + * both tsfs and tsfso is disabled. + * @wb_enable: To indicate if wb module should be enabled or not. + * @pde_enable: To indicate if pde module should be enabled or not. + * @ae_param: AE Statistic window config + * @awb_param: AWB statistic configuration control + * @dgn_param: DGN settings + * @flk_param: Flicker statistic configuration + * @tsf_param: tsf statistic configuration + * @wb_param: WB settings + * @pde_param: pde settings + */ +struct mtk_cam_uapi_meta_raw_stats_cfg { + s8 ae_awb_enable; + s8 af_enable; + s8 dgn_enable; + s8 flk_enable; + s8 tsf_enable; + s8 wb_enable; + s8 pde_enable; + u8 rsv; + + struct mtk_cam_uapi_ae_param ae_param; + struct mtk_cam_uapi_awb_param awb_param; + struct mtk_cam_uapi_af_param af_param; + struct mtk_cam_uapi_dgn_param dgn_param; + struct mtk_cam_uapi_flk_param flk_param; + struct mtk_cam_uapi_tsf_param tsf_param; + struct mtk_cam_uapi_wb_param wb_param; + struct mtk_cam_uapi_pde_param pde_param; + + struct mtk_cam_uapi_prot { + /* The following top control are generated by script */ + u8 drzh2n_r1_tuning_enable; + u8 drzh2n_r2_tuning_enable; + u8 drzh2n_r3_tuning_enable; + u8 drzh2n_r4_tuning_enable; + u8 drzh2n_r5_tuning_enable; + u8 drzh2n_r6_tuning_enable; + u8 drzh2n_r7_tuning_enable; + u8 drzh2n_r8_tuning_enable; + u8 drzs4n_r1_tuning_enable; + u8 drzs4n_r2_tuning_enable; + u8 drzs4n_r3_tuning_enable; + u8 dm_tuning_enable; + u8 drzs8t_r1_tuning_enable; + u8 drzs8t_r2_tuning_enable; + u8 ggm_r1_tuning_enable; + u8 ggm_r2_tuning_enable; + u8 ggm_r3_tuning_enable; + u8 bpc_r1_enable; + u8 bpc_r2_enable; + u8 ccm_r1_enable; + u8 ccm_r2_enable; + u8 ccm_r3_enable; + u8 fus_enable; + u8 g2c_r1_enable; + u8 g2c_r2_enable; + u8 g2c_r3_enable; + u8 hlr_enable; + u8 lsc_enable; + u8 ltm_enable; + u8 ltms_enable; + u8 obc_r1_enable; + u8 obc_r2_enable; + u8 tcy_r1_enable; + u8 tcy_r2_enable; + u8 tcy_r3_enable; + u8 tncs_r1_enable; + + struct mtk_cam_uapi_ccm_param_prot ccm_r1_param; + struct mtk_cam_uapi_ccm_param_prot ccm_r2_param; + struct mtk_cam_uapi_ccm_param_prot ccm_r3_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r1_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r2_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r3_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r4_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r5_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r6_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r7_param; + struct mtk_cam_uapi_drzh2n_param_prot drzh2n_r8_param; + struct mtk_cam_uapi_drzs4n_param_prot drzs4n_r1_param; + struct mtk_cam_uapi_drzs4n_param_prot drzs4n_r2_param; + struct mtk_cam_uapi_drzs4n_param_prot drzs4n_r3_param; + struct mtk_cam_uapi_tncs_param_prot tncs_param; + /* script generation done */ + struct mtk_cam_uapi_drzs8t_param_prot drzs8t_r1_param; + struct mtk_cam_uapi_drzs8t_param_prot drzs8t_r2_param; + struct mtk_cam_uapi_awb_param_prot awb_param; + struct mtk_cam_uapi_bpc_param_prot bpc_param; + struct mtk_cam_uapi_lsc_param_prot lsc_param; + struct mtk_cam_uapi_slk_param_prot slk_param; + struct mtk_cam_uapi_wb_param_prot wb_param; + struct mtk_cam_uapi_ltms_param_prot ltms_param; + struct mtk_cam_uapi_yuvo_param_prot yuvo_r2_param; + struct mtk_cam_uapi_yuvo_param_prot yuvo_r4_param; + /* The following module stuctures are generated by script */ + struct mtk_cam_uapi_regmap_raw_bpc bpc_r1; + struct mtk_cam_uapi_regmap_raw_bpc bpc_r2; + struct mtk_cam_uapi_regmap_raw_ccm ccm_r1; + struct mtk_cam_uapi_regmap_raw_ccm ccm_r2; + struct mtk_cam_uapi_regmap_raw_ccm ccm_r3; + struct mtk_cam_uapi_regmap_raw_dm dm_r1; + u8 rsv1[116]; + struct mtk_cam_uapi_regmap_raw_g2c g2c_r1; + struct mtk_cam_uapi_regmap_raw_g2c g2c_r2; + struct mtk_cam_uapi_regmap_raw_g2c g2c_r3; + struct mtk_cam_uapi_regmap_raw_ggm ggm_r1; + struct mtk_cam_uapi_regmap_raw_ggm ggm_r2; + struct mtk_cam_uapi_regmap_raw_ggm ggm_r3; + u8 rsv2[68]; + struct mtk_cam_uapi_regmap_raw_lsc lsc_r1; + struct mtk_cam_uapi_regmap_raw_ltm ltm_r1; + struct mtk_cam_uapi_regmap_raw_ltms ltms_r1; + struct mtk_cam_uapi_regmap_raw_obc obc_r1; + struct mtk_cam_uapi_regmap_raw_obc obc_r2; + u8 rsv3[1420]; + struct mtk_cam_uapi_regmap_raw_tsfs tsfs_r1; + u8 rsv4[50080]; + /* script generation done */ + } __packed prot; +} __packed; + +/* + * struct mtk_cam_uapi_meta_raw_stats_0 - capture buffer returns from camsys + * after the frame is done. The buffer are not be pushed the other + * driver such as dip. + * + * @ae_awb_stats_enabled: indicate that ae_awb_stats is ready or not in + * this buffer + * @ltm_stats_enabled: indicate that ltm_stats is ready or not in + * this buffer + * @flk_stats_enabled: indicate that flk_stats is ready or not in + * this buffer + * @tsf_stats_enabled: indicate that tsf_stats is ready or not in + * this buffer + * @pde_stats_enabled: indicate that pde_stats is ready or not in + * this buffer + * @pipeline_config: the pipeline configuration during processing + * @pde_stats: the pde module stats + */ +struct mtk_cam_uapi_meta_raw_stats_0 { + u8 ae_awb_stats_enabled; + u8 ltm_stats_enabled; + u8 flk_stats_enabled; + u8 tsf_stats_enabled; + u8 tncy_stats_enabled; + u8 pde_stats_enabled; + u8 rsv[2]; + + struct mtk_cam_uapi_pipeline_config pipeline_config; + + struct mtk_cam_uapi_ae_awb_stats ae_awb_stats; + struct mtk_cam_uapi_ltm_stats ltm_stats; + struct mtk_cam_uapi_flk_stats flk_stats; + struct mtk_cam_uapi_tsf_stats tsf_stats; + struct mtk_cam_uapi_tncy_stats tncy_stats; + struct mtk_cam_uapi_pd_stats pde_stats; + struct mtk_cam_uapi_timestamp timestamp; +} __packed; + +/* + * struct mtk_cam_uapi_meta_raw_stats_1 - statistics before frame done + * + * @af_stats_enabled: indicate that lce_stats is ready or not in this buffer + * @af_stats: AF statistics + * + * Any statistic output put in this structure should be careful. + * The meta buffer needs copying overhead to return the buffer before the + * all the ISP hardware's processing is finished. + */ +struct mtk_cam_uapi_meta_raw_stats_1 { + u8 af_stats_enabled; + u8 af_qbn_r6_enabled; + u8 rsv[2]; + struct mtk_cam_uapi_af_stats af_stats; +} __packed; + +/* + * struct mtk_cam_uapi_meta_raw_stats_2 - shared statistics buffer + * + * @act_stats_enabled: indicate that act_stats is ready or not in this + * buffer + * @act_stats: act statistics + * + * The statistic output in this structure may be pushed to the other + * driver such as dip. + * + */ +struct mtk_cam_uapi_meta_raw_stats_2 { + u8 act_stats_enabled; + u8 rsv[3]; + struct mtk_cam_uapi_act_stats act_stats; +} __packed; + +/* + * struct mtk_cam_uapi_meta_camsv_stats_0 - capture buffer returns from + * camsys's camsv module after the frame is done. The buffer are + * not be pushed the other driver such as dip. + * + * @pd_stats_enabled: indicate that pd_stats is ready or not in + * this buffer + */ +struct mtk_cam_uapi_meta_camsv_stats_0 { + u8 pd_stats_enabled; + u8 rsv[3]; + struct mtk_cam_uapi_pd_stats pd_stats; +} __packed; + +#define MTK_CAM_META_VERSION_MAJOR 2 +#define MTK_CAM_META_VERSION_MINOR 3 +#define MTK_CAM_META_PLATFORM_NAME "isp71" +#define MTK_CAM_META_CHIP_NAME "mt8188" + +#endif /* __MTK_CAM_META_H__ */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c new file mode 100644 index 000000000000..3294ffaf56e6 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.c @@ -0,0 +1,207 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2022 MediaTek Inc. + +#include +#include +#include +#include +#include + +#include +#include + +#include "mtk_cam.h" +#include "mtk_cam-raw.h" +#include "mtk_cam-video.h" +#include "mtk_cam-plat-util.h" +#include "mtk_cam-meta-mt8188.h" + +#define RAW_STATS_CFG_SIZE \ + ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_cfg), SZ_1K) + +/* meta out max size include 1k meta info and dma buffer size */ +#define RAW_STATS_0_SIZE \ + ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_0), SZ_1K) + \ + MTK_CAM_UAPI_AAO_MAX_BUF_SIZE + MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE + \ + MTK_CAM_UAPI_LTMSO_SIZE + \ + MTK_CAM_UAPI_FLK_MAX_BUF_SIZE + \ + MTK_CAM_UAPI_TSFSO_SIZE * 2 + /* r1 & r2 */ \ + MTK_CAM_UAPI_TNCSYO_SIZE, (4 * SZ_1K)) + +#define RAW_STATS_1_SIZE \ + ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_1), SZ_1K) + \ + MTK_CAM_UAPI_AFO_MAX_BUF_SIZE, (4 * SZ_1K)) + +#define RAW_STATS_2_SIZE \ + ALIGN(ALIGN(sizeof(struct mtk_cam_uapi_meta_raw_stats_2), SZ_1K) + \ + MTK_CAM_UAPI_ACTSO_SIZE, (4 * SZ_1K)) + +/* ISP platform meta format */ +static const struct mtk_cam_format_desc meta_fmts[] = { + { + .vfmt.fmt.meta = { + .dataformat = V4L2_META_FMT_MTISP_PARAMS, + .buffersize = RAW_STATS_CFG_SIZE, + }, + }, + { + .vfmt.fmt.meta = { + .dataformat = V4L2_META_FMT_MTISP_3A, + .buffersize = RAW_STATS_0_SIZE, + }, + }, + { + .vfmt.fmt.meta = { + .dataformat = V4L2_META_FMT_MTISP_AF, + .buffersize = RAW_STATS_1_SIZE, + }, + }, + { + .vfmt.fmt.meta = { + .dataformat = V4L2_META_FMT_MTISP_LCS, + .buffersize = RAW_STATS_2_SIZE, + }, + }, +}; + +struct mtk_cam_vb2_buf { + struct device *dev; + void *vaddr; + unsigned long size; + void *cookie; + dma_addr_t dma_addr; + unsigned long attrs; + enum dma_data_direction dma_dir; + struct sg_table *dma_sgt; + struct frame_vector *vec; + + /* MMAP related */ + struct vb2_vmarea_handler handler; + refcount_t refcount; + struct sg_table *sgt_base; + + /* DMABUF related */ + struct dma_buf_attachment *db_attach; + struct iosys_map map; +}; + +static void set_payload(struct mtk_cam_uapi_meta_hw_buf *buf, + unsigned int size, unsigned long *offset) +{ + buf->offset = *offset; + buf->size = size; + *offset += size; +} + +static void vb2_sync_for_device(void *buf_priv) +{ + struct mtk_cam_vb2_buf *buf = buf_priv; + struct sg_table *sgt = buf->dma_sgt; + + if (!sgt) + return; + + dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir); +} + +uint64_t *camsys_get_timestamp_addr(void *vaddr) +{ + struct mtk_cam_uapi_meta_raw_stats_0 *stats0; + + stats0 = (struct mtk_cam_uapi_meta_raw_stats_0 *)vaddr; + return (uint64_t *)(stats0->timestamp.timestamp_buf); +} +EXPORT_SYMBOL_GPL(camsys_get_timestamp_addr); + +void camsys_set_meta_stats_info(u32 dma_port, struct vb2_buffer *vb, + struct mtk_raw_pde_config *pde_cfg) +{ + struct mtk_cam_uapi_meta_raw_stats_0 *stats0; + struct mtk_cam_uapi_meta_raw_stats_1 *stats1; + unsigned long offset; + unsigned int plane; + void *vaddr = vb2_plane_vaddr(vb, 0); + + switch (dma_port) { + case MTKCAM_IPI_RAW_META_STATS_0: + stats0 = (struct mtk_cam_uapi_meta_raw_stats_0 *)vaddr; + offset = sizeof(*stats0); + set_payload(&stats0->ae_awb_stats.aao_buf, + MTK_CAM_UAPI_AAO_MAX_BUF_SIZE, &offset); + set_payload(&stats0->ae_awb_stats.aaho_buf, + MTK_CAM_UAPI_AAHO_MAX_BUF_SIZE, &offset); + set_payload(&stats0->ltm_stats.ltmso_buf, + MTK_CAM_UAPI_LTMSO_SIZE, &offset); + set_payload(&stats0->flk_stats.flko_buf, + MTK_CAM_UAPI_FLK_MAX_BUF_SIZE, &offset); + set_payload(&stats0->tsf_stats.tsfo_r1_buf, + MTK_CAM_UAPI_TSFSO_SIZE, &offset); + set_payload(&stats0->tsf_stats.tsfo_r2_buf, + MTK_CAM_UAPI_TSFSO_SIZE, &offset); + set_payload(&stats0->tncy_stats.tncsyo_buf, + MTK_CAM_UAPI_TNCSYO_SIZE, &offset); + if (pde_cfg) { + if (pde_cfg->pde_info.pd_table_offset) { + set_payload(&stats0->pde_stats.pdo_buf, + pde_cfg->pde_info.pdo_max_size, &offset); + } + } + /* Use scp reserved cache buffer, do buffer cache sync after fill in meta payload */ + for (plane = 0; plane < vb->num_planes; ++plane) + vb2_sync_for_device(vb->planes[plane].mem_priv); + break; + case MTKCAM_IPI_RAW_META_STATS_1: + stats1 = (struct mtk_cam_uapi_meta_raw_stats_1 *)vaddr; + offset = sizeof(*stats1); + set_payload(&stats1->af_stats.afo_buf, + MTK_CAM_UAPI_AFO_MAX_BUF_SIZE, &offset); + /* Use scp reserved cache buffer, do buffer cache sync after fill in meta payload */ + for (plane = 0; plane < vb->num_planes; ++plane) + vb2_sync_for_device(vb->planes[plane].mem_priv); + break; + case MTKCAM_IPI_RAW_META_STATS_2: + pr_info("stats 2 not support"); + break; + default: + pr_debug("%s: dma_port err\n", __func__); + break; + } +} +EXPORT_SYMBOL_GPL(camsys_set_meta_stats_info); + +int camsys_get_meta_version(bool major) +{ + if (major) + return MTK_CAM_META_VERSION_MAJOR; + else + return MTK_CAM_META_VERSION_MINOR; +} +EXPORT_SYMBOL_GPL(camsys_get_meta_version); + +int camsys_get_meta_size(u32 video_id) +{ + switch (video_id) { + case MTKCAM_IPI_RAW_META_STATS_CFG: + return RAW_STATS_CFG_SIZE; + case MTKCAM_IPI_RAW_META_STATS_0: + return RAW_STATS_0_SIZE; + case MTKCAM_IPI_RAW_META_STATS_1: + return RAW_STATS_1_SIZE; + case MTKCAM_IPI_RAW_META_STATS_2: + return RAW_STATS_2_SIZE; + default: + pr_debug("%s: no support stats(%d)\n", __func__, video_id); + } + return 0; +} +EXPORT_SYMBOL_GPL(camsys_get_meta_size); + +const struct mtk_cam_format_desc *camsys_get_meta_fmts(void) +{ + return meta_fmts; +} +EXPORT_SYMBOL_GPL(camsys_get_meta_fmts); + +MODULE_DESCRIPTION("MediaTek camera platform utility"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h new file mode 100644 index 000000000000..18c387ffd9fc --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-plat-util.h @@ -0,0 +1,16 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_PLAT_UTIL_H +#define __MTK_CAM_PLAT_UTIL_H + +int camsys_get_meta_version(bool major); +int camsys_get_meta_size(u32 video_id); +const struct mtk_cam_format_desc *camsys_get_meta_fmts(void); +void camsys_set_meta_stats_info(u32 dma_port, struct vb2_buffer *vb, + struct mtk_raw_pde_config *pde_cfg); +uint64_t *camsys_get_timestamp_addr(void *vaddr); + +#endif /*__MTK_CAM_PLAT_UTIL_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c new file mode 100644 index 000000000000..d5ae321e1040 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.c @@ -0,0 +1,393 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2018 MediaTek Inc. + * Author: Louis Kuo + */ + +#include +#include +#include +#include +#include +#include + +#include "mtk_cam.h" +#include "mtk_cam-pool.h" + +int mtk_cam_working_buf_pool_init(struct mtk_cam_ctx *ctx, struct device *dev) +{ + int i, ret; + void *ptr; + dma_addr_t addr; + struct mtk_cam_device *cam = ctx->cam; + const unsigned int working_buf_size = round_up(CQ_BUF_SIZE, PAGE_SIZE); + const unsigned int msg_buf_size = round_up(IPI_FRAME_BUF_SIZE, PAGE_SIZE); + + INIT_LIST_HEAD(&ctx->buf_pool.cam_freelist.list); + spin_lock_init(&ctx->buf_pool.cam_freelist.lock); + ctx->buf_pool.cam_freelist.cnt = 0; + ctx->buf_pool.working_buf_size = CAM_CQ_BUF_NUM * working_buf_size; + ctx->buf_pool.msg_buf_size = CAM_CQ_BUF_NUM * msg_buf_size; + ctx->buf_pool.raw_workbuf_size = round_up(SIZE_OF_RAW_WORKBUF, PAGE_SIZE); + ctx->buf_pool.priv_workbuf_size = round_up(SIZE_OF_RAW_PRIV, PAGE_SIZE); + ctx->buf_pool.session_buf_size = round_up(SIZE_OF_SESSION, PAGE_SIZE); + + /* raw working buffer */ + ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.raw_workbuf_size, + &addr, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ctx->buf_pool.raw_workbuf_scp_addr = addr; + ctx->buf_pool.raw_workbuf_va = ptr; + dev_dbg(dev, "[%s] raw working buf scp addr:%pad va:%pK size %u\n", + __func__, + &ctx->buf_pool.raw_workbuf_scp_addr, + ctx->buf_pool.raw_workbuf_va, + ctx->buf_pool.raw_workbuf_size); + + /* raw priv working buffer */ + ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.priv_workbuf_size, + &addr, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ctx->buf_pool.priv_workbuf_scp_addr = addr; + ctx->buf_pool.priv_workbuf_va = ptr; + dev_dbg(dev, "[%s] raw pri working buf scp addr:%pad va:%pK size %u\n", + __func__, + &ctx->buf_pool.priv_workbuf_scp_addr, + ctx->buf_pool.priv_workbuf_va, + ctx->buf_pool.priv_workbuf_size); + + /* session buffer */ + ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.session_buf_size, + &addr, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ctx->buf_pool.session_buf_scp_addr = addr; + ctx->buf_pool.session_buf_va = ptr; + dev_dbg(dev, "[%s] session buf scp addr:%pad va:%pK size %u\n", + __func__, + &ctx->buf_pool.session_buf_scp_addr, + ctx->buf_pool.session_buf_va, + ctx->buf_pool.session_buf_size); + + /* working buffer */ + ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size, + &addr, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ctx->buf_pool.working_buf_scp_addr = addr; + ctx->buf_pool.working_buf_va = ptr; + addr = dma_map_resource(dev, addr, ctx->buf_pool.working_buf_size, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(dev, addr)) { + dev_err(dev, "failed to map scp iova\n"); + ret = -ENOMEM; + goto fail_free_mem; + } + ctx->buf_pool.working_buf_iova = addr; + dev_dbg(dev, "[%s] CQ buf scp addr:%pad va:%pK iova:%pad size %u\n", + __func__, + &ctx->buf_pool.working_buf_scp_addr, + ctx->buf_pool.working_buf_va, + &ctx->buf_pool.working_buf_iova, + ctx->buf_pool.working_buf_size); + + /* msg buffer */ + ptr = dma_alloc_coherent(cam->smem_dev, ctx->buf_pool.msg_buf_size, + &addr, GFP_KERNEL); + if (!ptr) { + ret = -ENOMEM; + goto fail_free_mem; + } + ctx->buf_pool.msg_buf_scp_addr = addr; + ctx->buf_pool.msg_buf_va = ptr; + dev_dbg(dev, "[%s] msg buf scp addr:%pad va:%pK size %u\n", + __func__, &ctx->buf_pool.msg_buf_scp_addr, + ctx->buf_pool.msg_buf_va, ctx->buf_pool.msg_buf_size); + + for (i = 0; i < CAM_CQ_BUF_NUM; i++) { + struct mtk_cam_working_buf_entry *buf = &ctx->buf_pool.working_buf[i]; + unsigned int offset = i * working_buf_size; + unsigned int offset_msg = i * msg_buf_size; + + buf->ctx = ctx; + buf->buffer.va = ctx->buf_pool.working_buf_va + offset; + buf->buffer.iova = ctx->buf_pool.working_buf_iova + offset; + buf->buffer.scp_addr = ctx->buf_pool.working_buf_scp_addr + offset; + buf->buffer.size = working_buf_size; + buf->msg_buffer.va = ctx->buf_pool.msg_buf_va + offset_msg; + buf->msg_buffer.scp_addr = ctx->buf_pool.msg_buf_scp_addr + offset_msg; + buf->msg_buffer.size = msg_buf_size; + buf->s_data = NULL; + + list_add_tail(&buf->list_entry, &ctx->buf_pool.cam_freelist.list); + ctx->buf_pool.cam_freelist.cnt++; + } + + dev_dbg(ctx->cam->dev, + "%s: ctx(%d): cq buffers init, freebuf cnt(%d)\n", + __func__, ctx->stream_id, ctx->buf_pool.cam_freelist.cnt); + + return 0; +fail_free_mem: + dma_free_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size, + ctx->buf_pool.working_buf_va, + ctx->buf_pool.working_buf_scp_addr); + ctx->buf_pool.working_buf_scp_addr = 0; + + return ret; +} + +void mtk_cam_working_buf_pool_release(struct mtk_cam_ctx *ctx, struct device *dev) +{ + struct mtk_cam_device *cam = ctx->cam; + + /* msg buffer */ + dma_free_coherent(cam->smem_dev, ctx->buf_pool.msg_buf_size, + ctx->buf_pool.msg_buf_va, + ctx->buf_pool.msg_buf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):msg buffers release, va:%pK scp_addr %pad sz %u\n", + __func__, ctx->stream_id, + ctx->buf_pool.msg_buf_va, + &ctx->buf_pool.msg_buf_scp_addr, + ctx->buf_pool.msg_buf_size); + + /* working buffer */ + dma_unmap_page_attrs(dev, ctx->buf_pool.working_buf_iova, + ctx->buf_pool.working_buf_size, + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); + dma_free_coherent(cam->smem_dev, ctx->buf_pool.working_buf_size, + ctx->buf_pool.working_buf_va, + ctx->buf_pool.working_buf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):cq buffers release, iova %pad scp_addr %pad sz %u\n", + __func__, ctx->stream_id, + &ctx->buf_pool.working_buf_iova, + &ctx->buf_pool.working_buf_scp_addr, + ctx->buf_pool.working_buf_size); + + /* session buffer */ + dma_free_coherent(cam->smem_dev, ctx->buf_pool.session_buf_size, + ctx->buf_pool.session_buf_va, + ctx->buf_pool.session_buf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):session buffers release, scp_addr %pad sz %u\n", + __func__, ctx->stream_id, + &ctx->buf_pool.session_buf_scp_addr, + ctx->buf_pool.session_buf_size); + + /* raw priv working buffer */ + dma_free_coherent(cam->smem_dev, ctx->buf_pool.priv_workbuf_size, + ctx->buf_pool.priv_workbuf_va, + ctx->buf_pool.priv_workbuf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):raw pri working buffers release, scp_addr %pad sz %u\n", + __func__, ctx->stream_id, + &ctx->buf_pool.priv_workbuf_scp_addr, + ctx->buf_pool.priv_workbuf_size); + + /* raw working buffer */ + dma_free_coherent(cam->smem_dev, ctx->buf_pool.raw_workbuf_size, + ctx->buf_pool.raw_workbuf_va, + ctx->buf_pool.raw_workbuf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):raw working buffers release, scp_addr %pad sz %u\n", + __func__, ctx->stream_id, + &ctx->buf_pool.raw_workbuf_scp_addr, + ctx->buf_pool.raw_workbuf_size); +} + +void mtk_cam_working_buf_put(struct mtk_cam_working_buf_entry *buf_entry) +{ + struct mtk_cam_ctx *ctx = buf_entry->ctx; + int cnt; + + spin_lock(&ctx->buf_pool.cam_freelist.lock); + + list_add_tail(&buf_entry->list_entry, + &ctx->buf_pool.cam_freelist.list); + cnt = ++ctx->buf_pool.cam_freelist.cnt; + + spin_unlock(&ctx->buf_pool.cam_freelist.lock); + + dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(%pad), free cnt(%d)\n", + __func__, ctx->stream_id, &buf_entry->buffer.iova, cnt); +} + +struct mtk_cam_working_buf_entry *mtk_cam_working_buf_get(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_working_buf_entry *buf_entry; + int cnt; + + /* get from free list */ + spin_lock(&ctx->buf_pool.cam_freelist.lock); + if (list_empty(&ctx->buf_pool.cam_freelist.list)) { + spin_unlock(&ctx->buf_pool.cam_freelist.lock); + + dev_info(ctx->cam->dev, "%s:ctx(%d):no free buf\n", + __func__, ctx->stream_id); + return NULL; + } + + buf_entry = list_first_entry(&ctx->buf_pool.cam_freelist.list, + struct mtk_cam_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + cnt = --ctx->buf_pool.cam_freelist.cnt; + buf_entry->ctx = ctx; + + spin_unlock(&ctx->buf_pool.cam_freelist.lock); + + dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(%pad), free cnt(%d)\n", + __func__, ctx->stream_id, &buf_entry->buffer.iova, cnt); + + return buf_entry; +} + +int mtk_cam_img_working_buf_pool_init(struct mtk_cam_ctx *ctx, int buf_num, + struct device *dev) +{ + int i, ret; + u32 working_buf_size; + void *ptr; + dma_addr_t addr; + struct mtk_cam_device *cam = ctx->cam; + struct mtk_cam_video_device *vdev; + + if (buf_num > CAM_IMG_BUF_NUM) { + dev_err(ctx->cam->dev, + "%s: ctx(%d): image buffers number too large(%d)\n", + __func__, ctx->stream_id, buf_num); + WARN_ON(1); + return 0; + } + + vdev = &ctx->pipe->vdev_nodes[MTK_RAW_MAIN_STREAM_OUT - MTK_RAW_SINK_NUM]; + working_buf_size = vdev->active_fmt.fmt.pix_mp.plane_fmt[0].sizeimage; + INIT_LIST_HEAD(&ctx->img_buf_pool.cam_freeimglist.list); + spin_lock_init(&ctx->img_buf_pool.cam_freeimglist.lock); + ctx->img_buf_pool.cam_freeimglist.cnt = 0; + ctx->img_buf_pool.working_img_buf_size = buf_num * working_buf_size; + ptr = dma_alloc_coherent(cam->smem_dev, + ctx->img_buf_pool.working_img_buf_size, + &addr, GFP_KERNEL); + if (!ptr) + return -ENOMEM; + ctx->img_buf_pool.working_img_buf_scp_addr = addr; + ctx->img_buf_pool.working_img_buf_va = ptr; + addr = dma_map_resource(dev, addr, ctx->img_buf_pool.working_img_buf_size, + DMA_BIDIRECTIONAL, DMA_ATTR_SKIP_CPU_SYNC); + if (dma_mapping_error(dev, addr)) { + dev_err(dev, "failed to map scp iova\n"); + ret = -ENOMEM; + goto fail_free_mem; + } + ctx->img_buf_pool.working_img_buf_iova = addr; + dev_dbg(dev, + "[%s] img working buf scp addr:%pad va:%pK iova: %pad size %d\n", + __func__, + &ctx->img_buf_pool.working_img_buf_scp_addr, + ctx->img_buf_pool.working_img_buf_va, + &ctx->img_buf_pool.working_img_buf_iova, + ctx->img_buf_pool.working_img_buf_size); + + for (i = 0; i < buf_num; i++) { + struct mtk_cam_img_working_buf_entry *buf = + &ctx->img_buf_pool.img_working_buf[i]; + int offset = i * working_buf_size; + + buf->ctx = ctx; + buf->img_buffer.va = + ctx->img_buf_pool.working_img_buf_va + offset; + buf->img_buffer.scp_addr = + ctx->img_buf_pool.working_img_buf_scp_addr + offset; + buf->img_buffer.iova = + ctx->img_buf_pool.working_img_buf_iova + offset; + buf->img_buffer.size = working_buf_size; + + list_add_tail(&buf->list_entry, + &ctx->img_buf_pool.cam_freeimglist.list); + ctx->img_buf_pool.cam_freeimglist.cnt++; + } + + dev_dbg(dev, "%s: ctx(%d): image buffers init, freebuf cnt(%d)\n", + __func__, ctx->stream_id, ctx->img_buf_pool.cam_freeimglist.cnt); + return 0; + +fail_free_mem: + dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size, + ctx->img_buf_pool.working_img_buf_va, + ctx->img_buf_pool.working_img_buf_scp_addr); + return ret; +} + +void mtk_cam_img_working_buf_pool_release(struct mtk_cam_ctx *ctx, + struct device *dev) +{ + struct mtk_cam_device *cam = ctx->cam; + + dma_unmap_page_attrs(dev, ctx->img_buf_pool.working_img_buf_iova, + ctx->img_buf_pool.working_img_buf_size, + DMA_BIDIRECTIONAL, + DMA_ATTR_SKIP_CPU_SYNC); + dma_free_coherent(cam->smem_dev, ctx->img_buf_pool.working_img_buf_size, + ctx->img_buf_pool.working_img_buf_va, + ctx->img_buf_pool.working_img_buf_scp_addr); + dev_dbg(dev, + "%s:ctx(%d):img working buf release, scp addr %pad va %pK iova %pad, sz %u\n", + __func__, ctx->stream_id, + &ctx->img_buf_pool.working_img_buf_scp_addr, + ctx->img_buf_pool.working_img_buf_va, + &ctx->img_buf_pool.working_img_buf_iova, + ctx->img_buf_pool.working_img_buf_size); +} + +void mtk_cam_img_working_buf_put(struct mtk_cam_img_working_buf_entry *buf_entry) +{ + struct mtk_cam_ctx *ctx = buf_entry->ctx; + int cnt; + + spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock); + + list_add_tail(&buf_entry->list_entry, + &ctx->img_buf_pool.cam_freeimglist.list); + cnt = ++ctx->img_buf_pool.cam_freeimglist.cnt; + + spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock); + + dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n", + __func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt); +} + +struct mtk_cam_img_working_buf_entry * +mtk_cam_img_working_buf_get(struct mtk_cam_ctx *ctx) +{ + struct mtk_cam_img_working_buf_entry *buf_entry; + int cnt; + + /* get from free list */ + spin_lock(&ctx->img_buf_pool.cam_freeimglist.lock); + if (list_empty(&ctx->img_buf_pool.cam_freeimglist.list)) { + spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock); + + dev_info(ctx->cam->dev, "%s:ctx(%d):no free buf\n", + __func__, ctx->stream_id); + return NULL; + } + + buf_entry = list_first_entry(&ctx->img_buf_pool.cam_freeimglist.list, + struct mtk_cam_img_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + cnt = --ctx->img_buf_pool.cam_freeimglist.cnt; + + spin_unlock(&ctx->img_buf_pool.cam_freeimglist.lock); + + dev_dbg(ctx->cam->dev, "%s:ctx(%d):iova(0x%pad), free cnt(%d)\n", + __func__, ctx->stream_id, &buf_entry->img_buffer.iova, cnt); + + return buf_entry; +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h new file mode 100644 index 000000000000..24cc8382f93d --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-pool.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2018 MediaTek Inc. + */ + +#ifndef __MTK_CAM_POOL_H +#define __MTK_CAM_POOL_H + +struct mtk_cam_ctx; + +int mtk_cam_working_buf_pool_init(struct mtk_cam_ctx *ctx, struct device *dev); +void mtk_cam_working_buf_pool_release(struct mtk_cam_ctx *ctx, + struct device *dev); + +void mtk_cam_working_buf_put(struct mtk_cam_working_buf_entry *buf_entry); +struct mtk_cam_working_buf_entry * + mtk_cam_working_buf_get(struct mtk_cam_ctx *ctx); + +int mtk_cam_img_working_buf_pool_init(struct mtk_cam_ctx *ctx, int buf_num, + struct device *dev); +void mtk_cam_img_working_buf_pool_release(struct mtk_cam_ctx *ctx, + struct device *dev); + +void mtk_cam_img_working_buf_put(struct mtk_cam_img_working_buf_entry *buf_entry); +struct mtk_cam_img_working_buf_entry * + mtk_cam_img_working_buf_get(struct mtk_cam_ctx *ctx); + +#endif /* __MTK_CAM_POOL_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h new file mode 100644 index 000000000000..cb00d243559c --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-regs-mt8188.h @@ -0,0 +1,382 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef _CAM_REGS_H +#define _CAM_REGS_H + +/* Raw Part */ + +/* normal siganl */ +#define VS_INT_ST BIT(0) +#define TG_INT1_ST BIT(1) +#define TG_INT2_ST BIT(2) +#define EXPDON_ST BIT(5) +#define SOF_INT_ST BIT(8) +#define HW_PASS1_DON_ST BIT(20) +#define SW_PASS1_DON_ST BIT(22) +#define TG_VS_INT_ORG_ST BIT(11) + +/* YUV siganl */ +#define YUV_SW_PASS1_DON_ST BIT(0) +#define YUV_PASS1_DON_ST BIT(1) +#define YUV_DMA_ERR_ST BIT(2) + +/* err status */ +#define TG_OVRUN_ST BIT(6) +#define TG_GBERR_ST BIT(7) +#define CQ_DB_LOAD_ERR_ST BIT(12) +#define CQ_MAIN_CODE_ERR_ST BIT(14) +#define CQ_MAIN_VS_ERR_ST BIT(15) +#define CQ_MAIN_TRIG_DLY_ST BIT(16) +#define LSCI_ERR_ST BIT(24) +#define DMA_ERR_ST BIT(26) + +/* CAM DMA done status */ +#define IMGO_DONE_ST BIT(0) +#define AFO_DONE_ST BIT(8) +#define CQI_R1_DONE_ST BIT(15) + +/* RAW input trigger ctrl*/ +#define RAWI_R2_TRIG BIT(0) +#define RAWI_R3_TRIG BIT(1) +#define RAWI_R4_TRIG BIT(2) +#define RAWI_R5_TRIG BIT(3) +#define RAWI_R6_TRIG BIT(4) + +/* IRQ signal mask */ +#define INT_ST_MASK_CAM (VS_INT_ST |\ + TG_INT1_ST |\ + TG_INT2_ST |\ + EXPDON_ST |\ + HW_PASS1_DON_ST |\ + SOF_INT_ST |\ + SW_PASS1_DON_ST) + +/* IRQ Error Mask */ +#define INT_ST_MASK_CAM_ERR (TG_OVRUN_ST |\ + TG_GBERR_ST |\ + CQ_DB_LOAD_ERR_ST |\ + CQ_MAIN_CODE_ERR_ST |\ + CQ_MAIN_VS_ERR_ST |\ + DMA_ERR_ST) + +/* camsys */ +#define REG_CAMSYS_CG_SET 0x0004 +#define REG_CAMSYS_CG_CLR 0x0008 + +#define REG_HALT1_EN 0x0350 +#define REG_HALT2_EN 0x0354 +#define REG_HALT3_EN 0x0358 +#define REG_HALT4_EN 0x035c +#define REG_HALT5_EN 0x0360 +#define REG_HALT6_EN 0x0364 +#define REG_FLASH 0x03A0 +#define REG_ULTRA_HALT1_EN 0x03c0 +#define REG_ULTRA_HALT2_EN 0x03c4 +#define REG_ULTRA_HALT3_EN 0x03c8 +#define REG_ULTRA_HALT4_EN 0x03cc +#define REG_ULTRA_HALT5_EN 0x03d0 +#define REG_ULTRA_HALT6_EN 0x03d4 +#define REG_PREULTRA_HALT1_EN 0x03f0 +#define REG_PREULTRA_HALT2_EN 0x03f4 +#define REG_PREULTRA_HALT3_EN 0x03f8 +#define REG_PREULTRA_HALT4_EN 0x03fc +#define REG_PREULTRA_HALT5_EN 0x0400 +#define REG_PREULTRA_HALT6_EN 0x0404 + +/* Status check */ +#define REG_CTL_EN 0x0000 +#define REG_CTL_EN2 0x0004 + +/* DMA Enable Register, DMA_EN */ +#define REG_CTL_MOD5_EN 0x0010 +#define REG_CTL_MOD6_EN 0x0014 +/* RAW input trigger*/ +#define REG_CTL_RAWI_TRIG 0x00C0 + +#define REG_CTL_MISC 0x0060 +#define CTL_DB_EN BIT(4) + +#define REG_CTL_SW_CTL 0x00C4 +#define REG_CTL_START 0x00B0 + +#define REG_CTL_RAW_INT_EN 0x0100 +#define REG_CTL_RAW_INT_STAT 0x0104 +#define REG_CTL_RAW_INT2_EN 0x0110 +#define REG_CTL_RAW_INT2_STAT 0x0114 +#define REG_CTL_RAW_INT3_STAT 0x0124 +#define REG_CTL_RAW_INT4_STAT 0x0134 +#define REG_CTL_RAW_INT5_STAT 0x0144 +#define REG_CTL_RAW_INT6_EN 0x0150 +#define REG_CTL_RAW_INT6_STAT 0x0154 +#define REG_CTL_RAW_INT7_EN 0x0160 +#define REG_CTL_RAW_INT7_STAT 0x0164 + +#define REG_CTL_RAW_MOD_DCM_DIS 0x0300 +#define REG_CTL_RAW_MOD2_DCM_DIS 0x0304 +#define REG_CTL_RAW_MOD3_DCM_DIS 0x0308 +#define REG_CTL_RAW_MOD5_DCM_DIS 0x0310 +#define REG_CTL_RAW_MOD6_DCM_DIS 0x0314 + +#define REG_CTL_DBG_SET 0x00F0 +#define REG_CTL_DBG_PORT 0x00F4 +#define REG_DMA_DBG_SEL 0x4070 +#define REG_DMA_DBG_PORT 0x4074 +#define REG_CTL_DBG_SET2 0x00F8 + +#define REG_CTL_RAW_MOD_REQ_STAT 0x0340 +#define REG_CTL_RAW_MOD2_REQ_STAT 0x0344 +#define REG_CTL_RAW_MOD3_REQ_STAT 0x0348 +#define REG_CTL_RAW_MOD4_REQ_STAT 0x034c +#define REG_CTL_RAW_MOD5_REQ_STAT 0x0350 +#define REG_CTL_RAW_MOD6_REQ_STAT 0x0354 + +#define REG_CTL_RAW_MOD_RDY_STAT 0x0360 +#define REG_CTL_RAW_MOD2_RDY_STAT 0x0364 +#define REG_CTL_RAW_MOD3_RDY_STAT 0x0368 +#define REG_CTL_RAW_MOD4_RDY_STAT 0x036c +#define REG_CTL_RAW_MOD5_RDY_STAT 0x0370 +#define REG_CTL_RAW_MOD6_RDY_STAT 0x0374 + +#define REG_CQ_EN 0x0400 +#define REG_SCQ_START_PERIOD 0x0408 +#define REG_CQ_THR0_CTL 0x0410 +#define REG_CQ_SUB_CQ_EN 0x06B0 +#define REG_CQ_SUB_THR0_CTL 0x06C0 + +#define REG_CTL_SW_PASS1_DONE 0x00c8 +#define SW_DONE_SAMPLE_EN BIT(8) +#define REG_CTL_SW_SUB_CTL 0x00cc + +#define REG_CQ_THR0_BASEADDR 0x0414 +#define REG_CQ_THR0_BASEADDR_MSB 0x0418 +#define REG_CQ_THR0_DESC_SIZE 0x041C +#define REG_SCQ_CQ_TRIG_TIME 0x0410 +#define REG_CQ_SUB_THR0_BASEADDR_2 0x06CC +#define REG_CQ_SUB_THR0_BASEADDR_MSB_2 0x06D0 +#define REG_CQ_SUB_THR0_DESC_SIZE_2 0x06D8 +#define REG_CQ_SUB_THR0_BASEADDR_1 0x06C4 +#define REG_CQ_SUB_THR0_BASEADDR_MSB_1 0x06C8 +#define REG_CQ_SUB_THR0_DESC_SIZE_1 0x06D4 +#define SCQ_EN BIT(20) +#define SCQ_STAGGER_MODE BIT(12) +#define SCQ_SUBSAMPLE_EN BIT(21) +#define CQ_DB_EN BIT(4) +#define CQ_THR0_MODE_IMMEDIATE BIT(4) +#define CQ_THR0_MODE_CONTINUOUS BIT(5) +#define CQ_THR0_EN BIT(0) +#define SCQ_SUB_RESET BIT(16) + +#define REG_TG_SEN_MODE 0x0700 +#define TG_CMOS_RDY_SEL BIT(14) +#define TG_SEN_MODE_CMOS_EN BIT(0) +#define TG_VFDATA_EN BIT(0) +#define TG_TG_FULL_SEL BIT(15) +#define TG_STAGGER_EN BIT(22) + +#define REG_TG_VF_CON 0x0704 +#define REG_TG_SEN_GRAB_PXL 0x0708 +#define REG_TG_SEN_GRAB_LIN 0x070C +#define REG_TG_PATH_CFG 0x0710 +#define TG_DB_LOAD_DIS BIT(8) +#define TG_SUB_SOF_SRC_SEL_0 BIT(20) +#define TG_SUB_SOF_SRC_SEL_1 BIT(21) + +#define REG_TG_INTER_ST 0x073C +/* use this MASK to extract TG_CAM_CS from TG_INTER_ST */ +#define TG_CAM_CS_MASK 0x3f00 +#define TG_IDLE_ST BIT(8) + +#define REG_TG_FRMSIZE_ST 0x0738 +#define REG_TG_DCIF_CTL 0x075C +#define TG_DCIF_EN BIT(16) + +#define REG_TG_FRMSIZE_ST_R 0x076C +#define REG_TG_TIME_STAMP 0x0778 +#define REG_TG_TIME_STAMP_CNT 0x077C + +/* tg flash */ +#define REG_TG_XENON_FLASH_CTL 0x0780 +#define REG_TG_XENON_FLASH_OFFSET 0x0784 +#define REG_TG_XENON_FLASH_HIGH_WIDTH 0x0788 +#define REG_TG_XENON_FLASH_LOW_WIDTH 0x078C +#define REG_TG_IR_FLASH_CTL 0x0798 +#define REG_TG_IR_FLASH_OFFSET 0x079C +#define REG_TG_IR_FLASH_HIGH_WIDTH 0x07A0 +#define REG_TG_IR_FLASH_LOW_WIDTH 0x07A4 + +/* for raw & yuv's dma top base */ +#define CAMDMATOP_BASE 0x4000 + +#define REG_DMA_SOFT_RST_STAT 0x4068 +#define REG_DMA_SOFT_RST_STAT2 0x406C +#define REG_DMA_DBG_CHASING_STATUS 0x4098 +#define REG_DMA_DBG_CHASING_STATUS2 0x409c + +#define RAWI_R2_SMI_REQ_ST BIT(0) +#define RAWI_R3_SMI_REQ_ST BIT(16) +#define RAWI_R5_SMI_REQ_ST BIT(16) + +#define RST_STAT_RAWI_R2 BIT(0) +#define RST_STAT_RAWI_R3 BIT(2) +#define RST_STAT_RAWI_R5 BIT(5) +/* use spare register FH_SPARE_5 */ +#define REG_FRAME_SEQ_NUM 0x4994 + +#define REG_CAMCTL_FBC_SEL 0x00A0 +#define REG_CAMCTL_FBC_RCNT_INC 0x00A4 + +#define CAMCTL_IMGO_R1_RCNT_INC BIT(0) +#define CAMCTL_CQ_THR0_DONE_ST BIT(0) +#define CAMCTL_CQ_THRSUB_DONE_EN BIT(10) +#define CTL_CQ_THR0_START BIT(0) + +/* CAMSYS_RAW 0x1a03 */ +#define OFFSET_OBC_R1_R_SUM_L 0x1178 +#define OFFSET_OBC_R1_R_SUM_H 0x117c +#define OFFSET_OBC_R1_B_SUM_L 0x1180 +#define OFFSET_OBC_R1_B_SUM_H 0x1184 +#define OFFSET_OBC_R1_GR_SUM_L 0x1188 +#define OFFSET_OBC_R1_GR_SUM_H 0x118c +#define OFFSET_OBC_R1_GB_SUM_L 0x1190 +#define OFFSET_OBC_R1_GB_SUM_H 0x1194 +#define OFFSET_OBC_R1_ACT_WIN_X 0x1198 +#define OFFSET_OBC_R1_ACT_WIN_Y 0x119c + +#define OFFSET_OBC_R2_R_SUM_L 0x1438 +#define OFFSET_OBC_R2_R_SUM_H 0x143c +#define OFFSET_OBC_R2_B_SUM_L 0x1440 +#define OFFSET_OBC_R2_B_SUM_H 0x1444 +#define OFFSET_OBC_R2_GR_SUM_L 0x1448 +#define OFFSET_OBC_R2_GR_SUM_H 0x144c +#define OFFSET_OBC_R2_GB_SUM_L 0x1450 +#define OFFSET_OBC_R2_GB_SUM_H 0x1454 +#define OFFSET_OBC_R2_ACT_WIN_X 0x1458 +#define OFFSET_OBC_R2_ACT_WIN_Y 0x145c + +#define OFFSET_OBC_R3_R_SUM_L 0x16f8 +#define OFFSET_OBC_R3_R_SUM_H 0x16fc +#define OFFSET_OBC_R3_B_SUM_L 0x1700 +#define OFFSET_OBC_R3_B_SUM_H 0x1704 +#define OFFSET_OBC_R3_GR_SUM_L 0x1708 +#define OFFSET_OBC_R3_GR_SUM_H 0x170c +#define OFFSET_OBC_R3_GB_SUM_L 0x1710 +#define OFFSET_OBC_R3_GB_SUM_H 0x1714 +#define OFFSET_OBC_R3_ACT_WIN_X 0x1718 +#define OFFSET_OBC_R3_ACT_WIN_Y 0x171c + +#define REG_LTM_AE_DEBUG_B_MSB 0x23f0 +#define REG_LTM_AE_DEBUG_B_LSB 0x23f4 +#define REG_LTM_AE_DEBUG_GB_MSB 0x23f8 +#define REG_LTM_AE_DEBUG_GB_LSB 0x23fc +#define REG_LTM_AE_DEBUG_GR_MSB 0x2400 +#define REG_LTM_AE_DEBUG_GR_LSB 0x2404 +#define REG_LTM_AE_DEBUG_R_MSB 0x2408 +#define REG_LTM_AE_DEBUG_R_LSB 0x240c +#define REG_LTMS_ACT_WIN_X 0x2578 +#define REG_LTMS_ACT_WIN_Y 0x257c + +#define REG_AA_R_SUM_L 0x2a1c +#define REG_AA_R_SUM_H 0x2a20 +#define REG_AA_B_SUM_L 0x2a24 +#define REG_AA_B_SUM_H 0x2a28 +#define REG_AA_GR_SUM_L 0x2a2c +#define REG_AA_GR_SUM_H 0x2a30 +#define REG_AA_GB_SUM_L 0x2a34 +#define REG_AA_GB_SUM_H 0x2a30 +#define REG_AA_ACT_WIN_X 0x2a3c +#define REG_AA_ACT_WIN_Y 0x2a40 + +#define DMA_OFFSET_CON0 0x020 +#define DMA_OFFSET_CON1 0x024 +#define DMA_OFFSET_CON2 0x028 +#define DMA_OFFSET_CON3 0x02c +#define DMA_OFFSET_CON4 0x030 +#define DMA_OFFSET_ERR_STAT 0x034 + +#define DMA_OFFSET_SPECIAL_DCIF 0x03c +#define DC_CAMSV_STAGER_EN BIT(16) + +#define FBC_R1A_BASE 0x2c00 +#define FBC_R2A_BASE 0x3780 +#define REG_FBC_CTL1(base, idx) ((base) + (idx) * 8) +#define REG_FBC_CTL2(base, idx) ((base) + (idx) * 8 + 4) +#define WCNT_BIT_MASK 0xFF00 +#define CNT_BIT_MASK 0xFF0000 +#define TG_FULLSEL_BIT_MASK 0x8000 +/* ORIDMA */ +/* CAMSYS_RAW 0x1a03 */ +#define REG_IMGO_R1_BASE 0x4880 +#define REG_FHO_R1_BASE 0x4930 +#define REG_AAHO_R1_BASE 0x49e0 +#define REG_PDO_R1_BASE 0x4a90 +#define REG_AAO_R1_BASE 0x4a40 +#define REG_AFO_R1_BASE 0x4bf0 + +/* CAMSYS_YUV 0x1a05 */ +#define REG_YUVO_R1_BASE 0x4200 +#define REG_YUVBO_R1_BASE 0x42b0 +#define REG_YUVCO_R1_BASE 0x4360 +#define REG_YUVDO_R1_BASE 0x4410 +#define REG_YUVO_R3_BASE 0x44c0 +#define REG_YUVBO_R3_BASE 0x4570 +#define REG_YUVCO_R3_BASE 0x4620 +#define REG_YUVDO_R3_BASE 0x46D0 + +/* ULCDMA */ +/* CAMSYS_RAW 0x1603 */ +#define REG_LTMSO_R1_BASE 0x4ce0 +#define REG_TSFSO_R1_BASE 0x4ca0 +#define REG_TSFSO_R2_BASE 0x4de0 +#define REG_FLKO_R1_BASE 0x4d20 +#define REG_UFEO_R1_BASE 0x4d60 + +/* CAMSYS_YUV 0x1605 */ +#define REG_YUVO_R2_BASE 0x4780 +#define REG_YUVBO_R2_BASE 0x47c0 +#define REG_YUVO_R4_BASE 0x4800 +#define REG_YUVBO_R4_BASE 0x4840 +#define REG_YUVO_R5_BASE 0x4c00 +#define REG_YUVBO_R5_BASE 0x4c40 +#define REG_RZH1N2TO_R1_BASE 0x4880 +#define REG_RZH1N2TBO_R1_BASE 0x48c0 +#define REG_RZH1N2TO_R2_BASE 0x4900 +#define REG_RZH1N2TO_R3_BASE 0x4940 +#define REG_RZH1N2TBO_R3_BASE 0x4980 +#define REG_DRZS4NO_R1_BASE 0x49c0 +#define REG_DRZS4NO_R2_BASE 0x4a00 +#define REG_DRZS4NO_R3_BASE 0x4a40 +#define REG_ACTSO_R1_BASE 0x4ac0 +#define REG_TNCSO_R1_BASE 0x4b00 +#define REG_TNCSBO_R1_BASE 0x4b40 +#define REG_TNCSHO_R1_BASE 0x4b80 +#define REG_TNCSYO_R1_BASE 0x4bc0 + +/* CAMSYS_RAW 0x1a03 */ +#define REG_RAWI_R2_BASE 0x4100 +#define REG_RAWI_R2_BASE_MSB 0x4104 +#define REG_UFDI_R2_BASE 0x4170 +#define REG_RAWI_R3_BASE 0x41e0 +#define REG_RAWI_R3_BASE_MSB 0x41e4 +#define REG_UFDI_R3_BASE 0x4250 +#define REG_CQI_R1_BASE 0x4410 +#define REG_CQI_R1_BASE_MSB 0x4414 +#define REG_CQI_R2_BASE 0x4480 +#define REG_CQI_R2_BASE_MSB 0x4484 +#define REG_CQI_R3_BASE 0x44f0 +#define REG_CQI_R3_BASE_MSB 0x44f4 +#define REG_CQI_R4_BASE 0x4560 +#define REG_CQI_R4_BASE_MSB 0x4564 +#define REG_LSCI_R1_BASE 0x45d0 +#define REG_BPCI_R1_BASE 0x4640 +#define REG_BPCI_R2_BASE 0x4680 +#define REG_BPCI_R3_BASE 0x46c0 +#define REG_PDI_R1_BASE 0x4700 +#define REG_AAI_R1_BASE 0x4780 +#define REG_CACI_R1_BASE 0x47c0 +#define REG_RAWI_R5_BASE 0x4330 +#define REG_RAWI_R6_BASE 0x4800 + +#endif /* _CAM_REGS_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: 13828187 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 61991CF0457 for ; Wed, 9 Oct 2024 11:23: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=feYTh5N/CZvxiWWNxiO80BwiDZSBYicbkLOe9DUTMm0=; b=wAYe0z5u2COlgzUmKxK8s5QLja djbV3Qr05Y66NDYrQQB0wlDYja+B3LXhGUiZrXb0dhRhGpRQSLrxC3j8XBsJl1nTbKubSneAjhpde OblXrHndyW9S9sfrRkWXbXFsaSN+3z+Dsqy+rAnmHmCRXPPJ7cW7lnh6uGzn8kZpG1TlHLdafNabj WYatG6Fo/L1+r6wKP+++XvxRXCDsjEB5ETpBhz0Ld7+9nAxetqF2sAIEmxTUHSdm1fD02rt6bGdCM mSx7heMNnxzEpZUi8Mcsuiqjo4k7tg87aArXXZgcNhGyBvPNzStpeaO7avh8fAiZHLRGzeR98ozJm avynONLQ==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUmZ-000000092oY-02sU; Wed, 09 Oct 2024 11:23:07 +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 1syUgP-000000091Pd-3Nf1 for linux-mediatek@bombadil.infradead.org; Wed, 09 Oct 2024 11:16:46 +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 1syUgK-00000004v7l-1k2f for linux-mediatek@lists.infradead.org; Wed, 09 Oct 2024 11:16:44 +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_121642_221069_92763E24 X-CRM114-Status: GOOD ( 27.50 ) X-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=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:49 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: 13828188 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 E011ACF0454 for ; Wed, 9 Oct 2024 11:23:06 +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=8WnBIzf6vDW1wcLaoyU3ovzHi/IOQz093KVsB/jZhz4=; b=r3uPTOJUcVWIB8cM+ZWRUGseBJ LtPW/ymHoyXcav/wMUV6qCi/IAaNzl2cabqldtDTufCFqc4f7N1tKug+EUGZeQ5WQMqcJjg92JIKF ybT5Y4xG3CNwuRHg8WglLwS59BLmZT5+AvlfiEckO7l633pcrD+6VGASJHbfvXa96DSXGYKqnOhOr DGyqfKhoooq24mw+s5yex1q2zwidmx4bp7HtmcRZ3C/GKKsuIVp2yUaEybt64kzLMrTJLw+rEsrwg NFIbqVvCvcqJCqLETG8CAeQBpGFQ72hZ/BME1Ku/mfy7RcZYZBZR82bbgUi5Rmv0oJkaQrVE0lXVZ xcWoCTog==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUmX-000000092nQ-2ovB; 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-000000091Oh-2PKu for linux-mediatek@bombadil.infradead.org; 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=8WnBIzf6vDW1wcLaoyU3ovzHi/IOQz093KVsB/jZhz4=; b=OwSmYFTwJR0bTQx9E9bKoAB6T/ ac93f5Vggn0WbY+kPcvLhCz4PlrXVBPDujwPWq5xTYygYGkHj5JGUlalqJ/tg+f+MiATWt7xKtL9i YwEk+xc3srCSCF+n2jmI2BpnnHJsFVtjWC/Ww2v6+1N4kbKdx8yjsP8Cp+jLKcnYPlfvHl6A9/uRi TI+EGh7bHtQXoMNx2CYHCjoO4pp+PyZ5tqHMIKqILO5OYVBnAJSHnuPSFuiht0aHYP13OvTrA5pIM WfQjEe9Oa/sj6yr/fXVELu8Gsixw5FzGWP03eYyvKBBVnzjuyQAf9MXLRSNXZvfOnK9lCAyJ0MHyK 1WooFNAg==; Received: from mailgw01.mediatek.com ([216.200.240.184]) by desiato.infradead.org with esmtps (Exim 4.98 #2 (Red Hat Linux)) id 1syUgG-00000004v7c-2QTx for linux-mediatek@lists.infradead.org; Wed, 09 Oct 2024 11:16:42 +0000 X-UUID: e384456a862f11efb3adad29d29602c1-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=8WnBIzf6vDW1wcLaoyU3ovzHi/IOQz093KVsB/jZhz4=; b=agwaDnYJjiR3QmQI/0aEwzhYEUvNCYXoXEcEM349HfIih+wWM7dSrA6qE2aXZo6yyNKWMI+sYMwlYAAKNgNPiYvyXpwSrlgX48yuDYHr3GxDWHHt0YmHoMYdPgxVyXNk/4QrBxS/Hb41p81SKxhy/qPPF5lphXwIVrnkb7JYbzY=; X-CID-P-RULE: Release_Ham X-CID-O-INFO: VERSION:1.1.41,REQID:fe29c0e5-4cd3-4d79-9928-593c1a55aa17,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:f053fe64-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: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: e384456a862f11efb3adad29d29602c1-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 1159768206; Wed, 09 Oct 2024 04:16:11 -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:09 -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: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 08/10] media: platform: mediatek: add isp_7x state ctrl Date: Wed, 9 Oct 2024 19:15:49 +0800 Message-ID: <20241009111551.27052-9-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-BeenThere: linux-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=archiver.kernel.org@lists.infradead.org Introduces state management and debugging mechanisms for the MediaTek ISP7.x camsys platform. State management establishes control over ISP operations and events, defining distinct states for request handling, sensor control, and frame synchronization, ensuring event processing. The debugging mechanism ensures stable operation and timely data collection during anomalies. Signed-off-by: Shu-hsiang Yang --- .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c | 1797 +++++++++++++++++ .../mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h | 140 ++ .../isp/isp_7x/camsys/mtk_cam-debug.c | 1271 ++++++++++++ .../isp/isp_7x/camsys/mtk_cam-debug.h | 273 +++ 4 files changed, 3481 insertions(+) create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.c create mode 100644 drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.h diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c new file mode 100644 index 000000000000..82173adb50f8 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.c @@ -0,0 +1,1797 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#include +#include +#include +#include + +#include +#include + +#include "mtk_cam.h" +#include "mtk_cam-feature.h" +#include "mtk_cam-ctrl.h" +#include "mtk_cam-debug.h" +#include "mtk_cam-pool.h" +#include "mtk_cam-raw.h" + +#include "mtk_cam-regs-mt8188.h" + +#include "mtk_camera-v4l2-controls.h" + +#define SENSOR_SET_DEADLINE_MS 18 +#define SENSOR_SET_RESERVED_MS 7 +#define SENSOR_SET_DEADLINE_MS_60FPS 6 +#define SENSOR_SET_RESERVED_MS_60FPS 6 +#define STATE_NUM_AT_SOF 3 +#define INITIAL_DROP_FRAME_CNT 1 + +enum MTK_CAMSYS_STATE_RESULT { + STATE_RESULT_TRIGGER_CQ = 0, + STATE_RESULT_PASS_CQ_INIT, + STATE_RESULT_PASS_CQ_SW_DELAY, + STATE_RESULT_PASS_CQ_SCQ_DELAY, + STATE_RESULT_PASS_CQ_HW_DELAY, +}; + +void state_transition(struct mtk_camsys_ctrl_state *state_entry, + enum MTK_CAMSYS_STATE_IDX from, + enum MTK_CAMSYS_STATE_IDX to) +{ + if (state_entry->estate == from) + state_entry->estate = to; +} + +static void mtk_cam_event_eos(struct mtk_raw_pipeline *pipeline) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_EOS, + }; + v4l2_event_queue(pipeline->subdev.devnode, &event); +} + +static void mtk_cam_event_frame_sync(struct mtk_raw_pipeline *pipeline, + unsigned int frame_seq_no) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_FRAME_SYNC, + .u.frame_sync.frame_sequence = frame_seq_no, + }; + v4l2_event_queue(pipeline->subdev.devnode, &event); +} + +static void mtk_cam_event_request_drained(struct mtk_raw_pipeline *pipeline) +{ + struct v4l2_event event = { + .type = V4L2_EVENT_REQUEST_DRAINED, + }; + v4l2_event_queue(pipeline->subdev.devnode, &event); +} + +static bool mtk_cam_request_drained(struct mtk_camsys_sensor_ctrl *sensor_ctrl) +{ + struct mtk_cam_ctx *ctx = sensor_ctrl->ctx; + int sensor_seq_no_next = + atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1; + int res = 0; + + if (sensor_seq_no_next <= atomic_read(&ctx->enqueued_frame_seq_no)) + res = 1; + /* Send V4L2_EVENT_REQUEST_DRAINED event */ + if (res == 0) { + mtk_cam_event_request_drained(ctx->pipe); + dev_dbg(ctx->cam->dev, "request_drained:(%d)\n", + sensor_seq_no_next); + } + return (res == 0); +} + +static bool mtk_cam_req_frame_sync_start(struct mtk_cam_request *req) +{ + /* All ctx with sensor is in ready state */ + struct mtk_cam_device *cam = + container_of(req->req.mdev, struct mtk_cam_device, media_dev); + struct mtk_cam_ctx *ctx; + struct mtk_cam_ctx *sync_ctx[MTKCAM_SUBDEV_MAX]; + int i; + u32 ctx_cnt = 0, synced_cnt = 0; + bool ret = false; + + /* pick out the used ctxs */ + for (i = 0; i < cam->max_stream_num; i++) { + if (!(1 << i & req->ctx_used)) + continue; + + sync_ctx[ctx_cnt] = &cam->ctxs[i]; + ctx_cnt++; + } + + mutex_lock(&req->fs.op_lock); + if (ctx_cnt > 1) { + /* multi sensor case */ + req->fs.on_cnt++; + /* not first time */ + if (req->fs.on_cnt != 1) + goto EXIT; + + for (i = 0; i < ctx_cnt; i++) { + ctx = sync_ctx[i]; + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + spin_unlock(&ctx->streaming_lock); + dev_info(cam->dev, + "%s: ctx(%d): is streamed off\n", + __func__, ctx->stream_id); + continue; + } + spin_unlock(&ctx->streaming_lock); + + /* update sensor frame sync */ + if (ctx->synced) + synced_cnt++; + } + + /* + * the prepared sensor is no enough, skip + * frame sync set failed or stream off + */ + if (synced_cnt < 2) { + mtk_cam_fs_reset(&req->fs); + dev_info(cam->dev, "%s:%s: sensor is not ready\n", + __func__, req->req.debug_str); + goto EXIT; + } + + dev_dbg(cam->dev, "%s:%s:fs_sync_frame(1): ctxs: 0x%x\n", + __func__, req->req.debug_str, req->ctx_used); + + ret = true; + goto EXIT; + } + /* single sensor case: unsupported sensor hardware sync */ + +EXIT: + dev_dbg(cam->dev, "%s:%s:target/on/off(%d/%d/%d)\n", __func__, + req->req.debug_str, req->fs.target, req->fs.on_cnt, + req->fs.off_cnt); + mutex_unlock(&req->fs.op_lock); + return ret; +} + +static bool mtk_cam_req_frame_sync_end(struct mtk_cam_request *req) +{ + /* All ctx with sensor is not in ready state */ + struct mtk_cam_device *cam = + container_of(req->req.mdev, struct mtk_cam_device, media_dev); + bool ret = false; + + mutex_lock(&req->fs.op_lock); + if (req->fs.target && req->fs.on_cnt) { + /* check fs on */ + req->fs.off_cnt++; + if (req->fs.on_cnt != req->fs.target || + req->fs.off_cnt != req->fs.target) { + /* not the last */ + goto EXIT; + } + dev_dbg(cam->dev, + "%s:%s:fs_sync_frame(0): ctxs: 0x%x\n", + __func__, req->req.debug_str, req->ctx_used); + ret = true; + goto EXIT; + } +EXIT: + dev_dbg(cam->dev, "%s:%s:target/on/off(%d/%d/%d)\n", __func__, + req->req.debug_str, req->fs.target, req->fs.on_cnt, + req->fs.off_cnt); + mutex_unlock(&req->fs.op_lock); + return ret; +} + +static void mtk_cam_stream_on(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx) +{ + spin_lock(&ctx->streaming_lock); + if (ctx->streaming) + mtk_cam_raw_stream_on(raw_dev, 1); + + spin_unlock(&ctx->streaming_lock); +} + +static void mtk_cam_m2m_sensor_skip(struct mtk_cam_request_stream_data *data) +{ + struct mtk_cam_request *req = mtk_cam_s_data_get_req(data); + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(data); + + dev_dbg(ctx->cam->dev, + "%s:%s:ctx(%d):sensor ctrl skip frame_seq_no %d\n", + __func__, req->req.debug_str, + ctx->stream_id, data->frame_seq_no); + state_transition(&data->state, E_STATE_READY, E_STATE_SENSOR); + mtk_cam_complete_sensor_hdl(data); +} + +void mtk_cam_set_sensor_full(struct mtk_cam_request_stream_data *s_data, + struct mtk_camsys_sensor_ctrl *sensor_ctrl) +{ + struct mtk_cam_device *cam; + struct mtk_cam_ctx *ctx; + struct mtk_cam_request *req; + struct mtk_raw_device *raw_dev; + unsigned int time_after_sof = 0; + + /* EnQ this request's state element to state_list (STATE:READY) */ + spin_lock(&sensor_ctrl->camsys_state_lock); + list_add_tail(&s_data->state.state_element, + &sensor_ctrl->camsys_state_list); + atomic_set(&sensor_ctrl->sensor_request_seq_no, s_data->frame_seq_no); + spin_unlock(&sensor_ctrl->camsys_state_lock); + + if (mtk_cam_is_m2m(sensor_ctrl->ctx)) { + mtk_cam_m2m_sensor_skip(s_data); + return; + } + + /* sensor_worker task */ + ctx = mtk_cam_s_data_get_ctx(s_data); + cam = ctx->cam; + req = mtk_cam_s_data_get_req(s_data); + + dev_dbg(cam->dev, "%s:%s:ctx(%d) req(%d):sensor try set start\n", + __func__, req->req.debug_str, ctx->stream_id, s_data->frame_seq_no); + + if (ctx->used_raw_num && mtk_cam_req_frame_sync_start(req)) + dev_dbg(cam->dev, + "%s:%s:ctx(%d): sensor ctrl with frame sync - start\n", + __func__, req->req.debug_str, ctx->stream_id); + + /* + * request setup + * 1st frame sensor setting is treated like normal frame + * and is set with other settings like max fps. + * 2nd is special, only exposure is set. + */ + if (!mtk_cam_is_m2m(ctx)) { + if (s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN) { + v4l2_ctrl_request_setup(&req->req, + s_data->sensor->ctrl_handler); + time_after_sof = + div_u64(ktime_get_boottime_ns(), 1000000) - + ctx->sensor_ctrl.sof_time; + dev_dbg(cam->dev, + "[SOF+%dms] Sensor request:%d[ctx:%d] setup\n", + time_after_sof, s_data->frame_seq_no, + ctx->stream_id); + } + } + + state_transition(&s_data->state, E_STATE_READY, E_STATE_SENSOR); + + if (ctx->used_raw_num && mtk_cam_req_frame_sync_end(req)) + dev_dbg(cam->dev, + "%s:ctx(%d): sensor ctrl with frame sync - stop\n", + __func__, ctx->stream_id); + + if (ctx->used_raw_num) { + raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe); + if (raw_dev && atomic_read(&raw_dev->vf_en) == 0 && + ctx->sensor_ctrl.initial_cq_done == 1 && + s_data->frame_seq_no == 1) + mtk_cam_stream_on(raw_dev, ctx); + } + + dev_dbg(cam->dev, "%s:%s:ctx(%d)req(%d):sensor done at SOF+%dms\n", + __func__, req->req.debug_str, ctx->stream_id, + s_data->frame_seq_no, time_after_sof); + + mtk_cam_complete_sensor_hdl(s_data); +} + +static void mtk_cam_try_set_sensor(struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_cam_device *cam = ctx->cam; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_camsys_ctrl_state *state_entry; + struct mtk_cam_request *req; + int sensor_seq_no_next = + atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1; + int time_after_sof = div_u64(ktime_get_boottime_ns(), 1000000) - + ctx->sensor_ctrl.sof_time; + + /* for 1st unsync, sensor setting will be set at enque thread */ + if (ctx->used_raw_num) { + if (ctx->pipe->feature_active == 0 && sensor_seq_no_next <= 2) + return; + } else { + if (sensor_seq_no_next <= 2) + return; + } + + spin_lock(&sensor_ctrl->camsys_state_lock); + /* Check if previous state was without cq done */ + list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list, + state_element) { + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_entry); + if (req_stream_data->frame_seq_no == + atomic_read(&sensor_ctrl->sensor_request_seq_no)) { + if (state_entry->estate == E_STATE_CQ && + req_stream_data->frame_seq_no > INITIAL_DROP_FRAME_CNT) { + state_entry->estate = E_STATE_CQ_SCQ_DELAY; + spin_unlock(&sensor_ctrl->camsys_state_lock); + + dev_dbg(ctx->cam->dev, + "[%s] SCQ DELAY STATE at SOF+%dms\n", + __func__, time_after_sof); + return; + } else if (state_entry->estate == E_STATE_CAMMUX_OUTER_CFG) { + state_entry->estate = + E_STATE_CAMMUX_OUTER_CFG_DELAY; + spin_unlock(&sensor_ctrl->camsys_state_lock); + + dev_dbg(ctx->cam->dev, + "[%s] CAMMUX OUTTER CFG DELAY STATE\n", + __func__); + return; + } else if (state_entry->estate <= E_STATE_SENSOR) { + spin_unlock(&sensor_ctrl->camsys_state_lock); + + dev_dbg(ctx->cam->dev, + "[%s] wrong state:%d (sensor workqueue delay)\n", + __func__, state_entry->estate); + return; + } + } else if (req_stream_data->frame_seq_no == + atomic_read(&sensor_ctrl->sensor_request_seq_no) - 1) { + if (state_entry->estate < E_STATE_INNER) { + spin_unlock(&sensor_ctrl->camsys_state_lock); + + dev_dbg(ctx->cam->dev, + "[%s] req:%d isn't arrive inner at SOF+%dms\n", + __func__, req_stream_data->frame_seq_no, + time_after_sof); + return; + } + } + } + spin_unlock(&sensor_ctrl->camsys_state_lock); + + /** Frame sync: + * make sure the all ctxs of previous request are triggered + */ + req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, + sensor_seq_no_next - 1); + if (req_stream_data) { + req = mtk_cam_s_data_get_req(req_stream_data); + /* fs complete: fs.target <= off and on == off */ + if (!(req->fs.target <= req->fs.off_cnt && + req->fs.off_cnt == req->fs.on_cnt)) { + dev_info(ctx->cam->dev, + "[TimerIRQ] ctx:%d the fs of req(%s/%d) is not completed, target/on/off(%d/%d/%d)\n", + ctx->stream_id, req->req.debug_str, + sensor_seq_no_next - 1, req->fs.target, + req->fs.on_cnt, req->fs.off_cnt); + return; + } + } + + req_stream_data = + mtk_cam_get_req_s_data(ctx, ctx->stream_id, sensor_seq_no_next); + if (req_stream_data) { + req = mtk_cam_s_data_get_req(req_stream_data); + mtk_cam_set_sensor_full(req_stream_data, &ctx->sensor_ctrl); + + dev_dbg(cam->dev, + "%s:[TimerIRQ [SOF+%dms]:] ctx:%d, sensor_req_seq_no:%d\n", + __func__, time_after_sof, ctx->stream_id, + sensor_seq_no_next); + } else { + dev_dbg(cam->dev, + "%s:[TimerIRQ [SOF+%dms]] ctx:%d, empty req_queue, sensor_req_seq_no:%d\n", + __func__, time_after_sof, ctx->stream_id, + atomic_read(&sensor_ctrl->sensor_request_seq_no)); + } +} + +static void mtk_cam_sensor_worker_in_sensorctrl(struct kthread_work *work) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = + container_of(work, struct mtk_camsys_sensor_ctrl, work); + struct mtk_cam_ctx *ctx; + + ctx = sensor_ctrl->ctx; + mtk_cam_try_set_sensor(ctx); +} + +bool mtk_cam_submit_kwork_in_sensorctrl(struct kthread_worker *worker, + struct mtk_camsys_sensor_ctrl *sensor_ctrl) +{ + if (!worker) { + pr_info("%s: not queue work since kthread_worker is null\n", + __func__); + + return false; + } + + return kthread_queue_work(worker, &sensor_ctrl->work); +} + +static enum hrtimer_restart sensor_set_handler(struct hrtimer *t) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = + container_of(t, struct mtk_camsys_sensor_ctrl, + sensor_deadline_timer); + + mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq, + sensor_ctrl); + + return HRTIMER_NORESTART; +} + +static enum hrtimer_restart sensor_deadline_timer_handler(struct hrtimer *t) +{ + unsigned int enq_no, sen_no; + struct mtk_camsys_sensor_ctrl *sensor_ctrl = + container_of(t, struct mtk_camsys_sensor_ctrl, + sensor_deadline_timer); + struct mtk_cam_ctx *ctx = sensor_ctrl->ctx; + struct mtk_cam_device *cam = ctx->cam; + ktime_t m_kt; + int time_after_sof = div_u64(ktime_get_boottime_ns(), 1000000) - + sensor_ctrl->sof_time; + bool drained_res = false; + + sensor_ctrl->sensor_deadline_timer.function = sensor_set_handler; + + m_kt = ktime_set(0, sensor_ctrl->timer_req_sensor * 1000000); + + if (ctx->used_raw_num) { + /* handle V4L2_EVENT_REQUEST_DRAINED event */ + drained_res = mtk_cam_request_drained(sensor_ctrl); + } + dev_dbg(cam->dev, + "[TimerIRQ [SOF+%dms]] ctx:%d, sensor_req_seq_no:%d\n", + time_after_sof, ctx->stream_id, + atomic_read(&sensor_ctrl->sensor_request_seq_no)); + if (drained_res == 0) { + sen_no = atomic_read(&sensor_ctrl->sensor_enq_seq_no); + enq_no = atomic_read(&ctx->enqueued_frame_seq_no); + if (enq_no == sen_no) { + mtk_cam_submit_kwork_in_sensorctrl(sensor_ctrl->sensorsetting_wq, + sensor_ctrl); + return HRTIMER_NORESTART; + } + dev_dbg(cam->dev, + "[TimerIRQ [SOF+%dms]] ctx:%d, enq:%d/sensor_enq:%d\n", + time_after_sof, ctx->stream_id, enq_no, sen_no); + } + /*using enque timing for sensor setting*/ + if (ctx->used_raw_num) { + if (ctx->pipe->feature_active == 0) { + int drained_seq_no = + atomic_read(&sensor_ctrl->sensor_request_seq_no) + 1; + atomic_set(&sensor_ctrl->last_drained_seq_no, drained_seq_no); + return HRTIMER_NORESTART; + } + } + hrtimer_forward_now(&sensor_ctrl->sensor_deadline_timer, m_kt); + + return HRTIMER_RESTART; +} + +static void mtk_cam_sof_timer_setup(struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + ktime_t m_kt; + int after_sof_ms = div_u64(ktime_get_boottime_ns(), 1000000) - + sensor_ctrl->sof_time; + + sensor_ctrl->sensor_deadline_timer.function = + sensor_deadline_timer_handler; + sensor_ctrl->ctx = ctx; + if (after_sof_ms < 0) + after_sof_ms = 0; + else if (after_sof_ms > sensor_ctrl->timer_req_event) + after_sof_ms = sensor_ctrl->timer_req_event - 1; + m_kt = ktime_set(0, sensor_ctrl->timer_req_event * 1000000 - + after_sof_ms * 1000000); + hrtimer_start(&sensor_ctrl->sensor_deadline_timer, m_kt, HRTIMER_MODE_REL); +} + +static void +mtk_cam_set_timestamp(struct mtk_cam_request_stream_data *stream_data, + u64 time_boot, + u64 time_mono) +{ + stream_data->timestamp = time_boot; + stream_data->timestamp_mono = time_mono; +} + +static int +mtk_camsys_raw_state_handle(struct mtk_raw_device *raw_dev, + struct mtk_camsys_sensor_ctrl *sensor_ctrl, + struct mtk_camsys_ctrl_state **current_state, + struct mtk_camsys_irq_info *irq_info) +{ + struct mtk_cam_ctx *ctx = sensor_ctrl->ctx; + struct mtk_camsys_ctrl_state *state_temp, *state_outer = NULL; + struct mtk_camsys_ctrl_state *state_inner = NULL; + struct mtk_camsys_ctrl_state *state_rec[STATE_NUM_AT_SOF]; + struct mtk_cam_request_stream_data *req_stream_data; + int frame_idx_inner = irq_info->frame_idx_inner; + int stateidx; + int que_cnt = 0; + int write_cnt; + u64 time_boot = ktime_get_boottime_ns(); + u64 time_mono = ktime_get_ns(); + int working_req_found = 0; + + /* List state-queue status*/ + spin_lock(&sensor_ctrl->camsys_state_lock); + list_for_each_entry(state_temp, &sensor_ctrl->camsys_state_list, + state_element) { + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp); + stateidx = atomic_read(&sensor_ctrl->sensor_request_seq_no) - + req_stream_data->frame_seq_no; + if (stateidx < STATE_NUM_AT_SOF && stateidx > -1) { + state_rec[stateidx] = state_temp; + if (stateidx == 0) + working_req_found = 1; + + /* Find outer state element */ + if (state_temp->estate == E_STATE_OUTER || + state_temp->estate == E_STATE_CAMMUX_OUTER || + state_temp->estate == E_STATE_OUTER_HW_DELAY) { + state_outer = state_temp; + mtk_cam_set_timestamp(req_stream_data, + time_boot, time_mono); + } + + /* Find inner state element request */ + if (state_temp->estate == E_STATE_INNER || + state_temp->estate == E_STATE_INNER_HW_DELAY) + state_inner = state_temp; + + dev_dbg(raw_dev->dev, + "[SOF] STATE_CHECK [N-%d] Req:%d / State:%d\n", + stateidx, req_stream_data->frame_seq_no, + state_rec[stateidx]->estate); + } + /* counter for state queue*/ + que_cnt++; + } + spin_unlock(&sensor_ctrl->camsys_state_lock); + + /* HW imcomplete case */ + if (state_inner) { + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_inner); + write_cnt = (atomic_read(&sensor_ctrl->isp_request_seq_no) / 256) + * 256 + irq_info->write_cnt; + + if (frame_idx_inner > atomic_read(&sensor_ctrl->isp_request_seq_no) || + atomic_read(&req_stream_data->frame_done_work.is_queued) == 1) { + dev_dbg_ratelimited(raw_dev->dev, + "[SOF] frame done work too late frames. req(%d),ts(%llu)\n", + req_stream_data->frame_seq_no, + irq_info->ts_ns); + } else if (write_cnt >= req_stream_data->frame_seq_no) { + dev_info_ratelimited(raw_dev->dev, + "[SOF] frame done reading lost %d frames. req(%d),ts(%llu)\n", + write_cnt - req_stream_data->frame_seq_no + 1, + req_stream_data->frame_seq_no, + irq_info->ts_ns); + mtk_cam_set_timestamp(req_stream_data, + time_boot - 1000, time_mono - 1000); + mtk_camsys_frame_done(ctx, write_cnt, ctx->stream_id); + } else if ((write_cnt >= req_stream_data->frame_seq_no - 1) && + irq_info->fbc_cnt == 0) { + dev_info_ratelimited(raw_dev->dev, + "[SOF] frame done reading lost frames. req(%d),ts(%llu)\n", + req_stream_data->frame_seq_no, irq_info->ts_ns); + mtk_cam_set_timestamp(req_stream_data, + time_boot - 1000, time_mono - 1000); + mtk_camsys_frame_done(ctx, write_cnt + 1, ctx->stream_id); + } else { + state_transition(state_inner, + E_STATE_INNER, E_STATE_INNER_HW_DELAY); + if (state_outer) { + state_transition(state_outer, + E_STATE_OUTER, + E_STATE_OUTER_HW_DELAY); + state_transition(state_outer, + E_STATE_CAMMUX_OUTER, + E_STATE_OUTER_HW_DELAY); + } + dev_info_ratelimited(raw_dev->dev, + "[SOF] HW_IMCOMPLETE state cnt(%d,%d),req(%d),ts(%llu)\n", + write_cnt, irq_info->write_cnt, + req_stream_data->frame_seq_no, + irq_info->ts_ns); + return STATE_RESULT_PASS_CQ_HW_DELAY; + } + } + + /* Transit outer state to inner state */ + if (state_outer && sensor_ctrl->sensorsetting_wq) { + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_outer); + if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 && + req_stream_data->frame_seq_no > frame_idx_inner) { + dev_info(raw_dev->dev, + "[SOF-noDBLOAD] HW delay outer_no:%d, inner_idx:%d <= processing_idx:%d,ts:%llu\n", + req_stream_data->frame_seq_no, frame_idx_inner, + atomic_read(&sensor_ctrl->isp_request_seq_no), + irq_info->ts_ns); + return STATE_RESULT_PASS_CQ_HW_DELAY; + } + + if (atomic_read(&sensor_ctrl->initial_drop_frame_cnt) == 0 && + req_stream_data->frame_seq_no == frame_idx_inner) { + if (frame_idx_inner > + atomic_read(&sensor_ctrl->isp_request_seq_no)) { + state_transition(state_outer, + E_STATE_OUTER_HW_DELAY, + E_STATE_INNER_HW_DELAY); + state_transition(state_outer, + E_STATE_OUTER, + E_STATE_INNER); + state_transition(state_outer, + E_STATE_CAMMUX_OUTER, + E_STATE_INNER); + atomic_set(&sensor_ctrl->isp_request_seq_no, frame_idx_inner); + dev_dbg(raw_dev->dev, + "[SOF-DBLOAD] frame_seq_no:%d, OUTER->INNER state:%d,ts:%llu\n", + req_stream_data->frame_seq_no, + state_outer->estate, irq_info->ts_ns); + } + } + } + + /* Trigger high resolution timer to try sensor setting */ + sensor_ctrl->sof_time = div_u64(irq_info->ts_ns, 1000000); + mtk_cam_sof_timer_setup(ctx); + + if (que_cnt > 1 && state_rec[1]) { + state_temp = state_rec[1]; + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_temp); + if (req_stream_data->frame_seq_no == 1) + state_transition(state_temp, + E_STATE_SENSOR, E_STATE_INNER); + } + + if (que_cnt > 0) { + if (working_req_found && state_rec[0]) { + if (state_rec[0]->estate == E_STATE_READY) { + dev_info(raw_dev->dev, "[SOF] sensor delay ts:%llu\n", + irq_info->ts_ns); + req_stream_data = + mtk_cam_ctrl_state_to_req_s_data(state_rec[0]); + req_stream_data->flags |= + MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_DELAYED; + } + + if (state_rec[0]->estate == E_STATE_SENINF) + dev_info(raw_dev->dev, "[SOF] sensor switch delay\n"); + + /* CQ triggering judgment*/ + if (state_rec[0]->estate == E_STATE_SENSOR) { + *current_state = state_rec[0]; + return STATE_RESULT_TRIGGER_CQ; + } + /* last SCQ triggering delay judgment*/ + if (state_rec[0]->estate == E_STATE_CQ_SCQ_DELAY) { + state_transition(state_rec[0], + E_STATE_CQ_SCQ_DELAY, + E_STATE_OUTER); + dev_info(raw_dev->dev, "[SOF] SCQ_DELAY state:%d ts:%llu\n", + state_rec[0]->estate, irq_info->ts_ns); + return STATE_RESULT_PASS_CQ_SCQ_DELAY; + } + } else { + dev_dbg(raw_dev->dev, "[SOF] working request not found\n"); + } + } + return STATE_RESULT_PASS_CQ_SW_DELAY; +} + +static void mtk_cam_handle_m2m_frame_done(struct mtk_cam_ctx *ctx, + unsigned int dequeued_frame_seq_no, + unsigned int pipe_id) +{ + struct mtk_raw_device *raw_dev; + struct mtk_camsys_ctrl_state *state_temp, *state_inner = NULL; + struct mtk_camsys_ctrl_state *state_sensor = NULL; + struct mtk_cam_request *req; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_working_buf_entry *buf_entry; + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + dma_addr_t base_addr; + u32 que_cnt = 0; + u64 time_boot = ktime_get_boottime_ns(); + u64 time_mono = ktime_get_ns(); + u32 dequeue_cnt; + + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + dev_dbg(ctx->cam->dev, + "%s: skip frame done for stream off ctx:%d\n", + __func__, ctx->stream_id); + spin_unlock(&ctx->streaming_lock); + return; + } + spin_unlock(&ctx->streaming_lock); + + raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe); + if (!raw_dev) { + dev_err(ctx->cam->dev, "%s: not found raw device\n", __func__); + return; + } + mtk_cam_event_frame_sync(ctx->pipe, dequeued_frame_seq_no); + + /* No SOF in M2M, so we update ctx's dequeued_frame_seq_no here */ + ctx->dequeued_frame_seq_no = dequeued_frame_seq_no; + + /* List state-queue status*/ + spin_lock(&sensor_ctrl->camsys_state_lock); + list_for_each_entry(state_temp, &sensor_ctrl->camsys_state_list, + state_element) { + req = mtk_cam_ctrl_state_get_req(state_temp); + req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + + if (state_temp->estate == E_STATE_INNER && !state_inner) + state_inner = state_temp; + else if (state_temp->estate == E_STATE_SENSOR && !state_sensor) + state_sensor = state_temp; + /* counter for state queue*/ + que_cnt++; + } + spin_unlock(&sensor_ctrl->camsys_state_lock); + + /* Transit inner state to done state */ + if (state_inner) { + req = mtk_cam_ctrl_state_get_req(state_inner); + req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + + dev_dbg(raw_dev->dev, + "[M2M P1 Don] req_stream_data->frame_seq_no:%d dequeued_frame_seq_no:%d\n", + req_stream_data->frame_seq_no, dequeued_frame_seq_no); + + if (req_stream_data->frame_seq_no == dequeued_frame_seq_no) { + state_transition(state_inner, + E_STATE_INNER, E_STATE_DONE_NORMAL); + atomic_set(&sensor_ctrl->isp_request_seq_no, dequeued_frame_seq_no); + dev_dbg(raw_dev->dev, + "[Frame done] frame_seq_no:%d, INNER->DONE_NORMAL state:%d\n", + req_stream_data->frame_seq_no, state_inner->estate); + } + } + + req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, + dequeued_frame_seq_no); + dequeue_cnt = mtk_cam_dequeue_req_frame(ctx, dequeued_frame_seq_no, + ctx->stream_id); + complete(&ctx->m2m_complete); + + /* apply next composed buffer */ + spin_lock(&ctx->composed_buffer_list.lock); + dev_dbg(raw_dev->dev, + "[M2M check next action] que_cnt:%d composed_buffer_list.cnt:%d\n", + que_cnt, ctx->composed_buffer_list.cnt); + + if (list_empty(&ctx->composed_buffer_list.list)) { + dev_info(raw_dev->dev, + "[M2M] no buffer, cq_num:%d, frame_seq:%d, composed_buffer_list.cnt :%d\n", + ctx->composed_frame_seq_no, dequeued_frame_seq_no, + ctx->composed_buffer_list.cnt); + spin_unlock(&ctx->composed_buffer_list.lock); + } else { + buf_entry = list_first_entry(&ctx->composed_buffer_list.list, + struct mtk_cam_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + ctx->composed_buffer_list.cnt--; + spin_unlock(&ctx->composed_buffer_list.lock); + spin_lock(&ctx->processing_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, + &ctx->processing_buffer_list.list); + ctx->processing_buffer_list.cnt++; + + dev_dbg(raw_dev->dev, + "[M2M P1 Don] ctx->processing_buffer_list.cnt:%d\n", + ctx->processing_buffer_list.cnt); + + spin_unlock(&ctx->processing_buffer_list.lock); + + base_addr = buf_entry->buffer.iova; + + if (!state_sensor) { + dev_info(raw_dev->dev, + "[M2M P1 Don] Invalid state_sensor\n"); + return; + } + + req = mtk_cam_ctrl_state_get_req(state_sensor); + req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + req_stream_data->timestamp = time_boot; + req_stream_data->timestamp_mono = time_mono; + + mtk_cam_raw_apply_cq(raw_dev, base_addr, + buf_entry->cq_desc_size, + buf_entry->cq_desc_offset, + buf_entry->sub_cq_desc_size, + buf_entry->sub_cq_desc_offset); + /* Transit state from Sensor -> CQ */ + if (ctx->sensor) { + state_transition(state_sensor, + E_STATE_SENSOR, E_STATE_CQ); + + dev_dbg(raw_dev->dev, + "M2M apply_cq [ctx:%d-#%d], CQ-%d, composed:%d, cq_addr:0x%pad\n", + ctx->stream_id, dequeued_frame_seq_no, + req_stream_data->frame_seq_no, + ctx->composed_frame_seq_no, &base_addr); + + dev_dbg(raw_dev->dev, + "M2M apply_cq: composed_buffer_list.cnt:%d time:%lld, monotime:%lld\n", + ctx->composed_buffer_list.cnt, + req_stream_data->timestamp, + req_stream_data->timestamp_mono); + } + } + + if (dequeue_cnt) { + mutex_lock(&ctx->cam->queue_lock); + mtk_cam_dev_req_try_queue(ctx->cam); + mutex_unlock(&ctx->cam->queue_lock); + } +} + +static void mtk_camsys_raw_frame_start(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx, + struct mtk_camsys_irq_info *irq_info) +{ + unsigned int dequeued_frame_seq_no = irq_info->frame_idx_inner; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_cam_working_buf_entry *buf_entry; + struct mtk_camsys_ctrl_state *current_state; + struct mtk_cam_buffer *buf; + + dma_addr_t base_addr; + enum MTK_CAMSYS_STATE_RESULT state_handle_ret; + + /* touch watchdog*/ + if (watchdog_scenario(ctx)) + mtk_ctx_watchdog_kick(ctx); + /* inner register dequeue number */ + ctx->dequeued_frame_seq_no = dequeued_frame_seq_no; + /* Send V4L2_EVENT_FRAME_SYNC event */ + mtk_cam_event_frame_sync(ctx->pipe, dequeued_frame_seq_no); + + /* Handle directly enque buffers */ + spin_lock(&ctx->cam->dma_processing_lock); + list_for_each_entry(buf, &ctx->cam->dma_processing, list) { + if (buf->state.estate == E_BUF_STATE_COMPOSED) { + spin_unlock(&ctx->cam->dma_processing_lock); + goto apply_cq; + } + } + spin_unlock(&ctx->cam->dma_processing_lock); + buf = NULL; + current_state = NULL; + + /* Find request of this dequeued frame */ + req_stream_data = + mtk_cam_get_req_s_data(ctx, ctx->stream_id, dequeued_frame_seq_no); + /* Detect no frame done and trigger camsys dump for debugging */ + mtk_cam_debug_detect_dequeue_failed(req_stream_data, 30, irq_info, raw_dev); + if (ctx->sensor) { + state_handle_ret = + mtk_camsys_raw_state_handle(raw_dev, sensor_ctrl, + ¤t_state, irq_info); + + if (state_handle_ret != STATE_RESULT_TRIGGER_CQ) { + dev_dbg(raw_dev->dev, "[SOF] CQ drop s:%d deq:%d\n", + state_handle_ret, dequeued_frame_seq_no); + return; + } + } + +apply_cq: + /* Update CQ base address if needed */ + if (ctx->composed_frame_seq_no <= dequeued_frame_seq_no) { + dev_info_ratelimited(raw_dev->dev, + "SOF[ctx:%d-#%d], CQ isn't updated [composed_frame_deq (%d) ts:%llu]\n", + ctx->stream_id, dequeued_frame_seq_no, + ctx->composed_frame_seq_no, irq_info->ts_ns); + return; + } + /* apply next composed buffer */ + spin_lock(&ctx->composed_buffer_list.lock); + if (list_empty(&ctx->composed_buffer_list.list)) { + dev_info_ratelimited(raw_dev->dev, + "SOF_INT_ST, no buffer update, cq_num:%d, frame_seq:%d, ts:%llu\n", + ctx->composed_frame_seq_no, + dequeued_frame_seq_no, irq_info->ts_ns); + spin_unlock(&ctx->composed_buffer_list.lock); + } else { + buf_entry = list_first_entry(&ctx->composed_buffer_list.list, + struct mtk_cam_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + ctx->composed_buffer_list.cnt--; + spin_unlock(&ctx->composed_buffer_list.lock); + spin_lock(&ctx->processing_buffer_list.lock); + list_add_tail(&buf_entry->list_entry, + &ctx->processing_buffer_list.list); + ctx->processing_buffer_list.cnt++; + spin_unlock(&ctx->processing_buffer_list.lock); + base_addr = buf_entry->buffer.iova; + mtk_cam_raw_apply_cq(raw_dev, base_addr, + buf_entry->cq_desc_size, + buf_entry->cq_desc_offset, + buf_entry->sub_cq_desc_size, + buf_entry->sub_cq_desc_offset); + + if (buf) { + buf->state.estate = E_BUF_STATE_CQ; + return; + } + + /* Transit state from Sensor -> CQ */ + if (ctx->sensor) { + /* req_stream_data of req_cq*/ + req_stream_data = + mtk_cam_ctrl_state_to_req_s_data(current_state); + state_transition(current_state, + E_STATE_SENSOR, E_STATE_CQ); + + dev_dbg(raw_dev->dev, + "SOF[ctx:%d-#%d], CQ-%d is update, composed:%d, cq_addr:0x%pad, time:%lld, monotime:%lld\n", + ctx->stream_id, dequeued_frame_seq_no, + req_stream_data->frame_seq_no, + ctx->composed_frame_seq_no, &base_addr, + req_stream_data->timestamp, + req_stream_data->timestamp_mono); + } + } +} + +static void mtk_camsys_raw_m2m_cq_done(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no_outer) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_camsys_ctrl_state *state_entry; + struct mtk_cam_request *req; + struct mtk_cam_request_stream_data *req_stream_data; + + if (frame_seq_no_outer == 1) + mtk_cam_raw_stream_on(raw_dev, 1); + + dev_dbg(raw_dev->dev, + "[M2M CQD] frame_seq_no_outer:%d composed_buffer_list.cnt:%d\n", + frame_seq_no_outer, ctx->composed_buffer_list.cnt); + + spin_lock(&sensor_ctrl->camsys_state_lock); + list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list, + state_element) { + req = mtk_cam_ctrl_state_get_req(state_entry); + req_stream_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + + if (req_stream_data->frame_seq_no == frame_seq_no_outer) { + if (frame_seq_no_outer > + atomic_read(&sensor_ctrl->isp_request_seq_no)) { + /** + * outer number is 1 more from last SOF's + * inner number + */ + state_transition(state_entry, + E_STATE_CQ, E_STATE_OUTER); + + dev_dbg(raw_dev->dev, + "[M2M CQD] req:%d, CQ->OUTER state:%d\n", + req_stream_data->frame_seq_no, + state_entry->estate); + } + } + } + spin_unlock(&sensor_ctrl->camsys_state_lock); +} + +static void mtk_camsys_raw_cq_done(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no_outer) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_camsys_ctrl_state *state_entry; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_buffer *buf; + + /* initial CQ done */ + if (raw_dev->sof_count == 0) { + sensor_ctrl->initial_cq_done = 1; + spin_lock(&ctx->cam->dma_processing_lock); + if (!list_empty(&ctx->cam->dma_processing)) { + buf = list_first_entry(&ctx->cam->dma_processing, + struct mtk_cam_buffer, list); + if (buf->state.estate == E_BUF_STATE_CQ) + buf->state.estate = E_BUF_STATE_OUTER; + spin_unlock(&ctx->cam->dma_processing_lock); + mtk_cam_stream_on(raw_dev, ctx); + return; + } + spin_unlock(&ctx->cam->dma_processing_lock); + + req_stream_data = mtk_cam_get_req_s_data(ctx, ctx->stream_id, 1); + if (!req_stream_data) { + dev_err(raw_dev->dev, + "Cannot find req stream data with stream_id:%d\n", + ctx->stream_id); + return; + } + if (req_stream_data->state.estate >= E_STATE_SENSOR || !ctx->sensor) { + mtk_cam_stream_on(raw_dev, ctx); + } else { + dev_dbg(raw_dev->dev, + "[CQD] 1st sensor not set yet, req:%d, state:%d\n", + req_stream_data->frame_seq_no, + req_stream_data->state.estate); + } + } + /* Legacy CQ done will be always happened at frame done */ + spin_lock(&sensor_ctrl->camsys_state_lock); + list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list, + state_element) { + req_stream_data = mtk_cam_ctrl_state_to_req_s_data(state_entry); + if (req_stream_data->frame_seq_no == frame_seq_no_outer) { + if (frame_seq_no_outer > + atomic_read(&sensor_ctrl->isp_request_seq_no)) { + /* + * outer number is 1 more from last SOF's + * inner number + */ + if (frame_seq_no_outer == 1) + state_entry->estate = E_STATE_OUTER; + state_transition(state_entry, + E_STATE_CQ, E_STATE_OUTER); + state_transition(state_entry, + E_STATE_CQ_SCQ_DELAY, E_STATE_OUTER); + state_transition(state_entry, + E_STATE_SENINF, E_STATE_OUTER); + + dev_dbg(raw_dev->dev, + "[CQD] req:%d, CQ->OUTER state:%d\n", + req_stream_data->frame_seq_no, + state_entry->estate); + } + } + } + spin_unlock(&sensor_ctrl->camsys_state_lock); +} + +static void mtk_camsys_raw_m2m_trigger(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no_outer) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_camsys_ctrl_state *state_entry; + struct mtk_cam_request *req; + struct mtk_cam_request_stream_data *req_stream_data; + bool triggered; + + if (!mtk_cam_is_m2m(ctx)) + return; + + mtk_cam_raw_trigger_rawi(raw_dev, ctx, -1); + + spin_lock(&sensor_ctrl->camsys_state_lock); + triggered = false; + + list_for_each_entry(state_entry, &sensor_ctrl->camsys_state_list, + state_element) { + int s_data_idx, s_data_num; + + req = mtk_cam_ctrl_state_get_req(state_entry); + s_data_num = req->p_data[ctx->stream_id].s_data_num; + + for (s_data_idx = 0; s_data_idx < s_data_num; s_data_idx++) { + req_stream_data = mtk_cam_req_get_s_data(req, + ctx->stream_id, + s_data_idx); + dev_dbg(raw_dev->dev, + "s_data_idx/s_data_num:%d/%d, req_stream_data->frame_seq_no:%d", + s_data_idx, s_data_num, + req_stream_data->frame_seq_no); + if (req_stream_data->frame_seq_no == frame_seq_no_outer) { + /** + * outer number is 1 more from last SOF's + * inner number + */ + atomic_set(&sensor_ctrl->isp_request_seq_no, frame_seq_no_outer); + state_transition(state_entry, + E_STATE_OUTER, E_STATE_INNER); + dev_dbg(raw_dev->dev, + "[SW Trigger] req:%d, M2M CQ->INNER state:%d frame_seq_no:%d\n", + req_stream_data->frame_seq_no, + state_entry->estate, + frame_seq_no_outer); + triggered = true; + break; + } + } + if (triggered) + break; + } + spin_unlock(&sensor_ctrl->camsys_state_lock); +} + +static bool +mtk_camsys_raw_prepare_frame_done(struct mtk_raw_device *raw_dev, + struct mtk_cam_ctx *ctx, + unsigned int dequeued_frame_seq_no) +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_camsys_ctrl_state *state_entry; + struct mtk_cam_request *state_req; + struct mtk_cam_request_stream_data *s_data; + + if (!ctx->sensor) { + dev_info(cam->dev, "%s: no sensor found in ctx:%d, req:%d", + __func__, ctx->stream_id, dequeued_frame_seq_no); + + return true; + } + + spin_lock(&camsys_sensor_ctrl->camsys_state_lock); + /** + * Find inner register number's request and transit to + * STATE_DONE_xxx + */ + list_for_each_entry(state_entry, &camsys_sensor_ctrl->camsys_state_list, + state_element) { + state_req = mtk_cam_ctrl_state_get_req(state_entry); + s_data = mtk_cam_ctrl_state_to_req_s_data(state_entry); + if (s_data->frame_seq_no == dequeued_frame_seq_no) { + state_transition(state_entry, + E_STATE_INNER_HW_DELAY, E_STATE_DONE_MISMATCH); + state_transition(state_entry, + E_STATE_INNER, E_STATE_DONE_NORMAL); + if (atomic_read(&camsys_sensor_ctrl->isp_request_seq_no) == 0) + state_transition(state_entry, + E_STATE_CQ, E_STATE_OUTER); + + dev_dbg(cam->dev, + "[SWD] req:%d/state:%d/time:%lld/sync_id:%lld\n", + s_data->frame_seq_no, state_entry->estate, + s_data->timestamp, state_req->sync_id); + } + } + spin_unlock(&camsys_sensor_ctrl->camsys_state_lock); + + return true; +} + +static void mtk_cam_handle_frame_done(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no, + unsigned int pipe_id) +{ + struct mtk_raw_device *raw_dev; + bool need_dequeue; + + /** + * If ctx is already off, just return; mtk_cam_dev_req_cleanup() + * triggered by mtk_cam_vb2_stop_streaming() puts the all media + * requests back. + */ + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + dev_info(ctx->cam->dev, + "%s: skip frame done for stream off ctx:%d\n", + __func__, ctx->stream_id); + spin_unlock(&ctx->streaming_lock); + return; + } + spin_unlock(&ctx->streaming_lock); + + raw_dev = get_main_raw_dev(ctx->cam, ctx->pipe); + if (!raw_dev) { + dev_err(ctx->cam->dev, "%s: not found raw device\n", __func__); + return; + } + + need_dequeue = + mtk_camsys_raw_prepare_frame_done(raw_dev, ctx, frame_seq_no); + + if (!need_dequeue) + return; + + dev_dbg(ctx->cam->dev, "[%s] job done ctx-%d:pipe-%d:req(%d)\n", + __func__, ctx->stream_id, pipe_id, frame_seq_no); + if (mtk_cam_dequeue_req_frame(ctx, frame_seq_no, pipe_id)) { + mutex_lock(&ctx->cam->queue_lock); + mtk_cam_dev_req_try_queue(ctx->cam); + mutex_unlock(&ctx->cam->queue_lock); + } +} + +void mtk_cam_meta1_done_work(struct work_struct *work) +{ + struct mtk_cam_req_work *meta1_done_work = + (struct mtk_cam_req_work *)work; + struct mtk_cam_request_stream_data *s_data, *s_data_ctx; + struct mtk_cam_ctx *ctx; + struct mtk_cam_request *req; + struct mtk_cam_buffer *buf; + struct vb2_buffer *vb; + void *vaddr; + bool unreliable = false; + + s_data = mtk_cam_req_work_get_s_data(meta1_done_work); + ctx = mtk_cam_s_data_get_ctx(s_data); + req = mtk_cam_s_data_get_req(s_data); + s_data_ctx = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + + dev_dbg(ctx->cam->dev, "%s: ctx:%d\n", __func__, ctx->stream_id); + + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + spin_unlock(&ctx->streaming_lock); + dev_info(ctx->cam->dev, "%s: skip for stream off ctx:%d\n", + __func__, ctx->stream_id); + return; + } + spin_unlock(&ctx->streaming_lock); + + if (!s_data) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get s_data\n", + __func__, ctx->stream_id); + return; + } + + /* Copy the meta1 output content to user buffer */ + buf = mtk_cam_s_data_get_vbuf(s_data, MTK_RAW_META_OUT_1); + if (!buf) { + dev_info(ctx->cam->dev, + "ctx(%d): can't get MTK_RAW_META_OUT_1 buf from req(%d)\n", + ctx->stream_id, s_data->frame_seq_no); + return; + } + + vb = &buf->vbb.vb2_buf; + if (!vb) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get vb2 buf\n", + __func__, ctx->stream_id); + return; + } + + vaddr = vb2_plane_vaddr(&buf->vbb.vb2_buf, 0); + if (!vaddr) { + dev_info(ctx->cam->dev, + "%s:ctx(%d): can't get plane_vadd\n", + __func__, ctx->stream_id); + return; + } + + /* Update the timestamp for the buffer*/ + mtk_cam_s_data_update_timestamp(buf, s_data_ctx); + + /* clean the stream data for req reinit case */ + mtk_cam_s_data_reset_vbuf(s_data, MTK_RAW_META_OUT_1); + + /* Let user get the buffer */ + if (unreliable) + vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_ERROR); + else + vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_DONE); + + dev_dbg(ctx->cam->dev, "%s:%s: req(%d) done\n", + __func__, req->req.debug_str, s_data->frame_seq_no); +} + +static void mtk_cam_meta1_done(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no, + unsigned int pipe_id) +{ + struct mtk_cam_request *req; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_req_work *meta1_done_work; + + req = mtk_cam_get_req(ctx, frame_seq_no); + if (!req) { + dev_info(ctx->cam->dev, "%s:ctx-%d:pipe-%d:req(%d) not found!\n", + __func__, ctx->stream_id, pipe_id, frame_seq_no); + return; + } + + req_stream_data = mtk_cam_req_get_s_data(req, pipe_id, 0); + if (!req_stream_data) { + dev_info(ctx->cam->dev, "%s:ctx-%d:pipe-%d:s_data not found!\n", + __func__, ctx->stream_id, pipe_id); + return; + } + + if (!(req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_META1_INDEPENDENT)) + return; + + meta1_done_work = &req_stream_data->meta1_done_work; + atomic_set(&meta1_done_work->is_queued, 1); + queue_work(ctx->frame_done_wq, &meta1_done_work->work); +} + +static void mtk_camsys_m2m_frame_done(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no, + unsigned int pipe_id) +{ + struct mtk_cam_req_work *frame_done_work; + struct mtk_cam_request_stream_data *req_stream_data; + + req_stream_data = mtk_cam_get_req_s_data(ctx, pipe_id, frame_seq_no); + if (!req_stream_data) { + dev_err(ctx->cam->dev, + "cannot find req stream data, pipe_id:%d frm_seq_no:%d\n", + pipe_id, frame_seq_no); + return; + } + if (atomic_read(&req_stream_data->frame_done_work.is_queued)) { + dev_info(ctx->cam->dev, + "already queue done work %d\n", + req_stream_data->frame_seq_no); + return; + } + + atomic_set(&req_stream_data->seninf_dump_state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + atomic_set(&req_stream_data->frame_done_work.is_queued, 1); + frame_done_work = &req_stream_data->frame_done_work; + queue_work(ctx->frame_done_wq, &frame_done_work->work); +} + +void mtk_cam_frame_done_work(struct work_struct *work) +{ + struct mtk_cam_req_work *frame_done_work = + (struct mtk_cam_req_work *)work; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_ctx *ctx; + + req_stream_data = mtk_cam_req_work_get_s_data(frame_done_work); + ctx = mtk_cam_s_data_get_ctx(req_stream_data); + + if (mtk_cam_is_m2m(ctx)) + mtk_cam_handle_m2m_frame_done(ctx, + req_stream_data->frame_seq_no, + req_stream_data->pipe_id); + else + mtk_cam_handle_frame_done(ctx, + req_stream_data->frame_seq_no, + req_stream_data->pipe_id); +} + +void mtk_camsys_frame_done(struct mtk_cam_ctx *ctx, + unsigned int frame_seq_no, + unsigned int pipe_id) +{ + struct mtk_cam_req_work *frame_done_work; + struct mtk_cam_request_stream_data *req_stream_data; + struct mtk_cam_buffer *buf; + struct mtk_cam_working_buf_entry *buf_entry = NULL; + bool is_pending_buffer = false; + + spin_lock(&ctx->cam->dma_processing_lock); + if (!list_empty(&ctx->cam->dma_processing)) { + buf = list_first_entry(&ctx->cam->dma_processing, + struct mtk_cam_buffer, list); + list_del(&buf->list); + ctx->cam->dma_processing_count--; + vb2_buffer_done(&buf->vbb.vb2_buf, VB2_BUF_STATE_DONE); + is_pending_buffer = true; + } + spin_unlock(&ctx->cam->dma_processing_lock); + + if (is_pending_buffer) { + spin_lock(&ctx->processing_buffer_list.lock); + if (!list_empty(&ctx->processing_buffer_list.list)) { + buf_entry = + list_first_entry(&ctx->processing_buffer_list.list, + struct mtk_cam_working_buf_entry, + list_entry); + list_del(&buf_entry->list_entry); + ctx->processing_buffer_list.cnt--; + } + spin_unlock(&ctx->processing_buffer_list.lock); + if (buf_entry) + mtk_cam_working_buf_put(buf_entry); + + mtk_cam_buf_try_queue(ctx); + return; + } + + req_stream_data = mtk_cam_get_req_s_data(ctx, pipe_id, frame_seq_no); + if (!req_stream_data) { + dev_info(ctx->cam->dev, + "%s:ctx-%d:pipe-%d:req(%d) not found!\n", + __func__, ctx->stream_id, pipe_id, frame_seq_no); + return; + } + + if (atomic_read(&req_stream_data->frame_done_work.is_queued)) { + dev_info(ctx->cam->dev, + "already queue done work req:%d seq:%d pipe_id:%d\n", + req_stream_data->frame_seq_no, frame_seq_no, pipe_id); + return; + } + + atomic_set(&req_stream_data->seninf_dump_state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + atomic_set(&req_stream_data->frame_done_work.is_queued, 1); + frame_done_work = &req_stream_data->frame_done_work; + queue_work(ctx->frame_done_wq, &frame_done_work->work); +} + +void mtk_camsys_state_delete(struct mtk_cam_ctx *ctx, + struct mtk_camsys_sensor_ctrl *sensor_ctrl, + struct mtk_cam_request *req) +{ + struct mtk_camsys_ctrl_state *state_entry, *state_entry_prev; + struct mtk_cam_request_stream_data *s_data; + struct mtk_camsys_ctrl_state *req_state; + int state_found = 0; + + if (ctx->sensor) { + spin_lock(&sensor_ctrl->camsys_state_lock); + list_for_each_entry_safe(state_entry, state_entry_prev, + &sensor_ctrl->camsys_state_list, + state_element) { + s_data = mtk_cam_req_get_s_data(req, ctx->stream_id, 0); + req_state = &s_data->state; + + if (state_entry == req_state) { + list_del(&state_entry->state_element); + state_found = 1; + } + } + spin_unlock(&sensor_ctrl->camsys_state_lock); + if (state_found == 0) + dev_dbg(ctx->cam->dev, "state not found\n"); + } +} + +static bool mtk_camsys_is_all_cq_done(struct mtk_cam_ctx *ctx, + unsigned int pipe_id) +{ + unsigned int all_subdevs = 0; + bool ret = false; + + spin_lock(&ctx->first_cq_lock); + if (ctx->is_first_cq_done) { + ret = true; + spin_unlock(&ctx->first_cq_lock); + goto EXIT; + } + + /* update cq done status */ + ctx->cq_done_status |= (1 << pipe_id); + + /* check cq done status */ + if (ctx->used_raw_num) + all_subdevs |= (1 << ctx->pipe->id); + if ((ctx->cq_done_status & all_subdevs) == all_subdevs) { + ctx->is_first_cq_done = 1; + ret = true; + } + spin_unlock(&ctx->first_cq_lock); + dev_info(ctx->cam->dev, + "[1st-CQD] all done:%d, pipe_id:%d (using raw:%d)\n", + ctx->is_first_cq_done, pipe_id, ctx->used_raw_num); +EXIT: + return ret; +} + +static int mtk_camsys_event_handle_raw(struct mtk_cam_device *cam, + unsigned int engine_id, + struct mtk_camsys_irq_info *irq_info) +{ + struct mtk_raw_device *raw_dev; + struct mtk_cam_ctx *ctx; + + raw_dev = dev_get_drvdata(cam->raw.devs[engine_id]); + ctx = mtk_cam_find_ctx(cam, &raw_dev->pipeline->subdev.entity); + if (!ctx) { + dev_err(raw_dev->dev, "cannot find ctx\n"); + return -EINVAL; + } + + /* raw's CQ done */ + if (irq_info->irq_type & 1 << CAMSYS_IRQ_SETTING_DONE) { + if (mtk_cam_is_m2m(ctx)) { + mtk_camsys_raw_m2m_cq_done(raw_dev, ctx, irq_info->frame_idx); + mtk_camsys_raw_m2m_trigger(raw_dev, ctx, irq_info->frame_idx); + } else { + if (mtk_camsys_is_all_cq_done(ctx, ctx->pipe->id)) + mtk_camsys_raw_cq_done(raw_dev, ctx, + irq_info->frame_idx); + } + } + + /* raw's DMA done, we only allow AFO done here */ + if (irq_info->irq_type & 1 << CAMSYS_IRQ_AFO_DONE) + mtk_cam_meta1_done(ctx, ctx->dequeued_frame_seq_no, ctx->stream_id); + + /* raw's SW done */ + if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_DONE) { + if (mtk_cam_is_m2m(ctx)) + mtk_camsys_m2m_frame_done(ctx, irq_info->frame_idx_inner, + ctx->stream_id); + else + mtk_camsys_frame_done(ctx, ctx->dequeued_frame_seq_no, + ctx->stream_id); + } + /* raw's SOF */ + if (irq_info->irq_type & 1 << CAMSYS_IRQ_FRAME_START) { + if (atomic_read(&raw_dev->vf_en) == 0) { + dev_info(raw_dev->dev, "skip sof event when vf off\n"); + return 0; + } + mtk_camsys_raw_frame_start(raw_dev, ctx, irq_info); + } + + return 0; +} + +int mtk_camsys_isr_event(struct mtk_cam_device *cam, + enum MTK_CAMSYS_ENGINE_TYPE engine_type, + unsigned int engine_id, + struct mtk_camsys_irq_info *irq_info) +{ + int ret = 0; + + switch (engine_type) { + case CAMSYS_ENGINE_RAW: + ret = mtk_camsys_event_handle_raw(cam, engine_id, irq_info); + break; + case CAMSYS_ENGINE_SENINF: + if (irq_info->irq_type & (1 << CAMSYS_IRQ_FRAME_DROP)) + dev_info(cam->dev, + "MTK_CAMSYS_ENGINE_SENINF_TAG engine:%d type:0x%x\n", + engine_id, irq_info->irq_type); + break; + default: + break; + } + + return ret; +} + +void mtk_cam_initial_sensor_setup(struct mtk_cam_request *initial_req, + struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_cam_request_stream_data *req_stream_data; + + sensor_ctrl->ctx = ctx; + req_stream_data = mtk_cam_req_get_s_data(initial_req, ctx->stream_id, 0); + req_stream_data->ctx = ctx; + mtk_cam_set_sensor_full(req_stream_data, &ctx->sensor_ctrl); + dev_info(ctx->cam->dev, "Directly setup sensor req:%d\n", + req_stream_data->frame_seq_no); +} + +static void mtk_cam_complete_hdl(struct mtk_cam_request_stream_data *s_data, + struct media_request_object *hdl_obj, + char *name) +{ + char *debug_str; + u64 start, cost; + + debug_str = mtk_cam_s_data_get_dbg_str(s_data); + + start = ktime_get_boottime_ns(); + if (hdl_obj->ops) + hdl_obj->ops->unbind(hdl_obj); /* mutex used */ + else + pr_info("%s:%s:pipe(%d):seq(%d): cannot unbind %s hd\n", + __func__, debug_str, s_data->pipe_id, + s_data->frame_seq_no, name); + + cost = ktime_get_boottime_ns() - start; + if (cost > 1000000) + pr_info("%s:%s:pipe(%d):seq(%d): complete hdl:%s, cost:%llu ns\n", + __func__, debug_str, s_data->pipe_id, + s_data->frame_seq_no, name, cost); + else + pr_debug("%s:%s:pipe(%d):seq(%d): complete hdl:%s, cost:%llu ns\n", + __func__, debug_str, s_data->pipe_id, + s_data->frame_seq_no, name, cost); + + media_request_object_complete(hdl_obj); +} + +void mtk_cam_complete_sensor_hdl(struct mtk_cam_request_stream_data *s_data) +{ + if (s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_EN && + !(s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE) && + s_data->sensor_hdl_obj) { + mtk_cam_complete_hdl(s_data, s_data->sensor_hdl_obj, "sensor"); + s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_SENSOR_HDL_COMPLETE; + } +} + +void mtk_cam_complete_raw_hdl(struct mtk_cam_request_stream_data *s_data) +{ + if ((s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN) && + !(s_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE) && + s_data->raw_hdl_obj) { + mtk_cam_complete_hdl(s_data, s_data->raw_hdl_obj, "raw"); + s_data->flags |= MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE; + } +} + +void mtk_cam_req_ctrl_setup(struct mtk_raw_pipeline *raw_pipe, + struct mtk_cam_request *req) +{ + struct mtk_cam_request_stream_data *req_stream_data; + + req_stream_data = mtk_cam_req_get_s_data(req, raw_pipe->id, 0); + + /* request setup*/ + if (req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_EN && + !(req_stream_data->flags & MTK_CAM_REQ_S_DATA_FLAG_RAW_HDL_COMPLETE) && + req_stream_data->raw_hdl_obj) { + dev_dbg(raw_pipe->subdev.v4l2_dev->dev, + "%s:%s:%s:raw ctrl set start (seq:%d)\n", + __func__, raw_pipe->subdev.name, req->req.debug_str, + req_stream_data->frame_seq_no); + v4l2_ctrl_request_setup(&req->req, &raw_pipe->ctrl_handler); + + mtk_cam_complete_raw_hdl(req_stream_data); + } +} + +static int timer_reqdrained_chk(int fps_ratio) +{ + int timer_ms = 0; + + if (fps_ratio > 1) + timer_ms = SENSOR_SET_DEADLINE_MS / fps_ratio; + else + timer_ms = SENSOR_SET_DEADLINE_MS; + /* earlier request drained event*/ + if (fps_ratio > 1) + timer_ms = SENSOR_SET_DEADLINE_MS_60FPS; + + return timer_ms; +} + +static int timer_setsensor(int fps_ratio) +{ + int timer_ms = 0; + + if (fps_ratio > 1) + timer_ms = SENSOR_SET_RESERVED_MS / fps_ratio; + else + timer_ms = SENSOR_SET_RESERVED_MS; + + /* faster sensor setting*/ + if (fps_ratio > 1) + timer_ms = SENSOR_SET_RESERVED_MS_60FPS; + + return timer_ms; +} + +int mtk_camsys_ctrl_start(struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl; + struct v4l2_subdev_frame_interval fi = { + .pad = 0, + .interval = { + .numerator = 1, + .denominator = 30 + }, + }; + int fps_factor = 1; + + if (ctx->used_raw_num) { + v4l2_subdev_call_state_active(ctx->sensor, pad, get_frame_interval, &fi); + fps_factor = (fi.interval.numerator > 0) ? + (fi.interval.denominator / fi.interval.numerator / 30) : 1; + } + + camsys_sensor_ctrl->ctx = ctx; + atomic_set(&camsys_sensor_ctrl->sensor_enq_seq_no, 0); + atomic_set(&camsys_sensor_ctrl->sensor_request_seq_no, 0); + atomic_set(&camsys_sensor_ctrl->isp_request_seq_no, 0); + atomic_set(&camsys_sensor_ctrl->isp_enq_seq_no, 0); + atomic_set(&camsys_sensor_ctrl->last_drained_seq_no, 0); + camsys_sensor_ctrl->initial_cq_done = 0; + camsys_sensor_ctrl->sof_time = 0; + if (ctx->used_raw_num) + atomic_set(&camsys_sensor_ctrl->initial_drop_frame_cnt, 0); + + camsys_sensor_ctrl->timer_req_event = + timer_reqdrained_chk(fps_factor); + camsys_sensor_ctrl->timer_req_sensor = + timer_setsensor(fps_factor); + INIT_LIST_HEAD(&camsys_sensor_ctrl->camsys_state_list); + spin_lock_init(&camsys_sensor_ctrl->camsys_state_lock); + if (ctx->sensor) { + hrtimer_init(&camsys_sensor_ctrl->sensor_deadline_timer, + CLOCK_MONOTONIC, HRTIMER_MODE_REL); + camsys_sensor_ctrl->sensor_deadline_timer.function = + sensor_deadline_timer_handler; + camsys_sensor_ctrl->sensorsetting_wq = &ctx->sensor_worker; + } + kthread_init_work(&camsys_sensor_ctrl->work, + mtk_cam_sensor_worker_in_sensorctrl); + + dev_info(ctx->cam->dev, + "[%s] ctx:%d/raw_dev:0x%x drained/sensor (%d)%d/%d\n", + __func__, ctx->stream_id, ctx->used_raw_dev, fps_factor, + camsys_sensor_ctrl->timer_req_event, + camsys_sensor_ctrl->timer_req_sensor); + + return 0; +} + +void mtk_camsys_ctrl_update(struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl; + struct v4l2_subdev_frame_interval fi = { + .pad = 0, + .interval = { + .numerator = 1, + .denominator = 30 + }, + }; + int fps_factor = 1; + + if (ctx->used_raw_num) { + fi.pad = 0; + v4l2_subdev_call_state_active(ctx->sensor, pad, get_frame_interval, &fi); + fps_factor = (fi.interval.numerator > 0) ? + (fi.interval.denominator / fi.interval.numerator / 30) : 1; + } + + camsys_sensor_ctrl->timer_req_event = + timer_reqdrained_chk(fps_factor); + camsys_sensor_ctrl->timer_req_sensor = + timer_setsensor(fps_factor); + + dev_info(ctx->cam->dev, + "[%s] ctx:%d/raw_dev:0x%x drained/sensor (%d)%d/%d\n", + __func__, ctx->stream_id, ctx->used_raw_dev, fps_factor, + camsys_sensor_ctrl->timer_req_event, + camsys_sensor_ctrl->timer_req_sensor); +} + +void mtk_camsys_ctrl_stop(struct mtk_cam_ctx *ctx) +{ + struct mtk_camsys_sensor_ctrl *camsys_sensor_ctrl = &ctx->sensor_ctrl; + struct mtk_camsys_ctrl_state *state_entry, *state_entry_prev; + + spin_lock(&camsys_sensor_ctrl->camsys_state_lock); + list_for_each_entry_safe(state_entry, state_entry_prev, + &camsys_sensor_ctrl->camsys_state_list, + state_element) { + list_del(&state_entry->state_element); + } + spin_unlock(&camsys_sensor_ctrl->camsys_state_lock); + + if (ctx->sensor) { + hrtimer_cancel(&camsys_sensor_ctrl->sensor_deadline_timer); + camsys_sensor_ctrl->sensorsetting_wq = NULL; + } + kthread_flush_work(&camsys_sensor_ctrl->work); + if (ctx->used_raw_num) + mtk_cam_event_eos(ctx->pipe); + + dev_info(ctx->cam->dev, "[%s] ctx:%d/raw_dev:0x%x\n", + __func__, ctx->stream_id, ctx->used_raw_dev); +} + +void mtk_cam_m2m_enter_cq_state(struct mtk_camsys_ctrl_state *ctrl_state) +{ + state_transition(ctrl_state, E_STATE_SENSOR, E_STATE_CQ); +} diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h new file mode 100644 index 000000000000..1b780a405193 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-ctrl.h @@ -0,0 +1,140 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_CTRL_H +#define __MTK_CAM_CTRL_H + +#include +#include + +struct mtk_cam_device; + +enum MTK_CAMSYS_ENGINE_TYPE { + CAMSYS_ENGINE_RAW, + CAMSYS_ENGINE_MRAW, + CAMSYS_ENGINE_CAMSV, + CAMSYS_ENGINE_SENINF, +}; + +enum MTK_CAMSYS_IRQ_EVENT { + /* with normal_data */ + CAMSYS_IRQ_SETTING_DONE = 0, + CAMSYS_IRQ_FRAME_START, + CAMSYS_IRQ_AFO_DONE, + CAMSYS_IRQ_FRAME_DONE, + CAMSYS_IRQ_SUBSAMPLE_SENSOR_SET, + CAMSYS_IRQ_FRAME_DROP, + + /* with error_data */ + CAMSYS_IRQ_ERROR, +}; + +struct mtk_camsys_irq_normal_data { + /* with normal_status */ +}; + +struct mtk_camsys_irq_error_data { + /* with error_status */ + int err_status; +}; + +struct mtk_camsys_irq_info { + enum MTK_CAMSYS_IRQ_EVENT irq_type; + u64 ts_ns; + int frame_idx; + int frame_idx_inner; + bool sub_engine; + int write_cnt; + int fbc_cnt; + union { + struct mtk_camsys_irq_normal_data n; + struct mtk_camsys_irq_error_data e; + }; +}; + +enum MTK_CAMSYS_STATE_IDX { + /* For state analysis and controlling for request */ + E_STATE_READY = 0x0, + E_STATE_SENINF, + E_STATE_SENSOR, + E_STATE_CQ, + E_STATE_OUTER, + E_STATE_CAMMUX_OUTER_CFG, + E_STATE_CAMMUX_OUTER, + E_STATE_INNER, + E_STATE_DONE_NORMAL, + E_STATE_CQ_SCQ_DELAY, + E_STATE_CAMMUX_OUTER_CFG_DELAY, + E_STATE_OUTER_HW_DELAY, + E_STATE_INNER_HW_DELAY, + E_STATE_DONE_MISMATCH, +}; + +struct mtk_camsys_ctrl_state { + enum MTK_CAMSYS_STATE_IDX estate; + struct list_head state_element; +}; + +struct mtk_camsys_link_ctrl { + struct mtk_raw_pipeline *pipe; + struct media_pad remote; + struct mtk_cam_ctx *swapping_ctx; + u8 active; + u8 wait_exchange; +}; + +/* per stream from sensor */ +struct mtk_camsys_sensor_ctrl { + struct mtk_cam_ctx *ctx; + struct kthread_worker *sensorsetting_wq; + struct kthread_work work; + struct hrtimer sensor_deadline_timer; + u64 sof_time; + int timer_req_sensor; + int timer_req_event; + atomic_t sensor_enq_seq_no; + atomic_t sensor_request_seq_no; + atomic_t isp_request_seq_no; + atomic_t isp_enq_seq_no; + atomic_t last_drained_seq_no; + int initial_cq_done; + atomic_t initial_drop_frame_cnt; + struct list_head camsys_state_list; + spinlock_t camsys_state_lock; /* protect camsys_state_list */ + /* link change ctrl */ + struct mtk_camsys_link_ctrl link_ctrl; + struct mtk_cam_request *link_change_req; +}; + +void mtk_camsys_state_delete(struct mtk_cam_ctx *ctx, + struct mtk_camsys_sensor_ctrl *sensor_ctrl, + struct mtk_cam_request *req); +void mtk_camsys_frame_done(struct mtk_cam_ctx *ctx, unsigned int frame_seq_no, + unsigned int pipe_id); +int mtk_camsys_isr_event(struct mtk_cam_device *cam, + enum MTK_CAMSYS_ENGINE_TYPE engine_type, + unsigned int engine_id, + struct mtk_camsys_irq_info *irq_info); +bool mtk_cam_submit_kwork_in_sensorctrl(struct kthread_worker *worker, + struct mtk_camsys_sensor_ctrl *sensor_ctrl); +void mtk_cam_initial_sensor_setup(struct mtk_cam_request *req, + struct mtk_cam_ctx *ctx); +void mtk_cam_req_ctrl_setup(struct mtk_raw_pipeline *raw_pipe, + struct mtk_cam_request *req); +int mtk_camsys_ctrl_start(struct mtk_cam_ctx *ctx); /* ctx_stream_on */ +void mtk_camsys_ctrl_update(struct mtk_cam_ctx *ctx); +void mtk_camsys_ctrl_stop(struct mtk_cam_ctx *ctx); /* ctx_stream_off */ +void mtk_cam_frame_done_work(struct work_struct *work); +void mtk_cam_meta1_done_work(struct work_struct *work); +void mtk_cam_m2m_enter_cq_state(struct mtk_camsys_ctrl_state *ctrl_state); +void mtk_cam_set_sensor_full(struct mtk_cam_request_stream_data *s_data, + struct mtk_camsys_sensor_ctrl *sensor_ctrl); +void state_transition(struct mtk_camsys_ctrl_state *state_entry, + enum MTK_CAMSYS_STATE_IDX from, + enum MTK_CAMSYS_STATE_IDX to); +void mtk_cam_set_sensor_switch(struct mtk_cam_request_stream_data *s_data, + struct mtk_camsys_sensor_ctrl *sensor_ctrl); + +#endif /* __MTK_CAM_CTRL_H */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.c b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.c new file mode 100644 index 000000000000..9e6f2a33a111 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.c @@ -0,0 +1,1271 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (c) 2022 MediaTek Inc. + +#ifdef CONFIG_DEBUG_FS + +#include +#include +#include +#include + +#include +#include "mtk_camera-v4l2-controls.h" +#include "mtk_cam-regs-mt8188.h" +#include "mtk_cam.h" +#include "mtk_cam-raw.h" +#include "mtk_cam-debug.h" + +#define CAMSYS_DUMP_SATATE_INIT 0 +#define CAMSYS_DUMP_SATATE_READY 1 + +#define CTRL_BLOCK_STATE_EMPTY 0 +#define CTRL_BLOCK_STATE_WRITE 1 +#define CTRL_BLOCK_STATE_READY 2 +#define CTRL_BLOCK_STATE_READ 3 + +static int +mtk_cam_debug_init_dump_param(struct mtk_cam_ctx *ctx, + struct mtk_cam_dump_param *param, + struct mtk_cam_request_stream_data *stream_data, + char *desc) +{ + struct mtk_cam_device *cam = ctx->cam; + struct mtk_cam_buffer *buf; + struct mtk_cam_video_device *node; + int request_fd = -1; + + memset(param, 0, sizeof(*param)); + param->stream_id = ctx->stream_id; + param->sequence = stream_data->frame_seq_no; + param->timestamp = stream_data->timestamp; + + if (stream_data->working_buf) { + param->cq_cpu_addr = stream_data->working_buf->buffer.va; + } else { + dev_info(cam->dev, + "%s:ctx(%d):req(%d):stream_data->working_buf is null\n", + __func__, ctx->stream_id, param->sequence); + return -EINVAL; + } + + buf = mtk_cam_s_data_get_vbuf(stream_data, MTK_RAW_META_IN); + if (buf) { + request_fd = buf->vbb.request_fd; + node = mtk_cam_vbq_to_vdev(buf->vbb.vb2_buf.vb2_queue); + param->meta_in_cpu_addr = vb2_plane_vaddr(&buf->vbb.vb2_buf, 0); + param->meta_in_dump_buf_size = + node->active_fmt.fmt.meta.buffersize; + param->meta_in_iova = buf->daddr; + dev_dbg(cam->dev, + "%s:ctx(%d):req(%d):MTK_RAW_META_IN(%s) found: %d\n", + __func__, ctx->stream_id, param->sequence, + node->desc.name, param->meta_in_dump_buf_size); + } + + param->cq_size = stream_data->working_buf->buffer.size; + param->cq_iova = stream_data->working_buf->buffer.iova; + param->cq_desc_offset = stream_data->working_buf->cq_desc_offset; + param->cq_desc_size = stream_data->working_buf->cq_desc_size; + param->sub_cq_desc_size = stream_data->working_buf->sub_cq_desc_size; + param->sub_cq_desc_offset = stream_data->working_buf->sub_cq_desc_offset; + + param->request_fd = request_fd; + param->desc = desc; + + /* add mtkcam_ipi_frame_param to dump */ + param->frame_params = &stream_data->frame_params; + param->frame_param_size = sizeof(stream_data->frame_params); + dev_dbg(cam->dev, "%s:ctx(%d):req(%d), frame_param size(%u)\n", + __func__, ctx->stream_id, param->sequence, param->frame_param_size); + + /* add mtkcam_ipi_config_param to dump */ + param->config_params = &ctx->config_params; + param->config_param_size = sizeof(ctx->config_params); + dev_dbg(cam->dev, "%s:ctx(%d):req(%d), cofig_param size(%u)\n", + __func__, ctx->stream_id, param->sequence, param->config_param_size); + + return 0; +} + +/* Dump single region to the buffer */ +static void mtk_cam_dump_buf_content(struct device *dev, void *buf, void *src, + int offset, int size, char *buf_name) +{ + void *dest; + + if (!src || size <= 0) + return; + + dest = buf + offset; + dev_dbg(dev, "%s: dump:%s(%p --> %p), offset(%d), size(%d)", + __func__, buf_name, src, dest, offset, size); + memcpy(dest, src, size); +} + +static void +mtk_cam_debug_dump_all_content(struct mtk_cam_debug_fs *debug_fs, + void *dump_buf, + struct mtk_cam_dump_param *param) +{ + struct mtk_cam_dump_header *header; + struct device *dev = debug_fs->cam->dev; + + header = (struct mtk_cam_dump_header *)dump_buf; + strscpy(header->desc, param->desc, MTK_CAM_DEBUG_DUMP_DESC_SIZE - 1); + header->request_fd = param->request_fd; + header->stream_id = param->stream_id; + header->timestamp = param->timestamp; + header->sequence = param->sequence; + header->header_size = sizeof(*header); + header->payload_offset = header->header_size; + header->payload_size = debug_fs->buf_size - header->header_size; + + dev_dbg(dev, + "%s:ctx(%d):req_fd(%d),ts(%llu),req(%d),header_sz(%d),payload_offset(%d),payload_sz(%d)", + __func__, header->stream_id, header->request_fd, + header->timestamp, header->sequence, header->header_size, + header->payload_offset, header->payload_size); + + /* meta file information */ + header->meta_version_major = camsys_get_meta_version(true); + header->meta_version_minor = camsys_get_meta_version(false); + + /* CQ dump */ + header->cq_dump_buf_offset = header->payload_offset; + header->cq_size = param->cq_size; + header->cq_iova = param->cq_iova; + header->cq_desc_offset = param->cq_desc_offset; + header->cq_desc_size = param->cq_desc_size; + header->sub_cq_desc_offset = param->sub_cq_desc_offset; + header->sub_cq_desc_size = param->sub_cq_desc_size; + + /* meta in */ + header->meta_in_dump_buf_offset = + header->cq_dump_buf_offset + header->cq_size; + header->meta_in_dump_buf_size = param->meta_in_dump_buf_size; + header->meta_in_iova = param->meta_in_iova; + + /* meta out 0 */ + header->meta_out_0_dump_buf_offset = + header->meta_in_dump_buf_offset + + header->meta_in_dump_buf_size; + header->meta_out_0_dump_buf_size = param->meta_out_0_dump_buf_size; + header->meta_out_0_iova = param->meta_out_0_iova; + + /* meta out 1 */ + header->meta_out_1_dump_buf_offset = + header->meta_out_0_dump_buf_offset + + header->meta_out_0_dump_buf_size; + header->meta_out_1_dump_buf_size = param->meta_out_1_dump_buf_size; + header->meta_out_1_iova = param->meta_out_1_iova; + + /* meta out 2 */ + header->meta_out_2_dump_buf_offset = + header->meta_out_1_dump_buf_offset + + header->meta_out_1_dump_buf_size; + header->meta_out_2_dump_buf_size = param->meta_out_2_dump_buf_size; + header->meta_out_2_iova = param->meta_out_2_iova; + + /* ipi frame param */ + header->frame_dump_offset = + header->meta_out_2_dump_buf_offset + + header->meta_out_2_dump_buf_size; + header->frame_dump_size = param->frame_param_size; + + /* ipi config param */ + header->config_dump_offset = + header->frame_dump_offset + + header->frame_dump_size; + header->config_dump_size = param->config_param_size; + header->used_stream_num = 1; + + mtk_cam_dump_buf_content(dev, dump_buf, param->cq_cpu_addr, + header->cq_dump_buf_offset, + header->cq_size, + "CQ"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->meta_in_cpu_addr, + header->meta_in_dump_buf_offset, + header->meta_in_dump_buf_size, + "Meta-in"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->meta_out_0_cpu_addr, + header->meta_out_0_dump_buf_offset, + header->meta_out_0_dump_buf_size, + "Meta-out-0"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->meta_out_1_cpu_addr, + header->meta_out_1_dump_buf_offset, + header->meta_out_1_dump_buf_size, + "Meta-out-1"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->meta_out_2_cpu_addr, + header->meta_out_2_dump_buf_offset, + header->meta_out_2_dump_buf_size, + "Meta-out-2"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->frame_params, + header->frame_dump_offset, + header->frame_dump_size, + "Ipi-frame-params"); + + mtk_cam_dump_buf_content(dev, dump_buf, param->config_params, + header->config_dump_offset, + header->config_dump_size, + "Ipi-config-params"); +} + +static struct mtk_cam_dump_ctrl_block * +mtk_cam_dump_ctrl_block_next(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_buf_ctrl *ctrl) +{ + struct device *dev = debug_fs->cam->dev; + struct mtk_cam_dump_ctrl_block *ctrl_block; + int head, tail; + + head = ctrl->head; + tail = ctrl->tail; + + if (ctrl->num <= 0) { + dev_info(dev, "%s:pipe(%d):no buffer allocated:%d\n", + __func__, ctrl->pipe_id, ctrl->num); + return NULL; + } + + if (ctrl->count) { + head++; + if (head == ctrl->num) + head = 0; + /* User is still reading the buffer*/ + if (atomic_read(&ctrl->blocks[head].state) == CTRL_BLOCK_STATE_READ) + return NULL; + /* overwrite the last buffer */ + if (head == tail) + tail++; + if (tail == ctrl->num) + tail = 0; + } + + ctrl->tail = tail; + ctrl->head = head; + ctrl->count++; + if (ctrl->count > ctrl->num) + ctrl->count = ctrl->num; + + ctrl_block = &ctrl->blocks[ctrl->head]; + dev_dbg(dev, + "%s:pipe(%d):ctrl_block(%p),buf(%p),head(%d),tail(%d),cnt(%d),num(%d)\n", + __func__, ctrl->pipe_id, ctrl_block, ctrl_block->buf, + ctrl->head, ctrl->tail, ctrl->count, ctrl->num); + + return ctrl_block; +} + +static int mtk_cam_debug_dump(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_param *param) +{ + struct device *dev = debug_fs->cam->dev; + struct mtk_cam_dump_buf_ctrl *ctrl = &debug_fs->ctrl[param->stream_id]; + struct mtk_cam_dump_ctrl_block *ctrl_block; + + mutex_lock(&ctrl->ctrl_lock); + ctrl_block = mtk_cam_dump_ctrl_block_next(debug_fs, ctrl); + if (!ctrl_block || !ctrl_block->buf) { + dev_info(dev, "%s:pipe(%d):req(%d):no free buffer, drop\n", + __func__, param->stream_id, param->sequence); + mutex_unlock(&ctrl->ctrl_lock); + + return -EINVAL; + } + mutex_unlock(&ctrl->ctrl_lock); + + atomic_set(&ctrl_block->state, CTRL_BLOCK_STATE_WRITE); + mtk_cam_debug_dump_all_content(debug_fs, ctrl_block->buf, param); + atomic_set(&ctrl_block->state, CTRL_BLOCK_STATE_READY); + + dev_dbg(dev, "%s:pipe(%d):req(%d):dump(%p) is ready to read, sz(%u)\n", + __func__, param->stream_id, param->sequence, ctrl_block->buf, + debug_fs->buf_size); + + return 0; +} + +static int mtk_cam_debug_exp_dump(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_param *param) +{ + struct device *dev = debug_fs->cam->dev; + void *dump_buf = debug_fs->exp_dump_buf; + + if (!dump_buf) { + dev_info(dev, "%s:pipe(%d):req(%d):no dump buffer. sz(%u)\n", + __func__, param->stream_id, param->sequence, + debug_fs->buf_size); + return -EINVAL; + } + + mutex_lock(&debug_fs->exp_dump_buf_lock); + if (atomic_read(&debug_fs->exp_dump_state) != CAMSYS_DUMP_SATATE_INIT) { + dev_info(dev, + "%s:pipe(%d):req(%d):dump can't be written, state(%d), buf(%p), sz(%u)\n", + __func__, param->stream_id, param->sequence, + atomic_read(&debug_fs->exp_dump_state), dump_buf, + debug_fs->buf_size); + mutex_unlock(&debug_fs->exp_dump_buf_lock); + + return -EINVAL; + } + + memset(dump_buf, 0, debug_fs->buf_size); + mtk_cam_debug_dump_all_content(debug_fs, dump_buf, param); + atomic_set(&debug_fs->exp_dump_state, CAMSYS_DUMP_SATATE_READY); + mutex_unlock(&debug_fs->exp_dump_buf_lock); + + dev_dbg(dev, "%s:pipe(%d):req(%d):dump is ready to read\n", + __func__, param->stream_id, param->sequence); + + return 0; +} + +static int mtk_cam_debug_find_dump_ctrl(struct mtk_cam_dump_buf_ctrl *ctrl, + unsigned long seq) +{ + int i = ctrl->head; + struct mtk_cam_dump_ctrl_block *ctrl_block; + struct mtk_cam_dump_header *header; + + if (!ctrl->count) + return -EINVAL; + + while (1) { + ctrl_block = &ctrl->blocks[i]; + header = (struct mtk_cam_dump_header *)ctrl_block->buf; + if (header->sequence == seq) + return i; + + if (i == ctrl->tail) + break; + + if (--i < 0) + i = ctrl->num - 1; + } + + return -EINVAL; +} + +static int mtk_cam_debug_dump_ctrl_set(struct mtk_cam_dump_buf_ctrl *ctrl, + unsigned long seq, bool start) +{ + struct mtk_cam_dump_ctrl_block *ctrl_block; + int ctrl_block_idx; + + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe_id(%d):to read req(%ld), start/end(%d)\n", + __func__, ctrl->pipe_id, seq, start); + mutex_lock(&ctrl->ctrl_lock); + ctrl_block_idx = mtk_cam_debug_find_dump_ctrl(ctrl, seq); + if (ctrl_block_idx < 0) { + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe_id(%d): to read req(%ld) dump, start/end(%d), not found\n", + __func__, ctrl->pipe_id, seq, start); + goto FAIL_RELEASE_LOCK; + } + ctrl_block = &ctrl->blocks[ctrl_block_idx]; + if (start) { + if (atomic_read(&ctrl_block->state) != CTRL_BLOCK_STATE_READY) { + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe_id(%d):to get req(%ld) dump failed, state(%d)\n", + __func__, ctrl->pipe_id, seq, + atomic_read(&ctrl_block->state)); + goto FAIL_RELEASE_LOCK; + } + atomic_set(&ctrl_block->state, CTRL_BLOCK_STATE_READ); + ctrl->cur_read = ctrl_block_idx; + } else { + if (atomic_read(&ctrl_block->state) != CTRL_BLOCK_STATE_READ) { + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe_id(%d):to release req(%ld) dump failed, state(%d)\n", + __func__, ctrl->pipe_id, seq, + atomic_read(&ctrl_block->state)); + goto FAIL_RELEASE_LOCK; + } + ctrl->cur_read = -1; + atomic_set(&ctrl_block->state, CTRL_BLOCK_STATE_READY); + } + mutex_unlock(&ctrl->ctrl_lock); + return 0; + +FAIL_RELEASE_LOCK: + ctrl->cur_read = -1; + mutex_unlock(&ctrl->ctrl_lock); + return -EINVAL; +} + +static void mtk_cam_dump_ctrl_init(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_buf_ctrl *ctrl, int num) +{ + ctrl->num = num; + ctrl->head = 0; + ctrl->tail = 0; + ctrl->count = 0; + ctrl->cur_read = -1; +} + +static void mtk_cam_dump_ctrl_reinit(struct mtk_cam_dump_buf_ctrl *ctrl) +{ + int i; + + mutex_lock(&ctrl->ctrl_lock); + + ctrl->head = 0; + ctrl->tail = 0; + ctrl->count = 0; + ctrl->cur_read = -1; + for (i = 0; i < ctrl->num; i++) + atomic_set(&ctrl->blocks[i].state, CTRL_BLOCK_STATE_EMPTY); + + mutex_unlock(&ctrl->ctrl_lock); +} + +static int mtk_cam_dump_buf_realloc(struct mtk_cam_dump_buf_ctrl *ctrl, + int num_of_bufs) +{ + int num_of_alloc = 0; + int i; + struct mtk_cam_dump_ctrl_block *ctrl_block; + struct mtk_cam_debug_fs *debug_fs = ctrl->debug_fs; + struct device *dev = debug_fs->cam->dev; + void *dump_buf; + + mutex_lock(&ctrl->ctrl_lock); + /* Release the previous buffers */ + for (i = 0; i < ctrl->num; i++) { + dev_dbg(dev, "%s:pipe(%d):free dump buf(%d):%p\n", __func__, + ctrl->pipe_id, i, ctrl->blocks[i].buf); + vfree(ctrl->blocks[i].buf); + ctrl->blocks[i].buf = NULL; + } + + if (num_of_bufs > MTK_CAM_DEBUG_DUMP_MAX_BUF) + ctrl->num = MTK_CAM_DEBUG_DUMP_MAX_BUF; + else + ctrl->num = num_of_bufs; + + for (i = 0; i < ctrl->num; i++) { + dump_buf = vzalloc(debug_fs->buf_size); + if (!dump_buf) + break; + + ctrl_block = &ctrl->blocks[i]; + atomic_set(&ctrl_block->state, CTRL_BLOCK_STATE_EMPTY); + ctrl_block->buf = dump_buf; + num_of_alloc++; + dev_dbg(dev, "%s:pipe(%d):alloc dump buf(%d):%p\n", __func__, + ctrl->pipe_id, i, ctrl->blocks[i].buf); + } + + mtk_cam_dump_ctrl_init(debug_fs, ctrl, num_of_alloc); + dev_info(dev, + "%s:pipe(%d):cnt(%d), head(%d), tail(%d), entry_sz(%u), entry_num(%d)\n", + __func__, ctrl->pipe_id, ctrl->count, ctrl->head, + ctrl->tail, debug_fs->buf_size, ctrl->num); + mutex_unlock(&ctrl->ctrl_lock); + + return 0; +} + +static int dbg_ctrl_open(struct inode *inode, struct file *file) +{ + struct mtk_cam_debug_fs *debug_fs; + struct mtk_cam_dump_buf_ctrl *ctrl; + + if (inode->i_private) + file->private_data = inode->i_private; + + ctrl = file->private_data; + debug_fs = ctrl->debug_fs; + + dev_dbg(debug_fs->cam->dev, + "%s:pipe(%d):cnt(%d), head(%d), tail(%d), entry_sz(%u), entry_num(%d)\n", + __func__, ctrl->pipe_id, ctrl->count, ctrl->head, ctrl->tail, + debug_fs->buf_size, ctrl->num); + + return 0; +} + +static ssize_t dbg_ctrl_write(struct file *file, const char __user *data, + size_t count, loff_t *ppos) +{ + struct mtk_cam_debug_fs *debug_fs; + struct mtk_cam_dump_buf_ctrl *ctrl; + char tmp[16]; + char *parse_str = tmp; + char *cmd_str; + char *param_str_0; + char *param_str_1; + unsigned long seq = 0; + int ret = -EINVAL; + + ctrl = file->private_data; + debug_fs = ctrl->debug_fs; + if (count >= 15) { + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe(%d):Invalid cmd sz(%zu)\n", __func__, + ctrl->pipe_id, count); + goto FAIL; + } + + memset(tmp, 0, 16); + if (copy_from_user(tmp, data, count)) { + dev_info(ctrl->debug_fs->cam->dev, + "%s:pipe(%d):copy_from_user failed, data(%p), sz(%zu)\n", + __func__, ctrl->pipe_id, data, count); + ret = -EFAULT; + goto FAIL; + } + dev_dbg(ctrl->debug_fs->cam->dev, "%s:pipe(%d):received cmd(%s)\n", + __func__, ctrl->pipe_id, tmp); + cmd_str = strsep(&parse_str, ":"); + param_str_0 = strsep(&parse_str, ":"); + + if (cmd_str[0] == 'r') { + param_str_1 = strsep(&parse_str, ":"); + if (kstrtoul(param_str_1, 10, &seq)) { + ret = -EFAULT; + dev_dbg(ctrl->debug_fs->cam->dev, "kstrtoul failed:%s\n", + param_str_1); + goto FAIL; + } + + if (param_str_0[0] == 's') { + ret = mtk_cam_debug_dump_ctrl_set(ctrl, seq, true); + if (ret < 0) + goto FAIL; + } else if (param_str_0[0] == 'e') { + ret = mtk_cam_debug_dump_ctrl_set(ctrl, seq, false); + if (ret < 0) + goto FAIL; + } else { + ret = -EFAULT; + goto FAIL; + } + } else if (cmd_str[0] == 'd') { + if (param_str_0[0] == 's') { + mtk_cam_dump_buf_realloc(ctrl, MTK_CAM_DEBUG_DUMP_MAX_BUF); + debug_fs->force_dump = MTK_CAM_REQ_DUMP_FORCE; + } else if (param_str_0[0] == 'r') { + mtk_cam_dump_ctrl_reinit(ctrl); + debug_fs->force_dump = MTK_CAM_REQ_DUMP_FORCE; + } else if (param_str_0[0] == 'e') { + debug_fs->force_dump = 0; + mtk_cam_dump_buf_realloc(ctrl, 0); + } else { + ret = -EFAULT; + goto FAIL; + } + } + + return count; +FAIL: + return ret; +} + +static int dbg_data_open(struct inode *inode, struct file *file) +{ + struct mtk_cam_debug_fs *debug_fs; + struct mtk_cam_dump_buf_ctrl *ctrl; + + if (inode->i_private) + file->private_data = inode->i_private; + + ctrl = file->private_data; + debug_fs = ctrl->debug_fs; + + dev_dbg(debug_fs->cam->dev, + "%s:pipe(%d):cnt(%d), head(%d), tail(%d), entry_sz(%u), entry_num(%d)\n", + __func__, ctrl->pipe_id, ctrl->count, ctrl->head, ctrl->tail, + debug_fs->buf_size, ctrl->num); + + return 0; +} + +static ssize_t dbg_data_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct mtk_cam_dump_buf_ctrl *ctrl = file->private_data; + struct mtk_cam_debug_fs *debug_fs = ctrl->debug_fs; + struct mtk_cam_dump_ctrl_block *ctrl_block; + + int cur_read = 0; + size_t read_count; + + cur_read = ctrl->cur_read; + if (cur_read < 0) { + dev_dbg(debug_fs->cam->dev, + "%s:pipe(%d):user requested seq not found! cur_read(%d)\n", + __func__, ctrl->pipe_id, cur_read); + return 0; + } + + ctrl_block = &ctrl->blocks[cur_read]; + if (atomic_read(&ctrl_block->state) != CTRL_BLOCK_STATE_READ) + return 0; + + dev_dbg(debug_fs->cam->dev, + "%s:pipe(%d):read buf request: %zu bytes\n", __func__, + ctrl->pipe_id, count); + read_count = simple_read_from_buffer(user_buf, count, ppos, + ctrl_block->buf, + debug_fs->buf_size); + + return read_count; +} + +static int mtk_cam_debug_has_exp_dump(struct mtk_cam_debug_fs *debug_fs) +{ + return (atomic_read(&debug_fs->exp_dump_state) == CAMSYS_DUMP_SATATE_READY); +} + +static int exp_open(struct inode *inode, struct file *file) +{ + if (inode->i_private) + file->private_data = inode->i_private; + + return 0; +} + +static ssize_t exp_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct device *dev = file->private_data; + struct mtk_cam_device *cam; + struct mtk_cam_debug_fs *debug_fs; + size_t read_count; + + if (!dev) { + pr_debug("%s: dev can't be null\n", __func__); + return 0; + } + + cam = (struct mtk_cam_device *)dev_get_drvdata(dev); + if (!cam) { + dev_dbg(dev, "%s: cam can't be null\n", __func__); + return 0; + } + + debug_fs = cam->debug_fs; + if (!debug_fs) { + dev_dbg(dev, "%s: debug_fs can't be null\n", __func__); + return 0; + } + + if (!debug_fs->exp_dump_buf) { + dev_dbg(dev, "%s: dump buf can't be null\n", __func__); + return 0; + } + + /* If no dump, return 0 byte read directly */ + if (!mtk_cam_debug_has_exp_dump(debug_fs)) + return 0; + + dev_dbg(dev, "%s: read buf request: %zu bytes\n", __func__, count); + mutex_lock(&debug_fs->exp_dump_buf_lock); + + read_count = simple_read_from_buffer(user_buf, count, ppos, + debug_fs->exp_dump_buf, + debug_fs->buf_size); + + mutex_unlock(&debug_fs->exp_dump_buf_lock); + + return read_count; +} + +static int exp_release(struct inode *inode, struct file *file) +{ + struct device *dev; + struct mtk_cam_device *cam; + struct mtk_cam_debug_fs *debug_fs; + + dev = file->private_data; + if (!dev) { + pr_debug("%s: dev is NULL", __func__); + return 0; + } + + cam = (struct mtk_cam_device *)dev_get_drvdata(dev); + if (!cam) { + dev_dbg(dev, "%s: cam is NULL", __func__); + return 0; + } + + debug_fs = cam->debug_fs; + dev_dbg(dev, "%s dump_state: %d\n", __func__, + atomic_read(&debug_fs->exp_dump_state)); + + return 0; +} + +static const struct file_operations dbg_ctrl_fops = { + .open = dbg_ctrl_open, + .write = dbg_ctrl_write, +}; + +static const struct file_operations dbg_data_fops = { + .open = dbg_data_open, + .read = dbg_data_read, + .llseek = default_llseek, +}; + +static const struct file_operations exp_fops = { + .open = exp_open, + .read = exp_read, + .release = exp_release, +}; + +static int mtk_cam_exp_reinit(struct mtk_cam_debug_fs *debug_fs) +{ + /* Let the exception dump buffer can be written again */ + mutex_lock(&debug_fs->exp_dump_buf_lock); + atomic_set(&debug_fs->exp_dump_state, CAMSYS_DUMP_SATATE_INIT); + mutex_unlock(&debug_fs->exp_dump_buf_lock); + return 0; +} + +static int mtk_cam_debug_reinit(struct mtk_cam_debug_fs *debug_fs, + int streaming_id) +{ + struct mtk_cam_dump_buf_ctrl *ctrl; + + if (!debug_fs->force_dump) + return 0; + + ctrl = &debug_fs->ctrl[streaming_id]; + mtk_cam_dump_ctrl_reinit(ctrl); + + return 0; +} + +static int mtk_cam_debug_init(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_device *cam, u32 content_size) +{ + struct mtk_cam_dump_buf_ctrl *ctrl; + void *exp_dump_buf; + int i; + u32 dump_mem_size; + + dump_mem_size = content_size + sizeof(struct mtk_cam_dump_header); + debug_fs->cam = cam; + debug_fs->buf_size = dump_mem_size; + + /* Exception dump initialization*/ + exp_dump_buf = kzalloc(dump_mem_size, GFP_KERNEL); + if (!exp_dump_buf) + return -ENOMEM; + + debug_fs->exp_dump_buf = exp_dump_buf; + atomic_set(&debug_fs->exp_dump_state, CAMSYS_DUMP_SATATE_INIT); + mutex_init(&debug_fs->exp_dump_buf_lock); + + debug_fs->exp_dump_entry = debugfs_create_file("mtk_cam_exp_dump", + 0440, NULL, cam->dev, + &exp_fops); + if (!debug_fs->exp_dump_entry) { + dev_err(cam->dev, "Can't create debug fs\n"); + return -ENOMEM; + } + + debug_fs->dbg_entry = debugfs_create_dir("mtk_cam_dbg", NULL); + for (i = 0; i < cam->max_stream_num; i++) { + char name[4]; + + ctrl = &debug_fs->ctrl[i]; + ctrl->pipe_id = i; + ctrl->debug_fs = debug_fs; + atomic_set(&ctrl->dump_state, CAMSYS_DUMP_SATATE_INIT); + mutex_init(&ctrl->ctrl_lock); + + snprintf(name, 4, "%d", i); + ctrl->dir_entry = debugfs_create_dir(name, debug_fs->dbg_entry); + if (!ctrl->dir_entry) { + dev_err(cam->dev, "Can't create dir for pipe:%d\n", i); + return -ENOMEM; + } + + ctrl->ctrl_entry = debugfs_create_file("ctrl", 0640, + ctrl->dir_entry, ctrl, + &dbg_ctrl_fops); + if (!ctrl->ctrl_entry) { + dev_err(cam->dev, + "Can't create ctrl file for pipe:%d\n", i); + return -ENOMEM; + } + + ctrl->data_entry = debugfs_create_file("data", 0440, + ctrl->dir_entry, ctrl, + &dbg_data_fops); + if (!ctrl->data_entry) { + dev_err(cam->dev, + "Can't create data file for pipe:%d\n", i); + return -ENOMEM; + } + } + + return 0; +} + +static void mtk_cam_debug_deinit(struct mtk_cam_debug_fs *debug_fs) +{ + struct mtk_cam_dump_buf_ctrl *ctrl; + int i; + + if (!debug_fs) + return; + + for (i = 0; i < debug_fs->cam->max_stream_num; i++) { + ctrl = &debug_fs->ctrl[i]; + debugfs_remove(ctrl->ctrl_entry); + debugfs_remove(ctrl->data_entry); + debugfs_remove(ctrl->dir_entry); + } + + debugfs_remove(debug_fs->dbg_entry); + kfree(debug_fs->exp_dump_buf); + dev_dbg(debug_fs->cam->dev, "Free exception dump buffer\n"); + debugfs_remove(debug_fs->exp_dump_entry); +} + +static void mtk_cam_debug_dump_work(struct work_struct *work) +{ + struct mtk_cam_req_dbg_work *dbg_work = to_mtk_cam_req_dbg_work(work); + struct mtk_cam_request_stream_data *s_data = dbg_work->s_data; + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + struct mtk_cam_dump_param dump_param; + struct v4l2_event event = { + .type = V4L2_EVENT_REQUEST_DUMPED, + }; + int ret = 0; + + ret = mtk_cam_debug_init_dump_param(ctx, &dump_param, s_data, + dbg_work->desc); + if (ret < 0) { + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + return; + } + + ctx->cam->debug_fs->ops->dump(ctx->cam->debug_fs, &dump_param); + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + + event.u.frame_sync.frame_sequence = dump_param.sequence; + v4l2_event_queue(ctx->pipe->subdev.devnode, &event); +} + +#define EXCEPT_DUMP_SIZE 128 +static void mtk_cam_exception_work(struct work_struct *work) +{ + struct mtk_cam_req_dbg_work *dbg_work = to_mtk_cam_req_dbg_work(work); + struct mtk_cam_request_stream_data *s_data = dbg_work->s_data; + struct mtk_cam_request *req = mtk_cam_s_data_get_req(s_data); + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + struct mtk_cam_dump_param dump_param; + char warn_desc[EXCEPT_DUMP_SIZE]; + char title_desc[EXCEPT_DUMP_SIZE]; + int ret = 0; + + if (!s_data) + return; + + if (atomic_read(&s_data->dbg_exception_work.state) == MTK_CAM_REQ_DBGWORK_S_CANCEL) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):used_raw(0x%x):exception dump canceled\n", + __func__, ctx->stream_id, ctx->used_raw_dev); + return; + } + + ret = mtk_cam_debug_init_dump_param(ctx, &dump_param, s_data, + dbg_work->desc); + + if (ret < 0) { + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + return; + } + + ctx->cam->debug_fs->ops->exp_dump(ctx->cam->debug_fs, &dump_param); + snprintf(title_desc, EXCEPT_DUMP_SIZE, "Camsys:%s", dbg_work->desc); + snprintf(warn_desc, EXCEPT_DUMP_SIZE, "%s:ctx(%d):req(%d):%s", + req->req.debug_str, ctx->stream_id, s_data->frame_seq_no, + dbg_work->desc); + dev_info(ctx->cam->dev, "%s:camsys dump, %s\n", + __func__, warn_desc); + + WARN_ON(1); + + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_FINISHED); +} + +static bool +mtk_cam_exceptoin_is_job_done(struct mtk_cam_request_stream_data *s_data, + bool *streamoff) +{ + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + int state; + + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + spin_unlock(&ctx->streaming_lock); + *streamoff = true; + return true; + } + spin_unlock(&ctx->streaming_lock); + + state = atomic_read(&s_data->dbg_exception_work.state); + if (state == MTK_CAM_REQ_DBGWORK_S_FINISHED || + state == MTK_CAM_REQ_DBGWORK_S_INIT || + state == MTK_CAM_REQ_DBGWORK_S_CANCEL) { + *streamoff = false; + return true; + } + + return false; +} + +static void mtk_cam_exceptoin_detect_work(struct work_struct *work) +{ + struct mtk_cam_req_dbg_work *dbg_work = to_mtk_cam_req_dbg_work(work); + struct mtk_cam_request_stream_data *s_data = dbg_work->s_data; + struct mtk_cam_request *req = mtk_cam_s_data_get_req(s_data); + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + int ret; + bool streamoff = false; + + ret = wait_event_freezable_timeout(ctx->cam->debug_exception_waitq, + mtk_cam_exceptoin_is_job_done(s_data, &streamoff), + msecs_to_jiffies(1000 / 30 * 8)); + if (ret) { + if (!streamoff) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):%s:req(%d):skip dump since job done\n", + __func__, ctx->stream_id, req->req.debug_str, + s_data->frame_seq_no); + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + } else { + /** + * Workaround for abnormal request release after + * streaming off now, we can't touch the request + * any more. + */ + dev_info(ctx->cam->dev, + "%s: skip dump work for stream off ctx:%d\n", + __func__, ctx->stream_id); + } + return; + } + + if (atomic_read(&s_data->dbg_exception_work.state) == MTK_CAM_REQ_DBGWORK_S_CANCEL) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):used_raw(0x%x):exception dump canceled\n", + __func__, ctx->stream_id, ctx->used_raw_dev); + return; + } + + if (ctx->seninf) { + ret = mtk_cam_seninf_dump(ctx->seninf); + dev_info(ctx->cam->dev, + "%s:ctx(%d):used_raw(0x%x):mtk_cam_seninf_dump() ret=%d\n", + __func__, ctx->stream_id, ctx->used_raw_dev, ret); + } else { + dev_info(ctx->cam->dev, "%s: cannot find ctx->seninf\n", + __func__); + } + + mtk_cam_exception_work(work); +} + +int mtk_cam_req_dump(struct mtk_cam_request_stream_data *s_data, + unsigned int dump_flag, char *desc, bool smi_dump) +{ + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + struct mtk_cam_req_dbg_work *dbg_work; + void (*work_func)(struct work_struct *work); + struct workqueue_struct *wq; + + if (!ctx->cam->debug_fs) + return false; + + switch (dump_flag) { + case MTK_CAM_REQ_DUMP_FORCE: + if (!ctx->cam->debug_fs->force_dump || + !ctx->cam->debug_fs->ctrl[ctx->stream_id].num) + return false; + + dbg_work = &s_data->dbg_work; + work_func = mtk_cam_debug_dump_work; + wq = ctx->cam->debug_wq; + break; + case MTK_CAM_REQ_DUMP_DEQUEUE_FAILED: + dbg_work = &s_data->dbg_exception_work; + work_func = mtk_cam_exception_work; + wq = ctx->cam->debug_exception_wq; + break; + case MTK_CAM_REQ_DUMP_CHK_DEQUEUE_FAILED: + dbg_work = &s_data->dbg_exception_work; + work_func = mtk_cam_exceptoin_detect_work; + wq = ctx->cam->debug_exception_wq; + break; + default: + dev_dbg(ctx->cam->dev, + "%s:seq(%d) dump skipped, unknown dump type (%d)\n", + __func__, s_data->frame_seq_no, + dump_flag); + return false; + } + + if (atomic_read(&dbg_work->state) != MTK_CAM_REQ_DBGWORK_S_INIT) + return false; + + INIT_WORK(&dbg_work->work, work_func); + dbg_work->s_data = s_data; + dbg_work->dump_flags = dump_flag; + dbg_work->smi_dump = smi_dump; + atomic_set(&dbg_work->state, MTK_CAM_REQ_DBGWORK_S_PREPARED); + snprintf(dbg_work->desc, MTK_CAM_DEBUG_DUMP_DESC_SIZE - 1, desc); + if (!queue_work(wq, &dbg_work->work)) { + dev_dbg(ctx->cam->dev, + "%s: seq(%d) failed, debug work is already in queue\n", + __func__, s_data->frame_seq_no); + return false; + } + + return true; +} + +void +mtk_cam_debug_detect_dequeue_failed(struct mtk_cam_request_stream_data *s_data, + const unsigned int frame_no_update_limit, + struct mtk_camsys_irq_info *irq_info, + struct mtk_raw_device *raw_dev) +{ +#define NO_P1_DONE_DEBUG_START 3 + + struct mtk_cam_ctx *ctx; + struct mtk_cam_request *req; + + if (irq_info->fbc_cnt == 0) + return; + /** + * If the requset is already dequeued (for example, the p1 done and + * sof interrupt come almost together), skip the check. + */ + if (!s_data) + return; + + ctx = mtk_cam_s_data_get_ctx(s_data); + req = mtk_cam_s_data_get_req(s_data); + + if (ctx->composed_frame_seq_no < ctx->dequeued_frame_seq_no) + return; + + if (s_data->state.estate == E_STATE_CQ || + s_data->state.estate == E_STATE_OUTER || + s_data->state.estate == E_STATE_INNER || + s_data->state.estate == E_STATE_OUTER_HW_DELAY || + s_data->state.estate == E_STATE_INNER_HW_DELAY) { + s_data->no_frame_done_cnt++; + if (s_data->no_frame_done_cnt > 1) + dev_info(ctx->cam->dev, + "%s:SOF[ctx:%d-#%d] no p1 done for %d sofs, FBC_CNT %d dump req(%d) state(%d) ts(%llu)\n", + req->req.debug_str, ctx->stream_id, + ctx->dequeued_frame_seq_no, + s_data->no_frame_done_cnt, irq_info->fbc_cnt, + s_data->frame_seq_no, s_data->state.estate, + irq_info->ts_ns); + } + if (s_data->no_frame_done_cnt >= NO_P1_DONE_DEBUG_START) { + dev_info(raw_dev->dev, + "INT_EN %x\n", + readl_relaxed(raw_dev->base + REG_CTL_RAW_INT_EN)); + + dev_info(raw_dev->dev, + "REQ RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD5_REQ_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD6_REQ_STAT)); + dev_info(raw_dev->dev, + "RDY RAW/2/3 DMA/2:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD5_RDY_STAT), + readl_relaxed(raw_dev->base + REG_CTL_RAW_MOD6_RDY_STAT)); + dev_info(raw_dev->dev, + "REQ YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD2_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD3_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD4_REQ_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD5_REQ_STAT)); + dev_info(raw_dev->dev, + "RDY YUV/2/3/4 WDMA:%08x/%08x/%08x/%08x/%08x\n", + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD2_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD3_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD4_RDY_STAT), + readl_relaxed(raw_dev->yuv_base + REG_CTL_RAW_MOD5_RDY_STAT)); + } + + if (s_data->no_frame_done_cnt > frame_no_update_limit && + s_data->dbg_work.dump_flags == 0) { + dev_info(ctx->cam->dev, + "%s:SOF[ctx:%d-#%d] no p1 done for %d sofs, FBC_CNT %d dump req(%d) state(%d) ts(%llu)\n", + req->req.debug_str, ctx->stream_id, + ctx->dequeued_frame_seq_no, + s_data->no_frame_done_cnt, irq_info->fbc_cnt, + s_data->frame_seq_no, + s_data->state.estate, irq_info->ts_ns); + mtk_cam_req_dump(s_data, MTK_CAM_REQ_DUMP_DEQUEUE_FAILED, + "No P1 done", false); + } else if (s_data->no_frame_done_cnt > frame_no_update_limit && + s_data->dbg_work.dump_flags != 0) { + dev_info(ctx->cam->dev, + "%s:SOF[ctx:%d-#%d] no p1 done for %d sofs, s_data->dbg_work.dump_flags(%d) state(%d) ts(%llu)\n", + req->req.debug_str, ctx->stream_id, + ctx->dequeued_frame_seq_no, + s_data->no_frame_done_cnt, s_data->dbg_work.dump_flags, + s_data->state.estate, irq_info->ts_ns); + } +} + +void mtk_cam_debug_wakeup(struct wait_queue_head *wq_head) +{ + wake_up(wq_head); +} + +static void mtk_cam_req_seninf_dump_work(struct work_struct *work) +{ + struct mtk_cam_seninf_dump_work *seninf_dump_work; + struct v4l2_subdev *seninf; + + seninf_dump_work = to_mtk_cam_seninf_dump_work(work); + seninf = seninf_dump_work->seninf; + if (!seninf) + pr_info("%s: filaed, seninf can't be NULL\n", __func__); + else + mtk_cam_seninf_dump(seninf); + + kfree(seninf_dump_work); +} + +void +mtk_cam_debug_seninf_dump(struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_ctx *ctx; + struct mtk_cam_seninf_dump_work *dump_work; + + ctx = mtk_cam_s_data_get_ctx(s_data); + if (!ctx) { + pr_info("%s: failed, ctx can't be NULL\n", __func__); + return; + } + + spin_lock(&ctx->streaming_lock); + if (!ctx->streaming) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):s_data(%d) drop dump due to stream off\n", + __func__, ctx->stream_id, s_data->frame_seq_no); + spin_unlock(&ctx->streaming_lock); + return; + } + spin_unlock(&ctx->streaming_lock); + + if (atomic_read(&s_data->seninf_dump_state) != MTK_CAM_REQ_DBGWORK_S_INIT) { + dev_info(ctx->cam->dev, + "%s:ctx(%d):s_data(%d) drop duplicated dump\n", + __func__, ctx->stream_id, s_data->frame_seq_no); + + return; + } + + dump_work = kmalloc(sizeof(*dump_work), GFP_ATOMIC); + if (!dump_work) + return; + + dump_work->seninf = ctx->seninf; + INIT_WORK(&dump_work->work, mtk_cam_req_seninf_dump_work); + if (!queue_work(ctx->frame_done_wq, &dump_work->work)) + dev_info(ctx->cam->dev, + "%s:ctx(%d):s_data(%d) work was already on a queue\n", + __func__, ctx->stream_id, s_data->frame_seq_no); + else + atomic_set(&s_data->seninf_dump_state, MTK_CAM_REQ_DBGWORK_S_FINISHED); +} + +void mtk_cam_req_dump_work_init(struct mtk_cam_request_stream_data *s_data) +{ + atomic_set(&s_data->seninf_dump_state, MTK_CAM_REQ_DBGWORK_S_INIT); +} + +void mtk_cam_req_dbg_works_clean(struct mtk_cam_request_stream_data *s_data) +{ + struct mtk_cam_ctx *ctx = mtk_cam_s_data_get_ctx(s_data); + char *dbg_str = mtk_cam_s_data_get_dbg_str(s_data); + int state; + u64 start, cost; + + /* clean seninf dump work */ + atomic_set(&s_data->seninf_dump_state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + + /* clean execption dump work */ + state = atomic_read(&s_data->dbg_exception_work.state); + if (state != MTK_CAM_REQ_DBGWORK_S_INIT && + state != MTK_CAM_REQ_DBGWORK_S_FINISHED) { + atomic_set(&s_data->dbg_exception_work.state, MTK_CAM_REQ_DBGWORK_S_CANCEL); + mtk_cam_debug_wakeup(&ctx->cam->debug_exception_waitq); + start = ktime_get_boottime_ns(); + cancel_work_sync(&s_data->dbg_exception_work.work); + cost = ktime_get_boottime_ns() - start; + + dev_info(ctx->cam->dev, + "%s:ctx(%d):%s:seq(%d): cancel dbg_exception_work(%d), wait: %llu ns\n", + __func__, ctx->stream_id, dbg_str, + s_data->frame_seq_no, state, cost); + atomic_set(&s_data->dbg_exception_work.state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + } else { + mtk_cam_debug_wakeup(&ctx->cam->debug_exception_waitq); + atomic_set(&s_data->dbg_exception_work.state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + } + + /* clean debug dump work */ + state = atomic_read(&s_data->dbg_work.state); + if (state != MTK_CAM_REQ_DBGWORK_S_INIT && + state != MTK_CAM_REQ_DBGWORK_S_FINISHED) { + start = ktime_get_boottime_ns(); + cancel_work_sync(&s_data->dbg_work.work); + cost = ktime_get_boottime_ns() - start; + dev_info(ctx->cam->dev, + "%s:ctx(%d):%s:seq(%d): cancel dbg_work(%d), wait: %llu ns\n", + __func__, ctx->stream_id, dbg_str, + s_data->frame_seq_no, state, cost); + atomic_set(&s_data->dbg_work.state, MTK_CAM_REQ_DBGWORK_S_FINISHED); + } +} + +static struct mtk_cam_debug_ops debug_ops = { + .init = mtk_cam_debug_init, + .reinit = mtk_cam_debug_reinit, + .deinit = mtk_cam_debug_deinit, + .dump = mtk_cam_debug_dump, + .exp_reinit = mtk_cam_exp_reinit, + .exp_dump = mtk_cam_debug_exp_dump, +}; + +static struct mtk_cam_debug_fs debug_fs = { + .ops = &debug_ops, +}; + +struct mtk_cam_debug_fs *mtk_cam_get_debugfs(void) +{ + return &debug_fs; +} + +#endif /* CONFIG_DEBUG_FS */ diff --git a/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.h b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.h new file mode 100644 index 000000000000..91e695ff2e76 --- /dev/null +++ b/drivers/media/platform/mediatek/isp/isp_7x/camsys/mtk_cam-debug.h @@ -0,0 +1,273 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * Copyright (c) 2022 MediaTek Inc. + */ + +#ifndef __MTK_CAM_DEBUG__ +#define __MTK_CAM_DEBUG__ + +#include + +struct mtk_cam_device; +struct mtk_cam_dump_param; +struct mtk_raw_device; +struct mtk_cam_request; +struct mtk_cam_request_stream_data; +struct mtk_cam_debug_fs; + +#define MTK_CAM_DEBUG_DUMP_MAX_BUF (33 * 5) +#define MTK_CAM_DEBUG_DUMP_DESC_SIZE 64 +#define MTK_CAM_DEBUG_DUMP_HEADER_MAX_SIZE 0x1000 + +/* Force dump by user */ +#define MTK_CAM_REQ_DUMP_FORCE BIT(0) +/* Triggered when dequeue failed */ +#define MTK_CAM_REQ_DUMP_DEQUEUE_FAILED BIT(1) +/** + * Triggered when SOF may not come aganin. In this + * case, we will check if the request's state is + * still the same as the original one and start the + * dump if the state does not change. + */ +#define MTK_CAM_REQ_DUMP_CHK_DEQUEUE_FAILED BIT(2) +#define MTK_CAM_REQ_DBGWORK_S_INIT 0 +#define MTK_CAM_REQ_DBGWORK_S_PREPARED 1 +#define MTK_CAM_REQ_DBGWORK_S_FINISHED 2 +#define MTK_CAM_REQ_DBGWORK_S_CANCEL 3 + +struct mtk_cam_dump_param { + /* Common Debug Information*/ + char *desc; + u32 request_fd; + u32 stream_id; + u64 timestamp; + u32 sequence; + + /* CQ dump */ + void *cq_cpu_addr; + u32 cq_size; + u64 cq_iova; + u32 cq_desc_offset; + u32 cq_desc_size; + u32 sub_cq_desc_offset; + u32 sub_cq_desc_size; + + /* meta in */ + void *meta_in_cpu_addr; + u32 meta_in_dump_buf_size; + u64 meta_in_iova; + + /* meta out 0 */ + void *meta_out_0_cpu_addr; + u32 meta_out_0_dump_buf_size; + u64 meta_out_0_iova; + + /* meta out 1 */ + void *meta_out_1_cpu_addr; + u32 meta_out_1_dump_buf_size; + u64 meta_out_1_iova; + + /* meta out 2 */ + void *meta_out_2_cpu_addr; + u32 meta_out_2_dump_buf_size; + u64 meta_out_2_iova; + + /* ipi frame param */ + struct mtkcam_ipi_frame_param *frame_params; + u32 frame_param_size; + + /* ipi config param */ + struct mtkcam_ipi_config_param *config_params; + u32 config_param_size; +}; + +struct mtk_cam_req_dump_work { + struct work_struct work; + atomic_t state; + unsigned int dump_flags; +}; + +struct mtk_cam_seninf_dump_work { + struct work_struct work; + struct v4l2_subdev *seninf; +}; + +struct mtk_cam_req_dbg_work { + struct work_struct work; + struct mtk_cam_request_stream_data *s_data; + atomic_t state; + unsigned int dump_flags; + int buffer_state; + char desc[MTK_CAM_DEBUG_DUMP_DESC_SIZE]; + bool smi_dump; +}; + +struct mtk_cam_dump_header { + /* Common Debug Information*/ + u8 desc[MTK_CAM_DEBUG_DUMP_DESC_SIZE]; + u32 request_fd; + u32 stream_id; + u64 timestamp; + u32 sequence; + u32 header_size; + u32 payload_offset; + u32 payload_size; + + /* meta file information */ + u32 meta_version_major; + u32 meta_version_minor; + + /* CQ dump */ + u32 cq_dump_buf_offset; + u32 cq_size; + u64 cq_iova; + u32 cq_desc_offset; + u32 cq_desc_size; + u32 sub_cq_desc_offset; + u32 sub_cq_desc_size; + + /* meta in */ + u32 meta_in_dump_buf_offset; + u32 meta_in_dump_buf_size; + u64 meta_in_iova; + + /* meta out 0 */ + u32 meta_out_0_dump_buf_offset; + u32 meta_out_0_dump_buf_size; + u64 meta_out_0_iova; + + /* meta out 1 */ + u32 meta_out_1_dump_buf_offset; + u32 meta_out_1_dump_buf_size; + u64 meta_out_1_iova; + + /* meta out 2 */ + u32 meta_out_2_dump_buf_offset; + u32 meta_out_2_dump_buf_size; + u64 meta_out_2_iova; + + /* status dump */ + u32 status_dump_offset; + u32 status_dump_size; + + /* ipi frame param */ + u32 frame_dump_offset; + u32 frame_dump_size; + + /* ipi config param */ + u32 config_dump_offset; + u32 config_dump_size; + u32 used_stream_num; +}; + +struct mtk_cam_dump_ctrl_block { + atomic_t state; + void *buf; +}; + +struct mtk_cam_dump_buf_ctrl { + int pipe_id; + struct mtk_cam_debug_fs *debug_fs; + struct mtk_cam_dump_ctrl_block blocks[MTK_CAM_DEBUG_DUMP_MAX_BUF]; + struct dentry *dir_entry; + struct dentry *ctrl_entry; + struct dentry *data_entry; + struct mutex ctrl_lock; /* protect blocks */ + int head; + int tail; + int num; + int count; + int cur_read; + atomic_t dump_state; + struct dentry *dump_entry; +}; + +struct mtk_cam_debug_ops { + int (*init)(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_device *cam, u32 content_size); + int (*dump)(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_param *param); + int (*exp_dump)(struct mtk_cam_debug_fs *debug_fs, + struct mtk_cam_dump_param *param); + int (*exp_reinit)(struct mtk_cam_debug_fs *debug_fs); + int (*reinit)(struct mtk_cam_debug_fs *debug_fs, int stream_id); + void (*deinit)(struct mtk_cam_debug_fs *debug_fs); +}; + +struct mtk_cam_debug_fs { + struct mtk_cam_device *cam; + uint force_dump; + void *exp_dump_buf; /* kernel exception dump */ + atomic_t exp_dump_state; + struct mutex exp_dump_buf_lock; /* protect exp_dump_buf */ + struct dentry *exp_dump_entry; + u32 buf_size; + struct dentry *dbg_entry; + struct mtk_cam_dump_buf_ctrl ctrl[MTKCAM_SUBDEV_MAX]; + struct mtk_cam_debug_ops *ops; +}; + +#ifndef CONFIG_DEBUG_FS +static inline struct mtk_cam_debug_fs *mtk_cam_get_debugfs(void) +{ + return NULL; +} + +static inline int +mtk_cam_req_dump(struct mtk_cam_request_stream_data *s_data, + unsigned int dump_flag, char *desc, bool smi_dump) +{ + return 0; +} + +static inline void +mtk_cam_debug_detect_dequeue_failed(struct mtk_cam_request_stream_data *s_data, + const unsigned int frame_no_update_limit, + struct mtk_camsys_irq_info *irq_info, + struct mtk_raw_device *raw_dev) +{ +} + +static inline void mtk_cam_debug_wakeup(struct wait_queue_head *wq_head) +{ +} + +static inline void +mtk_cam_req_dump_work_init(struct mtk_cam_request_stream_data *s_data) +{ +} + +static inline void +mtk_cam_req_dbg_works_clean(struct mtk_cam_request_stream_data *s_data) +{ +} + +static inline void +mtk_cam_debug_seninf_dump(struct mtk_cam_request_stream_data *s_data) +{ +} + +#else + +struct mtk_cam_debug_fs *mtk_cam_get_debugfs(void); + +int mtk_cam_req_dump(struct mtk_cam_request_stream_data *s_data, + unsigned int dump_flag, char *desc, bool smi_dump); +void +mtk_cam_debug_detect_dequeue_failed(struct mtk_cam_request_stream_data *s_data, + const unsigned int frame_no_update_limit, + struct mtk_camsys_irq_info *irq_info, + struct mtk_raw_device *raw_dev); +void mtk_cam_debug_wakeup(struct wait_queue_head *wq_head); +void mtk_cam_req_dump_work_init(struct mtk_cam_request_stream_data *s_data); +void mtk_cam_req_dbg_works_clean(struct mtk_cam_request_stream_data *s_data); +void mtk_cam_debug_seninf_dump(struct mtk_cam_request_stream_data *s_data); +#endif /* CONFIG_DEBUG_FS */ + +static inline struct mtk_cam_req_dbg_work * +to_mtk_cam_req_dbg_work(struct work_struct *__work) +{ + return container_of(__work, struct mtk_cam_req_dbg_work, work); +} + +#endif /* __MTK_CAM_DEBUG__ */ 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: 13828182 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 545F0CF0453 for ; Wed, 9 Oct 2024 11:21:43 +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=PZ74klURlzV6qwB2japBK034/Y E36j8WKFR/gTQpMT/mWOGy4xJij9h8njHI+xdYOcWHJwGJLp4g1S0qjmHMWbYa8h+gUEA3zFQq1fK OJV6f8YLN0N+LXFLYeqc1uVyAJ79q6oWbjz6Ov8F3HryqPp2kW5eu7nAuyXnrbHoahHpSeyXRqtyX L89Rsi0pshN8rrSl5kIEyXEJuOk9YI+l8zcxBIzrQ30/M7bOFnTrDi+Wy19H9GDC1kocLS7zsy9Kg VK5Zr4oH/Wriht9ulvRVxEIzkVNriUDEFKSHK4csvZuHfZuZVu3pSWWbLqeV3wFeJGVIkpDYXNTZS JAPsm1jw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUlC-000000092Lx-16OP; Wed, 09 Oct 2024 11:21:42 +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-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=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: 13828186 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 1C9C3CF0453 for ; Wed, 9 Oct 2024 11:23:07 +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=iJ9bc7Vrdb0YNMZ7I4PaLwd8E3 MNUy1TXurmuWXCcF3MGxnTYRQQ26PvZSNp2mu/SrD6HEeLG4ZbnqSl7VnmSlqw9Ew/yVTPrhcLVnh br9kcozYLdrjvidexJ7Wn8Bc6TSj+uPsSj15L9SfQwFqTMSjvGgBjc45eSQhCnHGRntrrkwg06vgp 4g+ju3YAf43kF6XIuVtOHb3pqYr2ncISFvpEgzMPENy+o3F0sPGk/pY1X75FHzCuuy5xitWduH9m3 SL8K7K6kC8/FMClIy/asfeLy5NcmiJ2XdCdGjpupdPxHCizPjRxyQiyBO/8aIcag1130Dl6ss5mCc QOpxMn6Q==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.98 #2 (Red Hat Linux)) id 1syUmY-000000092nm-0SZn; Wed, 09 Oct 2024 11:23:06 +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-mediatek@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-mediatek" Errors-To: linux-mediatek-bounces+linux-mediatek=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 */