From nobody Fri Oct 3 15:34:23 2025 Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C7EA92ECEAC for ; Thu, 28 Aug 2025 08:59:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.33 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371573; cv=none; b=Tj5jXp4TChs2apjWa+/wvofG0XOfScOwubRbWps4tTs1Gt+TULU4H22it0H/FOAuqz0P2lvBGpMJ9UEKtCCOhIsAxRz70WnNMHCWCoZqtFzTYBKDVu/Nj0SLgNMOA7sFSPBZZvOTKk3y8EdPgf4HSlSmjmgGc5vLiFc0KUGIjVA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371573; c=relaxed/simple; bh=dQvNhzCuQBbDzPTHUgUTSzIHMORb3jTRG7p6bMnYcPM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=ZYWMbH6AoP45qSOKdpxIePUnyf7Zab6JAvBZd396JJPWsKte60q2G4SK6MfHBTwCd4/497vEvt6o52zi2gOrNVJupckG5SlKLjDvFJXP6LkBuT0f8+qin3dZQ0x5qluOhHm/wx5+cjYuCh6siG9Fqvy1PW5q3kF19XlzHoiIL0I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=FHkLhmcR; arc=none smtp.client-ip=203.254.224.33 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="FHkLhmcR" Received: from epcas5p4.samsung.com (unknown [182.195.41.42]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250828085928epoutp0357a313f291f2d64cc75f6439b0b75148~f4qLkw9yF0107501075epoutp03l for ; Thu, 28 Aug 2025 08:59:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250828085928epoutp0357a313f291f2d64cc75f6439b0b75148~f4qLkw9yF0107501075epoutp03l DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371568; bh=Nh+NV/RCQEe7YpPNjzL9CCS4Sy68m8a+56F+E9QurCM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=FHkLhmcR1r597S1wksvh9dJ25IOlg8H66lwtNHHyS6dMC8Y25dIfXxWyuNk7xk03m kSqiVaEAPRubOUHPXOA+zMhM1y6PGGS9feTRAH3Ct1CkG71EpsOxnLqVi7gVC7P7tv zrp9m1ACpvcU9YYIvv2DZgZEKqRXAYF0T5YkFziY= Received: from epsnrtp02.localdomain (unknown [182.195.42.154]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPS id 20250828085928epcas5p13a4867c73b3c3e4ba4afbd9dd228c504~f4qK_IiF00547205472epcas5p1w; Thu, 28 Aug 2025 08:59:28 +0000 (GMT) Received: from epcas5p4.samsung.com (unknown [182.195.38.92]) by epsnrtp02.localdomain (Postfix) with ESMTP id 4cCFhH2CZWz2SSKZ; Thu, 28 Aug 2025 08:59:27 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPA id 20250828085926epcas5p1b82576210280fb44c6c7f02851da71c6~f4qJgV6OG0547105471epcas5p1m; Thu, 28 Aug 2025 08:59:26 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085923epsmtip25f82c5e1bb289e9b9357c0b6a86fd6d4~f4qG3h2CV0309203092epsmtip2h; Thu, 28 Aug 2025 08:59:23 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 1/7] dt-bindings: media: nxp: Add support for FSD SoC Date: Thu, 28 Aug 2025 14:29:05 +0530 Message-ID: <20250828085911.81266-2-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085926epcas5p1b82576210280fb44c6c7f02851da71c6 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085926epcas5p1b82576210280fb44c6c7f02851da71c6 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Tesla FSD CSIS link controller is used to configure MIPI CSI-2 Rx link operations. The Tesla FSD SoC include a MIPI CSI-2 Rx IP core named CSIS, which is compatible with the CSIS IP found in NXP i.MX7 and i.MX8 SoCs. Add the compatible string "tesla,fsd-mipi-csi2" to support the MIPI CSI-2 Rx link operation on the Tesla FSD SoC. Signed-off-by: Inbaraj E --- .../bindings/media/nxp,imx-mipi-csi2.yaml | 91 +++++++++++++++---- 1 file changed, 71 insertions(+), 20 deletions(-) diff --git a/Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml= b/Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml index 41ad5b84eaeb..39b9447fd40c 100644 --- a/Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml +++ b/Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml @@ -14,7 +14,7 @@ description: |- The NXP i.MX7 and i.MX8 families contain SoCs that include a MIPI CSI-2 receiver IP core named CSIS. The IP core originates from Samsung, and ma= y be compatible with some of the Exynos4 and S5P SoCs. i.MX7 SoCs use CSIS ve= rsion - 3.3, and i.MX8 SoCs use CSIS version 3.6.3. + 3.3, i.MX8 SoCs use CSIS version 3.6.3 and FSD SoC uses CSIS version 4.3. =20 While the CSI-2 receiver is separate from the MIPI D-PHY IP core, the PH= Y is completely wrapped by the CSIS and doesn't expose a control interface of= its @@ -26,6 +26,7 @@ properties: - enum: - fsl,imx7-mipi-csi2 - fsl,imx8mm-mipi-csi2 + - tesla,fsd-mipi-csi2 - items: - enum: - fsl,imx8mp-mipi-csi2 @@ -38,24 +39,21 @@ properties: maxItems: 1 =20 clocks: - minItems: 3 - items: - - description: The peripheral clock (a.k.a. APB clock) - - description: The external clock (optionally used as the pixel cloc= k) - - description: The MIPI D-PHY clock - - description: The AXI clock + minItems: 2 + maxItems: 4 =20 clock-names: - minItems: 3 - items: - - const: pclk - - const: wrap - - const: phy - - const: axi + minItems: 2 + maxItems: 4 =20 power-domains: maxItems: 1 =20 + tesla,syscon-csis: + $ref: /schemas/types.yaml#/definitions/phandle-array + description: + Syscon used to hold and release the reset of MIPI D-PHY + phy-supply: description: The MIPI D-PHY digital power supply =20 @@ -93,7 +91,8 @@ properties: properties: data-lanes: description: - Note that 'fsl,imx7-mipi-csi2' only supports up to 2 dat= a lines. + Note that 'fsl,imx7-mipi-csi2' only supports up to 2 data + lines. minItems: 1 items: - const: 1 @@ -115,7 +114,6 @@ required: - interrupts - clocks - clock-names - - power-domains - ports =20 additionalProperties: false @@ -124,20 +122,73 @@ allOf: - if: properties: compatible: - contains: - const: fsl,imx7-mipi-csi2 + const: fsl,imx7-mipi-csi2 then: + properties: + clocks: + items: + - description: The peripheral clock (a.k.a. APB clock) + - description: The external clock (optionally used as the pixel + clock) + - description: The MIPI D-PHY clock + clock-names: + items: + - const: pclk + - const: wrap + - const: phy + tesla,syscon-csis: false + fsl,num-channels: false required: + - power-domains - phy-supply - resets - else: + + - if: + properties: + compatible: + const: fsl,imx8mm-mipi-csi2 + then: properties: clocks: - minItems: 4 + items: + - description: The peripheral clock (a.k.a. APB clock) + - description: The external clock (optionally used as the pixel + clock) + - description: The MIPI D-PHY clock + - description: The AXI clock clock-names: - minItems: 4 + items: + - const: pclk + - const: wrap + - const: phy + - const: axi + tesla,syscon-csis: false + fsl,num-channels: false phy-supply: false resets: false + required: + - power-domains + + - if: + properties: + compatible: + const: tesla,fsd-mipi-csi2 + then: + properties: + clocks: + items: + - description: The peripheral clock (a.k.a. APB clock) + - description: The DMA clock + clocks-names: + items: + - const: pclk + - const: aclk + phy-supply: false + resets: false + power-domains: false + required: + - tesla,syscon-csis + - fsl,num-channels =20 examples: - | --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D16892F363A for ; Thu, 28 Aug 2025 08:59:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371576; cv=none; b=RvTQI8UCFS3OC3Jzm8FTflvOLnyQlVmfBxLXd6335lP+miIweCRtLs+P0hANAUbBYMOkrpOOWF8v1sgA5SsosW7rc3cGgwRdF9x1Pgdm1Y86gEbL6MM5mcFDSwwLuENJjpaxyQjbJgVjjtNi+iqMbVlRwV07f59X/SRstVsvn/E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371576; c=relaxed/simple; bh=QBRMX12lgkd2k2KHBbSFK2RcHJBR3Mt0jOEFKQq+tmw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=Ezqjs8+Yg8T/+UCcp0iBkELREmgNM399tCb5CksD1vkV9FE+gb3G0b+ImPTpz4wH/2RTD/cHexzibaFEro8iCkxiUdz0H+iSj5YeoDqvhHNxxvdjtKEc5uGeXCAPmu1eLmf3hsEpqaibIrAK4KbnWf6ot4RAOYcpaQ/5eIkdbwg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=bJb0VE+L; arc=none smtp.client-ip=203.254.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="bJb0VE+L" Received: from epcas5p1.samsung.com (unknown [182.195.41.39]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250828085933epoutp042be560ee76f91a0f291029335cc2fa74~f4qPhFc_B2596825968epoutp04q for ; Thu, 28 Aug 2025 08:59:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250828085933epoutp042be560ee76f91a0f291029335cc2fa74~f4qPhFc_B2596825968epoutp04q DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371573; bh=XTEfXLQM+A9VUaqsYa0+kOHsGPzuzCyuDiyg7PrGRkI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=bJb0VE+LFxbL7o1vASQsDB0UHU+p9VXoi7orhWHXFdgBRjL/mAgmjaDorAUNtZOQ2 jwbIleKDa6ZmImqanCLWLPK4ZJlJWUuqA+b5AI71mH1AQuyFWJPpcir+e1DOmIaCz3 uFhzi5wk8AnJLdAu3hkUBjL4nOC4unSmAIcctRjQ= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas5p4.samsung.com (KnoxPortal) with ESMTPS id 20250828085932epcas5p4e09ce768a1e522b1d067b78ba5c19ebd~f4qOvpfmV0476004760epcas5p4R; Thu, 28 Aug 2025 08:59:32 +0000 (GMT) Received: from epcas5p2.samsung.com (unknown [182.195.38.93]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4cCFhM24bmz6B9mK; Thu, 28 Aug 2025 08:59:31 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPA id 20250828085930epcas5p1719c7db08074bf1540dc85b71736a6c5~f4qNN7ifM0548005480epcas5p1Y; Thu, 28 Aug 2025 08:59:30 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085927epsmtip293a425196cb6dc7c30d2f75654487ccd~f4qKkAQCW0306303063epsmtip2V; Thu, 28 Aug 2025 08:59:27 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 2/7] dt-bindings: media: fsd: Add CSIS video capture interface Date: Thu, 28 Aug 2025 14:29:06 +0530 Message-ID: <20250828085911.81266-3-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085930epcas5p1719c7db08074bf1540dc85b71736a6c5 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085930epcas5p1719c7db08074bf1540dc85b71736a6c5 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Tesla FSD CSIS video capture interface is used to capture frames. Signed-off-by: Inbaraj E --- .../bindings/media/tesla,fsd-csis-media.yaml | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 Documentation/devicetree/bindings/media/tesla,fsd-csis-= media.yaml diff --git a/Documentation/devicetree/bindings/media/tesla,fsd-csis-media.y= aml b/Documentation/devicetree/bindings/media/tesla,fsd-csis-media.yaml new file mode 100644 index 000000000000..f045094ae539 --- /dev/null +++ b/Documentation/devicetree/bindings/media/tesla,fsd-csis-media.yaml @@ -0,0 +1,76 @@ +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/media/tesla,fsd-csis-media.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: Tesla FSD SoC MIPI CSI-2 video capture interface(Bridge device). + +maintainers: + - Inbaraj E + +description: + The Tesla FSD CSIS has an internal video capture interface to capture + frames originating from the sensor. The power supply for the IP is + managed by custom firmware and is expected to remain enabled + permanently, so power supply control is not added in linux. + +properties: + compatible: + const: tesla,fsd-csis-media + + reg: + maxItems: 1 + + interrupts: + maxItems: 1 + + clocks: + maxItems: 3 + + clock-names: + items: + - const: aclk + - const: pclk + - const: pll + + iommus: + maxItems: 1 + + port: + $ref: /schemas/graph.yaml#/properties/port + +required: + - compatible + - reg + - interrupts + - clocks + - clock-names + - iommus + - port + +additionalProperties: false + +examples: + - | + #include + #include + + csis0: csis@12641000 { + compatible =3D "tesla,fsd-csis-media"; + reg =3D <0x12661000 0x44c>; + interrupts =3D ; + clocks =3D <&clock_csi CAM_CSI0_0_IPCLKPORT_I_ACLK>, + <&clock_csi CAM_CSI0_0_IPCLKPORT_I_PCLK>, + <&clock_csi CAM_CSI_PLL>; + clock-names =3D "aclk", "pclk", "pll"; + iommus =3D <&smmu_isp 0x0 0x0>; + + port { + csi_in_0: endpoint { + remote-endpoint =3D <&mipi_csis_0_out>; + }; + }; + }; + +... --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 990FD2F9C32 for ; Thu, 28 Aug 2025 08:59:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.33 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371580; cv=none; b=sgwc390ozcf6EGLQhjKRSuNRYK/0+gjY88JAd3hF8sTk83WEset22WOw5/Fgtk3/ByFBzksP4CJdwbKUcLS/FJq3db+6BvwpK/v8uowHtjAchJswZxqM7YbztDlyAKldiMn2CbdvZw/c6kxPBrJDdLrXzGNyeTK2nN0+mVTRJhg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371580; c=relaxed/simple; bh=FaBIUMZThXBFpt34EcTZeYT6Av7Tez0fAhaTvWdn0xM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=pWUXJIhvFqCLZrtWxhn+beyejvqqoEYWkLIrEd8+bcFiSy6tCFyKjNfFI/luOsjCDI7zS3WYC+M/A90TOZdWS5FEmN4XV/BfOFKrSJq7IXoGTipscZTfDuDVaG8k2iNXqK/7ShiGKctYR5E7p+xjL0ifAN5ou89HhEKstuCO9eo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=uoaOF7Mr; arc=none smtp.client-ip=203.254.224.33 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="uoaOF7Mr" Received: from epcas5p3.samsung.com (unknown [182.195.41.41]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250828085936epoutp032dc6bbd5d371c71f9ed2a5cb3c52fc21~f4qS43VEX0107501075epoutp03t for ; Thu, 28 Aug 2025 08:59:36 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250828085936epoutp032dc6bbd5d371c71f9ed2a5cb3c52fc21~f4qS43VEX0107501075epoutp03t DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371576; bh=MSqqONYPyXdoryTMVOMCVfHY1zxA8lghBgSEEzRog/c=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uoaOF7MrhY/QsdwjnI8oKgULbfWvDBuLIBDxw9vHOSC6cjeSfGBtp10eOESwbBoJi ktOiwlmpgPWThe6INnc1Z6bD3AilRO4qNkD1WFcgOLVxCE+PC49XqIsrBfE2IHpvkA KeUQAm9PAmSG0fCIe20PyDqys0PMluXa+03YzWf4= Received: from epsnrtp01.localdomain (unknown [182.195.42.153]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPS id 20250828085936epcas5p151a52aa51b0d013bd996852b7e378ad0~f4qSJY1De0547105471epcas5p15; Thu, 28 Aug 2025 08:59:36 +0000 (GMT) Received: from epcas5p4.samsung.com (unknown [182.195.38.87]) by epsnrtp01.localdomain (Postfix) with ESMTP id 4cCFhR0CQ1z6B9m5; Thu, 28 Aug 2025 08:59:35 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPA id 20250828085934epcas5p12a94dfc60a4ea9d5bb46fa7cd10874b7~f4qQtroHi0548005480epcas5p1d; Thu, 28 Aug 2025 08:59:34 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085931epsmtip25782e6ea336bdd3b95b00f614582f79e~f4qOE-OgQ0309203092epsmtip2j; Thu, 28 Aug 2025 08:59:31 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 3/7] media: imx-mipi-csis: Move clk to mipi_csis_info structure Date: Thu, 28 Aug 2025 14:29:07 +0530 Message-ID: <20250828085911.81266-4-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085934epcas5p12a94dfc60a4ea9d5bb46fa7cd10874b7 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085934epcas5p12a94dfc60a4ea9d5bb46fa7cd10874b7 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Clock names and number of Clocks in v3.3 and v3.6.3 differ v4.3. To extend the driver for Tesla FSD SoC support, move the Clock names and number of Clocks into the mipi_csis_info structure. Signed-off-by: Inbaraj E --- drivers/media/platform/nxp/imx-mipi-csis.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/pla= tform/nxp/imx-mipi-csis.c index b1136336a57f..cec035059445 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -304,6 +304,8 @@ static const struct mipi_csis_event mipi_csis_events[] = =3D { #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) #define MIPI_CSIS_NUM_ERROR_EVENTS (MIPI_CSIS_NUM_EVENTS - 20) =20 +#define MIPI_CSIS_MAX_CLOCKS 4 + enum mipi_csis_clk { MIPI_CSIS_CLK_PCLK, MIPI_CSIS_CLK_WRAP, @@ -311,13 +313,6 @@ enum mipi_csis_clk { MIPI_CSIS_CLK_AXI, }; =20 -static const char * const mipi_csis_clk_id[] =3D { - "pclk", - "wrap", - "phy", - "axi", -}; - enum mipi_csis_version { MIPI_CSIS_V3_3, MIPI_CSIS_V3_6_3, @@ -326,6 +321,7 @@ enum mipi_csis_version { struct mipi_csis_info { enum mipi_csis_version version; unsigned int num_clocks; + const char *clk_names[MIPI_CSIS_MAX_CLOCKS]; }; =20 struct mipi_csis_device { @@ -735,7 +731,7 @@ static int mipi_csis_clk_get(struct mipi_csis_device *c= sis) return -ENOMEM; =20 for (i =3D 0; i < csis->info->num_clocks; i++) - csis->clks[i].id =3D mipi_csis_clk_id[i]; + csis->clks[i].id =3D csis->info->clk_names[i]; =20 ret =3D devm_clk_bulk_get(csis->dev, csis->info->num_clocks, csis->clks); @@ -1609,12 +1605,14 @@ static const struct of_device_id mipi_csis_of_match= [] =3D { .data =3D &(const struct mipi_csis_info){ .version =3D MIPI_CSIS_V3_3, .num_clocks =3D 3, + .clk_names =3D {"pclk", "wrap", "phy"}, }, }, { .compatible =3D "fsl,imx8mm-mipi-csi2", .data =3D &(const struct mipi_csis_info){ .version =3D MIPI_CSIS_V3_6_3, .num_clocks =3D 4, + .clk_names =3D {"pclk", "wrap", "phy", "axi"}, }, }, { /* sentinel */ }, --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout1.samsung.com (mailout1.samsung.com [203.254.224.24]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 91A872FD7AD for ; Thu, 28 Aug 2025 08:59:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.24 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371584; cv=none; b=EvJrg+Mu/goYuo1zzh3TA5biwBegrKe56r9B1n2mKD4wuMEHg4rE9R8109ZQIm1O2d3XfWW48qozIQSCCIyxbRGqeUBOGZB2m3Hea5+zLhcfVnP+FPr0rILTVkTiAJ6vj6WJ2PIriZPIwwRV7VlQOm2FwgBUxfRz/W62HhmKXW8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371584; c=relaxed/simple; bh=1MdHhx5v3BAcGEHa/tXlUx16gIqHZGCvXZONQJHLdec=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=EzrXvN5gcyQrhQW/Q/9bCc9LuyeL9k03gry4JI8F/ARlwCotcC8H2tCfSMdvgXO+qotbq1+zHAsQjeOH16KkfKZEWKDIdSvwpxxg4I8Hdc4q2RjJjeQQSyjgZRPM7QA3fkcXJJAu/cPLYXRX2edv6XJYKqW2A7gCkgFccBnsW+o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=cmPplpZB; arc=none smtp.client-ip=203.254.224.24 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="cmPplpZB" Received: from epcas5p1.samsung.com (unknown [182.195.41.39]) by mailout1.samsung.com (KnoxPortal) with ESMTP id 20250828085940epoutp015e66c32f7232cf49f56e1e808fb0b96b~f4qWwlOoo1190311903epoutp01o for ; Thu, 28 Aug 2025 08:59:40 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.samsung.com 20250828085940epoutp015e66c32f7232cf49f56e1e808fb0b96b~f4qWwlOoo1190311903epoutp01o DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371580; bh=aP3JZ6i35oNdplmxk8s2s2TwgOzarCJEvRhAfBW6bEA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cmPplpZBw54vZbGtX98QypJRVKh9gmWmedPB3RLW1YnEucIP9lObd2Rqvou6w4V/i Vj/ygvOkBL+ur0NIm4EKAiYMOOW4lFiyoRQDdNgOUXNufKlxzJiizZ2EHPahlUvjCz nz6Uync4xXsO1X7PDucTGRcUxM5M0TLIRLyVxaMQ= Received: from epsnrtp04.localdomain (unknown [182.195.42.156]) by epcas5p2.samsung.com (KnoxPortal) with ESMTPS id 20250828085940epcas5p2dc296e2f6fb3094d4a92b9bec7cf8f75~f4qWCpDdZ1971119711epcas5p2B; Thu, 28 Aug 2025 08:59:40 +0000 (GMT) Received: from epcas5p1.samsung.com (unknown [182.195.38.89]) by epsnrtp04.localdomain (Postfix) with ESMTP id 4cCFhW0wmTz6B9mC; Thu, 28 Aug 2025 08:59:39 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p3.samsung.com (KnoxPortal) with ESMTPA id 20250828085938epcas5p3595ab67c6e5c40ab97f0b4a81faa16b3~f4qUUXAYG1632816328epcas5p3i; Thu, 28 Aug 2025 08:59:38 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085935epsmtip2d8cbb386c83433afe77acbe5f651cc4c~f4qRo3wsh0306303063epsmtip2W; Thu, 28 Aug 2025 08:59:35 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 4/7] media: imx-mipi-csis: Move irq flag and handler to mipi_csis_info structure Date: Thu, 28 Aug 2025 14:29:08 +0530 Message-ID: <20250828085911.81266-5-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085938epcas5p3595ab67c6e5c40ab97f0b4a81faa16b3 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085938epcas5p3595ab67c6e5c40ab97f0b4a81faa16b3 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Tesla FSD CSIS IP has single IRQ line, which is shared between imx-mipi-csis and fsd-csis drivers. To extend this driver for Tesla FSD SoC support, move the IRQ flag and IRQ handler into the device data(structure mipi_csis_info). Signed-off-by: Inbaraj E --- drivers/media/platform/nxp/imx-mipi-csis.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/pla= tform/nxp/imx-mipi-csis.c index cec035059445..2443906377bd 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -322,6 +322,8 @@ struct mipi_csis_info { enum mipi_csis_version version; unsigned int num_clocks; const char *clk_names[MIPI_CSIS_MAX_CLOCKS]; + unsigned int irq_flag; + irq_handler_t irq_handler; }; =20 struct mipi_csis_device { @@ -1532,7 +1534,7 @@ static int mipi_csis_probe(struct platform_device *pd= ev) mipi_csis_phy_reset(csis); =20 /* Now that the hardware is initialized, request the interrupt. */ - ret =3D devm_request_irq(dev, irq, mipi_csis_irq_handler, 0, + ret =3D devm_request_irq(dev, irq, csis->info->irq_handler, csis->info->i= rq_flag, dev_name(dev), csis); if (ret) { dev_err(dev, "Interrupt request failed\n"); @@ -1606,6 +1608,8 @@ static const struct of_device_id mipi_csis_of_match[]= =3D { .version =3D MIPI_CSIS_V3_3, .num_clocks =3D 3, .clk_names =3D {"pclk", "wrap", "phy"}, + .irq_flag =3D 0, + .irq_handler =3D mipi_csis_irq_handler, }, }, { .compatible =3D "fsl,imx8mm-mipi-csi2", @@ -1613,6 +1617,8 @@ static const struct of_device_id mipi_csis_of_match[]= =3D { .version =3D MIPI_CSIS_V3_6_3, .num_clocks =3D 4, .clk_names =3D {"pclk", "wrap", "phy", "axi"}, + .irq_flag =3D 0, + .irq_handler =3D mipi_csis_irq_handler, }, }, { /* sentinel */ }, --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EFDDD2FF17F for ; Thu, 28 Aug 2025 08:59:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371587; cv=none; b=ezuNlq/pLm8blV0OA0qriRXOwv6qAvSH1Z8IoGgu1XRU8sDQ0KFFFXQtO6CA2P0wXA+LpFRULA2vrLDORWIs6jDnDYc3auZRTu/fHYBFl7HwabBXS4/cVQG4BA5BllZjCLWqwsKDqosY+uvWu+sTbzNlOEkbwEPC4Jw9HyUyl4E= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371587; c=relaxed/simple; bh=y69aJvaC7ciZ5Hf9QaOQ87FPgv9BOZJHu+NQjvRatRw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=Jc5zQ6UxmbFySDewD3gSqwaC5BGRF7uL4WIvIL41XWIWXjDJJp9w6vsXRf/VEzdI2vezjKihpQkChYl0x3YFckAw+L4BxalT5yJQJdjRAULL3UapjecQeGFOB9PAQR96/5HRCFRDzhA6dE+5I2JYqoF5jW7cpZ/hQvXx/k/O99o= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=aI9Np7hy; arc=none smtp.client-ip=203.254.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="aI9Np7hy" Received: from epcas5p4.samsung.com (unknown [182.195.41.42]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250828085944epoutp044340b2c24f5e381210e9f59c90ef549e~f4qaAy8Tx2432424324epoutp04T for ; Thu, 28 Aug 2025 08:59:44 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250828085944epoutp044340b2c24f5e381210e9f59c90ef549e~f4qaAy8Tx2432424324epoutp04T DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371584; bh=MiHBdJbfHrVtpDhp68bjMjb9GJcwMtqCUnZwS8iakKU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aI9Np7hyuBLbHIWLY0jpDY7dsMh/oXWangAfqzVGy2BjMExfkD8HDLTqQfWIQfBvB vCDaAxcbUylGe9nfbShqx8TZoiuM+clQqBCsQdMV+hnZMgExL6/0k68lMutJs8EfRH VF4Uaavl1LgH7jTyk8oCNByXJV/yaQz1AYx7bRCc= Received: from epsnrtp02.localdomain (unknown [182.195.42.154]) by epcas5p2.samsung.com (KnoxPortal) with ESMTPS id 20250828085943epcas5p2abc570ed0afce51201230b0a623628f4~f4qZiduZm0593805938epcas5p2s; Thu, 28 Aug 2025 08:59:43 +0000 (GMT) Received: from epcas5p3.samsung.com (unknown [182.195.38.86]) by epsnrtp02.localdomain (Postfix) with ESMTP id 4cCFhZ6w18z2SSKZ; Thu, 28 Aug 2025 08:59:42 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p3.samsung.com (KnoxPortal) with ESMTPA id 20250828085942epcas5p3724f3184a1b12c20a8016c89f7e47ba7~f4qX9omGJ1633316333epcas5p3d; Thu, 28 Aug 2025 08:59:42 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085939epsmtip2842c1ef84d867f70baaae3e4d034b56d~f4qVS88A00283502835epsmtip2X; Thu, 28 Aug 2025 08:59:39 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 5/7] media: imx-mipi-csis: Add support for dynamic VC selection Date: Thu, 28 Aug 2025 14:29:09 +0530 Message-ID: <20250828085911.81266-6-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085942epcas5p3724f3184a1b12c20a8016c89f7e47ba7 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085942epcas5p3724f3184a1b12c20a8016c89f7e47ba7 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The existing implementation configures VC0 by default for streaming. This patch adds support to obtain the VC dynamically from the subdevice(Sensor) through the get_frame_desc() operation and configure the corresponding VC when starting the stream. If get_frame_desc() is not implemented by the subdevice, VC0 will be selected by default for configuration and streaming. Signed-off-by: Inbaraj E --- drivers/media/platform/nxp/imx-mipi-csis.c | 61 ++++++++++++++++++---- 1 file changed, 51 insertions(+), 10 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/pla= tform/nxp/imx-mipi-csis.c index 2443906377bd..b7ab441cc78a 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -334,6 +334,7 @@ struct mipi_csis_device { struct regulator *mipi_phy_regulator; =20 const struct mipi_csis_info *info; + unsigned int vc; unsigned int num_channels; =20 struct v4l2_subdev sd; @@ -585,7 +586,7 @@ static void __mipi_csis_set_format(struct mipi_csis_dev= ice *csis, u32 val; =20 /* Color format */ - val =3D mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(0)); + val =3D mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(csis->vc)); val &=3D ~(MIPI_CSIS_ISPCFG_PARALLEL | MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK | MIPI_CSIS_ISPCFG_DATAFORMAT_MASK); =20 @@ -606,10 +607,10 @@ static void __mipi_csis_set_format(struct mipi_csis_d= evice *csis, val |=3D MIPI_CSIS_ISPCFG_PIXEL_MODE_DUAL; =20 val |=3D MIPI_CSIS_ISPCFG_DATAFORMAT(csis_fmt->data_type); - mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(0), val); + mipi_csis_write(csis, MIPI_CSIS_ISP_CONFIG_CH(csis->vc), val); =20 /* Pixel resolution */ - mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(0), + mipi_csis_write(csis, MIPI_CSIS_ISP_RESOL_CH(csis->vc), MIPI_CSIS_ISP_RESOL_VRESOL(format->height) | MIPI_CSIS_ISP_RESOL_HRESOL(format->width)); } @@ -683,14 +684,14 @@ static void mipi_csis_set_params(struct mipi_csis_dev= ice *csis, MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle)); =20 - mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(0), + mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(csis->vc), MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0) | MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(0) | MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(0)); =20 val =3D mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL); - val |=3D MIPI_CSIS_CLK_CTRL_WCLK_SRC(0); - val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(0, 15); + val |=3D MIPI_CSIS_CLK_CTRL_WCLK_SRC(csis->vc); + val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(csis->vc, 15); val &=3D ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val); =20 @@ -707,7 +708,7 @@ static void mipi_csis_set_params(struct mipi_csis_devic= e *csis, /* Update the shadow register. */ val =3D mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, - val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(0) | + val | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(csis->vc) | MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } =20 @@ -778,7 +779,7 @@ static void mipi_csis_queue_event_sof(struct mipi_csis_= device *csis) }; u32 frame; =20 - frame =3D mipi_csis_read(csis, MIPI_CSIS_FRAME_COUNTER_CH(0)); + frame =3D mipi_csis_read(csis, MIPI_CSIS_FRAME_COUNTER_CH(csis->vc)); event.u.frame_sync.frame_sequence =3D frame; v4l2_event_queue(csis->sd.devnode, &event); } @@ -810,7 +811,7 @@ static irqreturn_t mipi_csis_irq_handler(int irq, void = *dev_id) } } =20 - if (status & MIPI_CSIS_INT_SRC_FRAME_START(0)) + if (status & MIPI_CSIS_INT_SRC_FRAME_START(csis->vc)) mipi_csis_queue_event_sof(csis); =20 spin_unlock_irqrestore(&csis->slock, flags); @@ -1191,7 +1192,7 @@ static int mipi_csis_get_frame_desc(struct v4l2_subde= v *sd, unsigned int pad, =20 entry->flags =3D 0; entry->pixelcode =3D csis_fmt->code; - entry->bus.csi2.vc =3D 0; + entry->bus.csi2.vc =3D csis->vc; entry->bus.csi2.dt =3D csis_fmt->data_type; =20 return 0; @@ -1269,6 +1270,39 @@ static const struct v4l2_subdev_internal_ops mipi_cs= is_internal_ops =3D { .init_state =3D mipi_csis_init_state, }; =20 +static int mipi_csis_get_vc(struct mipi_csis_device *csis) +{ + struct v4l2_mbus_frame_desc fd =3D { }; + int ret; + + ret =3D v4l2_subdev_call(csis->source.sd, pad, get_frame_desc, csis->sour= ce.pad->index, &fd); + if (ret < 0 && ret !=3D -ENOIOCTLCMD) { + dev_err(csis->dev, "get_frame_desc failed on source subdev\n"); + return ret; + } + + /* If remote subdev does not implement .get_frame_desc default to VC0 */ + if (ret =3D=3D -ENOIOCTLCMD) + return 0; + + if (fd.type !=3D V4L2_MBUS_FRAME_DESC_TYPE_CSI2) { + dev_err(csis->dev, "get_frame_desc returned invalid bus type %d\n", fd.t= ype); + return -EINVAL; + } + + if (!fd.num_entries) { + dev_err(csis->dev, "get_frame_desc returned zero enteries\n"); + return -EINVAL; + } + + if (fd.entry[0].bus.csi2.vc >=3D csis->num_channels) { + dev_err(csis->dev, "get_frame_desc returned invalid virtual channel\n"); + return -EINVAL; + } + + return fd.entry[0].bus.csi2.vc; +} + /* -----------------------------------------------------------------------= ------ * Media entity operations */ @@ -1296,6 +1330,13 @@ static int mipi_csis_link_setup(struct media_entity = *entity, =20 csis->source.sd =3D remote_sd; csis->source.pad =3D remote_pad; + + ret =3D mipi_csis_get_vc(csis); + + if (ret < 0) + return -EBUSY; + + csis->vc =3D ret; } else { csis->source.sd =3D NULL; csis->source.pad =3D NULL; --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout4.samsung.com (mailout4.samsung.com [203.254.224.34]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 07B2B2FFDF8 for ; Thu, 28 Aug 2025 08:59:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.34 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371592; cv=none; b=LTbv00AL/G16jD0lXzXxFT/HA4GoZ+/SMJrD2ZXIghSvFtSYg09yXbHcOWYtNZiLx64+4+bpoRn8XDMLfmcSPEqpMMBzLKhTOjixsKfhS2EyOuz1lZjThiazmg07Puiqui/N+2ujtpKYTtIeYMDx31QoFKVX5wRh7P8nZ42VOLs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371592; c=relaxed/simple; bh=740VZX2hF31//Vc/5RI9mwEMujGZOKxBmKImbAS0t00=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=oyPA9dCKnKfXrhmNCLoflOmRImXkgsRpJpDsyvwF0YLr780KeSujRLtpEY7CK1/vgVZVxObA72XOeDq8PT/OCgddriHf8s1liJ9E7Jd6voPhRSsxJMXGoolNEmwse8a6ZioBo9W7a4Hcl6cyreWpV7YLIHGWmHP8Px6rzVijwPk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=RyAkmAPn; arc=none smtp.client-ip=203.254.224.34 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="RyAkmAPn" Received: from epcas5p1.samsung.com (unknown [182.195.41.39]) by mailout4.samsung.com (KnoxPortal) with ESMTP id 20250828085948epoutp04f5dad40eb24b6ac2a25665cc4aa99234~f4qdxnvVy2596625966epoutp04q for ; Thu, 28 Aug 2025 08:59:48 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout4.samsung.com 20250828085948epoutp04f5dad40eb24b6ac2a25665cc4aa99234~f4qdxnvVy2596625966epoutp04q DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371588; bh=jymxJss5AlAGCE4UCXb1bxMUHtmCqjit6NMZ7PTXarY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RyAkmAPnpGmMtUxc6a7/80yzB6IYT9RgQFZEn2XFnsGmKsS2ZVrtVwAEp/BezIvE3 pmd6m1PJ4sZCIWvwxELlMzkXyHnXiZImAnW3S+s1eocRe/1B+ofLb7KSVwsffsTO4Y 5c/1rv9mwAfu7zJcLKAz33dGhOLJEKpAbC9q4x4A= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPS id 20250828085947epcas5p1bfb7344389959e93574fddc9818be2ee~f4qdFrs6C2857728577epcas5p1h; Thu, 28 Aug 2025 08:59:47 +0000 (GMT) Received: from epcas5p3.samsung.com (unknown [182.195.38.92]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4cCFhf55S0z3hhTG; Thu, 28 Aug 2025 08:59:46 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPA id 20250828085946epcas5p1752330d70434b840893b01a201324711~f4qbjE72I2857728577epcas5p1U; Thu, 28 Aug 2025 08:59:46 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085943epsmtip299870217aedfc50b0102bf0ec410898d~f4qY0lHaF0304903049epsmtip2Y; Thu, 28 Aug 2025 08:59:43 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 6/7] media: imx-mipi-csis: Add support for Telsa FSD CSIS. Date: Thu, 28 Aug 2025 14:29:10 +0530 Message-ID: <20250828085911.81266-7-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085946epcas5p1752330d70434b840893b01a201324711 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085946epcas5p1752330d70434b840893b01a201324711 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Telsa FSD SoC features a newer version(v4.3) of the CSI-2 receiver IP, similar to the one found in the i.MX7 and i.MX8MM, with the following differences. - Ability to select any one VC for streaming from the four available VCs. - Built-in DMA support, which is implemented by the fsd-csis driver. Signed-off-by: Inbaraj E --- drivers/media/platform/nxp/imx-mipi-csis.c | 256 +++++++++++++++++++-- 1 file changed, 231 insertions(+), 25 deletions(-) diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/pla= tform/nxp/imx-mipi-csis.c index b7ab441cc78a..07ce312a2ed5 100644 --- a/drivers/media/platform/nxp/imx-mipi-csis.c +++ b/drivers/media/platform/nxp/imx-mipi-csis.c @@ -35,6 +35,8 @@ #include #include #include +#include +#include =20 #define CSIS_DRIVER_NAME "imx-mipi-csis" =20 @@ -45,6 +47,9 @@ #define MIPI_CSIS_DEF_PIX_WIDTH 640 #define MIPI_CSIS_DEF_PIX_HEIGHT 480 =20 +/* CSIS V4_3 SYSREG macros */ +#define FSD_NO_CSI_PER_PHY_V4_3 4 +#define FSD_CSIS_RESETEN_DPHY_MASK_V4_3(phy) BIT_MASK(phy) /* Register map definition */ =20 /* CSIS version */ @@ -53,19 +58,22 @@ #define MIPI_CSIS_VERSION_IMX8MP 0x03060301 =20 /* CSIS common control */ -#define MIPI_CSIS_CMN_CTRL 0x04 -#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(n) BIT((n) + 16) -#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_NONE (0 << 10) -#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT (1 << 10) -#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER(n) ((n) << 8) -#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK (3 << 8) -#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2) -#define MIPI_CSIS_CMN_CTRL_SW_RESET BIT(1) -#define MIPI_CSIS_CMN_CTRL_CSI_EN BIT(0) +#define MIPI_CSIS_CMN_CTRL 0x04 +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW(n) BIT((n) + 16) +#define MIPI_CSIS_CMN_CTRL_DESKEW_ENABLE BIT(12) +#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_NONE (0 << 10) +#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT (1 << 10) +#define MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_VC_AND_DT (3 << 10) +#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER(n) ((n) << 8) +#define MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK (3 << 8) +#define MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL BIT(2) +#define MIPI_CSIS_CMN_CTRL_SW_RESET BIT(1) +#define MIPI_CSIS_CMN_CTRL_CSI_EN BIT(0) =20 /* CSIS clock control */ #define MIPI_CSIS_CLK_CTRL 0x08 #define MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(n, x) ((x) << ((n) * 4 + 16)) +#define MIPI_CSIS_CLK_CTRL_CLKGATE_EN(n) (1 << ((n) + 4)) #define MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK (0xf << 4) #define MIPI_CSIS_CLK_CTRL_WCLK_SRC(n) BIT(n) =20 @@ -107,6 +115,12 @@ #define MIPI_CSIS_INT_SRC_ERR_ID BIT(0) #define MIPI_CSIS_INT_SRC_ERRORS 0xfffff =20 +/* CSIS Interrupt mask1 */ +#define MIPI_CSIS_INT_MSK1 0x18 + +/* CSIS Interrupt source1 */ +#define MIPI_CSIS_INT_SRC1 0x1C + /* D-PHY status control */ #define MIPI_CSIS_DPHY_STATUS 0x20 #define MIPI_CSIS_DPHY_STATUS_ULPS_DAT BIT(8) @@ -120,8 +134,9 @@ #define MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE_MASK GENMASK(31, 24) #define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(n) ((n) << 22) #define MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE_MASK GENMASK(23, 22) -#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_CLK BIT(6) -#define MIPI_CSIS_DPHY_CMN_CTRL_S_DPDN_SWAP_DAT BIT(5) +#define MIPI_CSIS_DPHY_CMN_CTRL_S_BYTE_CLK_EN BIT(21) +#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_CLK BIT(6) +#define MIPI_CSIS_DPHY_CMN_CTRL_DPDN_SWAP_DAT BIT(5) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_DAT BIT(1) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE_CLK BIT(0) #define MIPI_CSIS_DPHY_CMN_CTRL_ENABLE (0x1f << 0) @@ -167,7 +182,10 @@ /* D-PHY Slave Control register Low */ #define MIPI_CSIS_DPHY_SCTRL_L 0x38 /* D-PHY Slave Control register High */ -#define MIPI_CSIS_DPHY_SCTRL_H 0x3c +#define MIPI_CSIS_DPHY_SCTRL_H 0x3c +#define MIPI_CSIS_DPHY_SCTRL_H_SKEW_CAL_MAX_SKEW_CODE_CTRL (0x24 << 2) +#define MIPI_CSIS_DPHY_SCTRL_H_SKEW_CAL_MAX_SKEW_CODE_CTRL_MASK GENMASK(7,= 2) +#define MIPI_CSIS_DPHY_SCTRL_H_SKEW_CAL_EN BIT(1) =20 /* ISP Configuration register */ #define MIPI_CSIS_ISP_CONFIG_CH(n) (0x40 + (n) * 0x10) @@ -222,6 +240,12 @@ =20 #define MIPI_CSIS_FRAME_COUNTER_CH(n) (0x0100 + (n) * 4) =20 +/* VC Passing register */ +#define MIPI_CSIS_VC_PASSING_REG 0x120 +#define MIPI_CSIS_VC_PASSING(n) ((n) << 8) +#define MIPI_CSIS_VC_PASSING_MASK GENMASK(9, 8) +#define MIPI_CSIS_VC_PASSING_EN BIT(7) + /* Non-image packet data buffers */ #define MIPI_CSIS_PKTDATA_ODD 0x2000 #define MIPI_CSIS_PKTDATA_EVEN 0x3000 @@ -303,6 +327,7 @@ static const struct mipi_csis_event mipi_csis_events[] = =3D { =20 #define MIPI_CSIS_NUM_EVENTS ARRAY_SIZE(mipi_csis_events) #define MIPI_CSIS_NUM_ERROR_EVENTS (MIPI_CSIS_NUM_EVENTS - 20) +#define MIPI_CSIS_INT_SRC_NUM_EVENTS_V4_3 17 =20 #define MIPI_CSIS_MAX_CLOCKS 4 =20 @@ -316,6 +341,7 @@ enum mipi_csis_clk { enum mipi_csis_version { MIPI_CSIS_V3_3, MIPI_CSIS_V3_6_3, + MIPI_CSIS_V4_3, }; =20 struct mipi_csis_info { @@ -329,6 +355,8 @@ struct mipi_csis_info { struct mipi_csis_device { struct device *dev; void __iomem *regs; + struct regmap *sysreg_map; + unsigned int phy_rst_off; struct clk_bulk_data *clks; struct reset_control *mrst; struct regulator *mipi_phy_regulator; @@ -391,6 +419,11 @@ static const struct csis_pix_format mipi_csis_formats[= ] =3D { .output =3D MEDIA_BUS_FMT_RGB888_1X24, .data_type =3D MIPI_CSI2_DT_RGB888, .width =3D 24, + }, { + .code =3D MEDIA_BUS_FMT_RGB888_1X24, + .output =3D MEDIA_BUS_FMT_RGB888_1X24, + .data_type =3D MIPI_CSI2_DT_RGB888, + .width =3D 24, }, /* RAW (Bayer and greyscale) formats. */ { @@ -547,7 +580,11 @@ static inline void mipi_csis_write(struct mipi_csis_de= vice *csis, u32 reg, static void mipi_csis_enable_interrupts(struct mipi_csis_device *csis, boo= l on) { mipi_csis_write(csis, MIPI_CSIS_INT_MSK, on ? 0xffffffff : 0); - mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); + + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) + mipi_csis_write(csis, MIPI_CSIS_INT_MSK1, on ? 0xffffffff : 0); + else + mipi_csis_write(csis, MIPI_CSIS_DBG_INTR_MSK, on ? 0xffffffff : 0); } =20 static void mipi_csis_sw_reset(struct mipi_csis_device *csis) @@ -576,6 +613,8 @@ static void mipi_csis_system_enable(struct mipi_csis_de= vice *csis, int on) mask =3D (1 << (csis->bus.num_data_lanes + 1)) - 1; val |=3D (mask & MIPI_CSIS_DPHY_CMN_CTRL_ENABLE); } + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) + val |=3D MIPI_CSIS_DPHY_CMN_CTRL_S_BYTE_CLK_EN; mipi_csis_write(csis, MIPI_CSIS_DPHY_CMN_CTRL, val); } =20 @@ -587,8 +626,11 @@ static void __mipi_csis_set_format(struct mipi_csis_de= vice *csis, =20 /* Color format */ val =3D mipi_csis_read(csis, MIPI_CSIS_ISP_CONFIG_CH(csis->vc)); - val &=3D ~(MIPI_CSIS_ISPCFG_PARALLEL | MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK | - MIPI_CSIS_ISPCFG_DATAFORMAT_MASK); + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) + val &=3D ~(MIPI_CSIS_ISPCFG_DATAFORMAT_MASK | MIPI_CSIS_ISPCFG_PIXEL_MOD= E_MASK); + else + val &=3D ~(MIPI_CSIS_ISPCFG_PARALLEL | MIPI_CSIS_ISPCFG_DATAFORMAT_MASK + | MIPI_CSIS_ISPCFG_PIXEL_MODE_MASK); =20 /* * YUV 4:2:2 can be transferred with 8 or 16 bits per clock sample @@ -632,7 +674,7 @@ static int mipi_csis_calculate_params(struct mipi_csis_= device *csis, =20 lane_rate =3D link_freq * 2; =20 - if (lane_rate < 80000000 || lane_rate > 1500000000) { + if (lane_rate < 80000000 || lane_rate > 1600000000) { dev_dbg(csis->dev, "Out-of-bound lane rate %u\n", lane_rate); return -EINVAL; } @@ -674,8 +716,12 @@ static void mipi_csis_set_params(struct mipi_csis_devi= ce *csis, val =3D mipi_csis_read(csis, MIPI_CSIS_CMN_CTRL); val &=3D ~MIPI_CSIS_CMN_CTRL_LANE_NUMBER_MASK; val |=3D MIPI_CSIS_CMN_CTRL_LANE_NUMBER(lanes - 1); - if (csis->info->version =3D=3D MIPI_CSIS_V3_3) + if (csis->info->version =3D=3D MIPI_CSIS_V3_3) { val |=3D MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_DT; + } else if (csis->info->version =3D=3D MIPI_CSIS_V4_3) { + val |=3D MIPI_CSIS_CMN_CTRL_INTERLEAVE_MODE_VC_AND_DT; + val |=3D MIPI_CSIS_CMN_CTRL_DESKEW_ENABLE; + } mipi_csis_write(csis, MIPI_CSIS_CMN_CTRL, val); =20 __mipi_csis_set_format(csis, format, csis_fmt); @@ -684,15 +730,23 @@ static void mipi_csis_set_params(struct mipi_csis_dev= ice *csis, MIPI_CSIS_DPHY_CMN_CTRL_HSSETTLE(csis->hs_settle) | MIPI_CSIS_DPHY_CMN_CTRL_CLKSETTLE(csis->clk_settle)); =20 - mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(csis->vc), - MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0) | - MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(0) | - MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(0)); + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) + val =3D MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0x20); + else + val =3D MIPI_CSIS_ISP_SYNC_HSYNC_LINTV(0) + | MIPI_CSIS_ISP_SYNC_VSYNC_SINTV(0) + | MIPI_CSIS_ISP_SYNC_VSYNC_EINTV(0); + mipi_csis_write(csis, MIPI_CSIS_ISP_SYNC_CH(csis->vc), val); =20 val =3D mipi_csis_read(csis, MIPI_CSIS_CLK_CTRL); - val |=3D MIPI_CSIS_CLK_CTRL_WCLK_SRC(csis->vc); - val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(csis->vc, 15); - val &=3D ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) { + val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_EN(csis->vc); + val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(csis->vc, 0x07); + } else { + val |=3D MIPI_CSIS_CLK_CTRL_WCLK_SRC(csis->vc); + val |=3D MIPI_CSIS_CLK_CTRL_CLKGATE_TRAIL(csis->vc, 15); + val &=3D ~MIPI_CSIS_CLK_CTRL_CLKGATE_EN_MSK; + } mipi_csis_write(csis, MIPI_CSIS_CLK_CTRL, val); =20 mipi_csis_write(csis, MIPI_CSIS_DPHY_BCTRL_L, @@ -712,6 +766,25 @@ static void mipi_csis_set_params(struct mipi_csis_devi= ce *csis, MIPI_CSIS_CMN_CTRL_UPDATE_SHADOW_CTRL); } =20 +static int mipi_csis_get_sysreg(struct mipi_csis_device *csis) +{ + unsigned int args; + + if (csis->info->version !=3D MIPI_CSIS_V4_3) + return 0; + + csis->sysreg_map =3D syscon_regmap_lookup_by_phandle_args + (csis->dev->of_node, "tesla,syscon-csis", 1, + &args); + + if (IS_ERR(csis->sysreg_map)) + return PTR_ERR(csis->sysreg_map); + + csis->phy_rst_off =3D args; + + return 0; +} + static int mipi_csis_clk_enable(struct mipi_csis_device *csis) { return clk_bulk_prepare_enable(csis->info->num_clocks, csis->clks); @@ -756,11 +829,71 @@ static int mipi_csis_clk_get(struct mipi_csis_device = *csis) return ret; } =20 +static void mipi_csis_dphy_reset_release_v4_3(struct mipi_csis_device *csi= s) +{ + unsigned int idx =3D 0, val =3D 0x0; + + /* There are 4 CSIs per each D-PHY i/f */ + idx =3D csis->vc; + + regmap_read(csis->sysreg_map, csis->phy_rst_off, &val); + + val &=3D ~FSD_CSIS_RESETEN_DPHY_MASK_V4_3(idx); + regmap_write(csis->sysreg_map, csis->phy_rst_off, val); + + usleep_range(500, 1000); + + val |=3D FSD_CSIS_RESETEN_DPHY_MASK_V4_3(idx); + regmap_write(csis->sysreg_map, csis->phy_rst_off, val); +} + +static void mipi_csis_dphy_init_v4_3(struct mipi_csis_device *csis) +{ + u32 val =3D 0; + + mipi_csis_dphy_reset_release_v4_3(csis); + + val =3D readl(csis->regs + MIPI_CSIS_DPHY_SCTRL_H); + + val |=3D MIPI_CSIS_DPHY_SCTRL_H_SKEW_CAL_EN; + val |=3D MIPI_CSIS_DPHY_SCTRL_H_SKEW_CAL_MAX_SKEW_CODE_CTRL; + writel(val, csis->regs + MIPI_CSIS_DPHY_SCTRL_H); +} + +static void mipi_csis_set_vc_passing(struct mipi_csis_device *csis) +{ + u32 val; + unsigned int vc =3D csis->vc; + + val =3D readl(csis->regs + MIPI_CSIS_VC_PASSING_REG); + + val &=3D ~MIPI_CSIS_VC_PASSING_MASK; + val |=3D MIPI_CSIS_VC_PASSING(vc); + val |=3D MIPI_CSIS_VC_PASSING_EN; + writel(val, csis->regs + MIPI_CSIS_VC_PASSING_REG); +} + +static void mipi_csis_get_irq_status(struct mipi_csis_device *csis, + unsigned int *sts) +{ + *sts =3D readl(csis->regs + MIPI_CSIS_INT_SRC1); +} + +static void mipi_csis_clear_irq_status(struct mipi_csis_device *csis, + unsigned int *sts) +{ + writel(*sts, csis->regs + MIPI_CSIS_INT_SRC1); +} + static void mipi_csis_start_stream(struct mipi_csis_device *csis, const struct v4l2_mbus_framefmt *format, const struct csis_pix_format *csis_fmt) { mipi_csis_sw_reset(csis); + if (csis->info->version =3D=3D MIPI_CSIS_V4_3) { + mipi_csis_dphy_init_v4_3(csis); + mipi_csis_set_vc_passing(csis); + } mipi_csis_set_params(csis, format, csis_fmt); mipi_csis_system_enable(csis, true); mipi_csis_enable_interrupts(csis, true); @@ -784,6 +917,31 @@ static void mipi_csis_queue_event_sof(struct mipi_csis= _device *csis) v4l2_event_queue(csis->sd.devnode, &event); } =20 +static irqreturn_t mipi_csis_irq_handler_v4_3(int irq, void *dev_id) +{ + struct mipi_csis_device *csis =3D dev_id; + unsigned long flags; + u32 status; + unsigned int i; + + status =3D mipi_csis_read(csis, MIPI_CSIS_INT_SRC); + + spin_lock_irqsave(&csis->slock, flags); + if ((status & MIPI_CSIS_INT_SRC_ERRORS)) { + for (i =3D 0; i < MIPI_CSIS_INT_SRC_NUM_EVENTS_V4_3; i++) { + struct mipi_csis_event *event =3D &csis->events[i]; + + if (status & event->mask) + event->counter++; + } + } + spin_unlock_irqrestore(&csis->slock, flags); + + mipi_csis_write(csis, MIPI_CSIS_INT_SRC, status); + + return IRQ_NONE; +} + static irqreturn_t mipi_csis_irq_handler(int irq, void *dev_id) { struct mipi_csis_device *csis =3D dev_id; @@ -1000,7 +1158,6 @@ static void mipi_csis_debugfs_exit(struct mipi_csis_d= evice *csis) /* -----------------------------------------------------------------------= ------ * V4L2 subdev operations */ - static struct mipi_csis_device *sd_to_mipi_csis_device(struct v4l2_subdev = *sdev) { return container_of(sdev, struct mipi_csis_device, sd); @@ -1064,6 +1221,39 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd= , int enable) return ret; } =20 +static void mipi_csis_read_vc_frame_counter(struct mipi_csis_device *csis, + u32 *current_frame_counter) +{ + unsigned int vc =3D csis->vc; + *current_frame_counter =3D readl(csis->regs + MIPI_CSIS_FRAME_COUNTER_CH(= vc)); +} + +static long mipi_csis_command(struct v4l2_subdev *sd, unsigned int cmd, vo= id *arg) +{ + struct mipi_csis_device *csis =3D sd_to_mipi_csis_device(sd); + long ret =3D 0; + + switch (cmd) { + case 1: + mipi_csis_system_enable(csis, true); + break; + case 2: + mipi_csis_get_irq_status(csis, arg); + break; + case 3: + mipi_csis_clear_irq_status(csis, arg); + break; + case 5: + mipi_csis_read_vc_frame_counter(csis, arg); + break; + default: + dev_err(csis->dev, "Invalid command\n"); + ret =3D -1; + } + + return ret; +} + static int mipi_csis_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *state, struct v4l2_subdev_mbus_code_enum *code) @@ -1171,6 +1361,7 @@ static int mipi_csis_set_fmt(struct v4l2_subdev *sd, static int mipi_csis_get_frame_desc(struct v4l2_subdev *sd, unsigned int p= ad, struct v4l2_mbus_frame_desc *fd) { + struct mipi_csis_device *csis =3D sd_to_mipi_csis_device(sd); struct v4l2_mbus_frame_desc_entry *entry =3D &fd->entry[0]; const struct csis_pix_format *csis_fmt; const struct v4l2_mbus_framefmt *fmt; @@ -1247,6 +1438,7 @@ static const struct v4l2_subdev_core_ops mipi_csis_co= re_ops =3D { .log_status =3D mipi_csis_log_status, .subscribe_event =3D mipi_csis_subscribe_event, .unsubscribe_event =3D v4l2_event_subdev_unsubscribe, + .command =3D mipi_csis_command, }; =20 static const struct v4l2_subdev_video_ops mipi_csis_video_ops =3D { @@ -1314,6 +1506,7 @@ static int mipi_csis_link_setup(struct media_entity *= entity, struct v4l2_subdev *sd =3D media_entity_to_v4l2_subdev(entity); struct mipi_csis_device *csis =3D sd_to_mipi_csis_device(sd); struct v4l2_subdev *remote_sd; + int ret; =20 dev_dbg(csis->dev, "link setup %s -> %s", remote_pad->entity->name, local_pad->entity->name); @@ -1563,6 +1756,10 @@ static int mipi_csis_probe(struct platform_device *p= dev) if (irq < 0) return irq; =20 + ret =3D mipi_csis_get_sysreg(csis); + if (ret < 0) + return ret; + ret =3D mipi_csis_phy_init(csis); if (ret < 0) return ret; @@ -1661,6 +1858,15 @@ static const struct of_device_id mipi_csis_of_match[= ] =3D { .irq_flag =3D 0, .irq_handler =3D mipi_csis_irq_handler, }, + }, { + .compatible =3D "tesla,fsd-mipi-csi2", + .data =3D &(const struct mipi_csis_info){ + .version =3D MIPI_CSIS_V4_3, + .num_clocks =3D 2, + .clk_names =3D { "aclk", "pclk"}, + .irq_flag =3D IRQF_SHARED, + .irq_handler =3D mipi_csis_irq_handler_v4_3, + }, }, { /* sentinel */ }, }; --=20 2.49.0 From nobody Fri Oct 3 15:34:23 2025 Received: from mailout3.samsung.com (mailout3.samsung.com [203.254.224.33]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3382A301006 for ; Thu, 28 Aug 2025 08:59:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.254.224.33 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371598; cv=none; b=Hgjo2QEnWhhkrTjQDJc0tNeLcS9jol7i3MtgFYnbZjqPkGy8/QM/McG8YpAaCKnsBx314QHApQaGTyIQuI2HdfaITdGjNq5KDF+LAxb9Dx6npwq2A2wqZcexov7Aiq+PsUU/3CburIWvBr7AXHViBo3V+jBMO3G4SrUSAfElG8w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1756371598; c=relaxed/simple; bh=nBnM34H0NCSSRZgVkirV8RClzulMWKYLmBBgSxIhxmU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:MIME-Version: Content-Type:References; b=RTz8BjZrm0qFmn41nUoCnVBmSgxSEZ/OSvma7YJLZqy30ze6+v8H8WG6kiXvcKe1dZ9XIsQdMAS9qe1ITGmyPEMwX38RTBqHqTb3EA0f+sASfFGEzGX0aIQ2tONF/KTyjnxhkng2gc1dkrqOvlYUudK+FDpvLZnkjhYFF9duGPI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com; spf=pass smtp.mailfrom=samsung.com; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b=stjXSj6i; arc=none smtp.client-ip=203.254.224.33 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=samsung.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=samsung.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=samsung.com header.i=@samsung.com header.b="stjXSj6i" Received: from epcas5p3.samsung.com (unknown [182.195.41.41]) by mailout3.samsung.com (KnoxPortal) with ESMTP id 20250828085952epoutp031af7c1e37f206bad96652b10edfe94a0~f4qhrEROc0097500975epoutp03w for ; Thu, 28 Aug 2025 08:59:52 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout3.samsung.com 20250828085952epoutp031af7c1e37f206bad96652b10edfe94a0~f4qhrEROc0097500975epoutp03w DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1756371592; bh=jes6gf+irf75vpBoJyNVdGaamBw9Mu9AFsZXy++CCv8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=stjXSj6ih+OuHr+OEMXMy3Bl33wFUjZNIy/y212Jc8vZ63kfc9wSrgQ9gjGcW+UaF dhS1WlyhV9IpiHYdyM9S6myCCCd7fusqXb0xlSLANBJYr3bnL8IYhHkA+hsl5pDKM/ 4gZ8v2PSvGbZOTwuM/SAmruI0CZv7EZSBe1F3o68= Received: from epsnrtp03.localdomain (unknown [182.195.42.155]) by epcas5p1.samsung.com (KnoxPortal) with ESMTPS id 20250828085951epcas5p1c8fa299fbc654795e340eda4d92e3f58~f4qgpL9_Q2857728577epcas5p1r; Thu, 28 Aug 2025 08:59:51 +0000 (GMT) Received: from epcas5p2.samsung.com (unknown [182.195.38.94]) by epsnrtp03.localdomain (Postfix) with ESMTP id 4cCFhk3t0Bz3hhT7; Thu, 28 Aug 2025 08:59:50 +0000 (GMT) Received: from epsmtip2.samsung.com (unknown [182.195.34.31]) by epcas5p2.samsung.com (KnoxPortal) with ESMTPA id 20250828085949epcas5p2a39a61925893e78ae8b70902fc7f4c20~f4qfD9XVT1971219712epcas5p2S; Thu, 28 Aug 2025 08:59:49 +0000 (GMT) Received: from cheetah.samsungds.net (unknown [107.109.115.53]) by epsmtip2.samsung.com (KnoxPortal) with ESMTPA id 20250828085946epsmtip2557bb01c02d6a7b52839e2271079e394~f4qcTv53T0248202482epsmtip2y; Thu, 28 Aug 2025 08:59:46 +0000 (GMT) From: Inbaraj E To: rmfrfs@gmail.com, laurent.pinchart@ideasonboard.com, martink@posteo.de, kernel@puri.sm, mchehab@kernel.org, robh@kernel.org, krzk+dt@kernel.org, conor+dt@kernel.org, shawnguo@kernel.org, s.hauer@pengutronix.de Cc: kernel@pengutronix.de, festevam@gmail.com, linux-media@vger.kernel.org, devicetree@vger.kernel.org, imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org, linux-kernel@vger.kernel.org, linux-samsung-soc@vger.kernel.org, pankaj.dubey@samsung.com, ravi.patel@samsung.com, shradha.t@samsung.com, Inbaraj E Subject: [PATCH v3 7/7] media: fsd-csis: Add FSD CSIS video capture interface support Date: Thu, 28 Aug 2025 14:29:11 +0530 Message-ID: <20250828085911.81266-8-inbaraj.e@samsung.com> X-Mailer: git-send-email 2.49.0 In-Reply-To: <20250828085911.81266-1-inbaraj.e@samsung.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CMS-MailID: 20250828085949epcas5p2a39a61925893e78ae8b70902fc7f4c20 X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" CMS-TYPE: 105P cpgsPolicy: CPGSC10-541,Y X-CFilter-Loop: Reflected X-CMS-RootMailID: 20250828085949epcas5p2a39a61925893e78ae8b70902fc7f4c20 References: <20250828085911.81266-1-inbaraj.e@samsung.com> The Tesla FSD CSIS IP bundles video capture interface to capture frames from MIPI-CSI2 bus. This driver exposes video device file to userspace for frame capture and a media device file to configure camera pipeline. Signed-off-by: Inbaraj E --- MAINTAINERS | 8 + drivers/media/platform/samsung/Kconfig | 1 + drivers/media/platform/samsung/Makefile | 1 + .../media/platform/samsung/fsd-csis/Kconfig | 18 + .../media/platform/samsung/fsd-csis/Makefile | 3 + .../platform/samsung/fsd-csis/fsd-csis.c | 1690 +++++++++++++++++ 6 files changed, 1721 insertions(+) create mode 100644 drivers/media/platform/samsung/fsd-csis/Kconfig create mode 100644 drivers/media/platform/samsung/fsd-csis/Makefile create mode 100644 drivers/media/platform/samsung/fsd-csis/fsd-csis.c diff --git a/MAINTAINERS b/MAINTAINERS index c5171a5dcba6..4d86fe921ca8 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3334,6 +3334,14 @@ S: Maintained F: Documentation/devicetree/bindings/media/samsung,s5p-mfc.yaml F: drivers/media/platform/samsung/s5p-mfc/ =20 +TESLA FSD BRIDGE DRIVER +M: Inbaraj E +L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers) +L: linux-media@vger.kernel.org +S: Maintained +F: Documentation/devicetree/bindings/media/tesla,fsd-csis-media.yaml +F: drivers/media/platform/samsung/fsd-csis/fsd-csis.c + ARM/SOCFPGA ARCHITECTURE M: Dinh Nguyen S: Maintained diff --git a/drivers/media/platform/samsung/Kconfig b/drivers/media/platfor= m/samsung/Kconfig index 0e34c5fc1dfc..4cebe2ae24a3 100644 --- a/drivers/media/platform/samsung/Kconfig +++ b/drivers/media/platform/samsung/Kconfig @@ -4,6 +4,7 @@ comment "Samsung media platform drivers" =20 source "drivers/media/platform/samsung/exynos-gsc/Kconfig" source "drivers/media/platform/samsung/exynos4-is/Kconfig" +source "drivers/media/platform/samsung/fsd-csis/Kconfig" source "drivers/media/platform/samsung/s3c-camif/Kconfig" source "drivers/media/platform/samsung/s5p-g2d/Kconfig" source "drivers/media/platform/samsung/s5p-jpeg/Kconfig" diff --git a/drivers/media/platform/samsung/Makefile b/drivers/media/platfo= rm/samsung/Makefile index 21fea3330e4b..fde1b9626713 100644 --- a/drivers/media/platform/samsung/Makefile +++ b/drivers/media/platform/samsung/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0-only obj-y +=3D exynos-gsc/ obj-y +=3D exynos4-is/ +obj-y +=3D fsd-csis/ obj-y +=3D s3c-camif/ obj-y +=3D s5p-g2d/ obj-y +=3D s5p-jpeg/ diff --git a/drivers/media/platform/samsung/fsd-csis/Kconfig b/drivers/medi= a/platform/samsung/fsd-csis/Kconfig new file mode 100644 index 000000000000..64ae57f81d22 --- /dev/null +++ b/drivers/media/platform/samsung/fsd-csis/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-only +# +# FSD MIPI CSI-2 Rx controller configurations + +config VIDEO_TESLA_FSD_CSIS + tristate "FSD SoC MIPI-CSI2 media controller driver" + depends on VIDEO_DEV && VIDEO_V4L2_SUBDEV_API + depends on HAS_DMA + depends on ARCH_TESLA_FSD + select VIDEOBUF2_DMA_CONTIG + select V4L2_FWNODE + help + This is a video4linux2 driver for TESLA FSD SoC MIPI-CSI2 Rx. + The driver provides interface for capturing frames. + + To compile this driver as a module, choose M here. The module + will be called fsd-csis. + diff --git a/drivers/media/platform/samsung/fsd-csis/Makefile b/drivers/med= ia/platform/samsung/fsd-csis/Makefile new file mode 100644 index 000000000000..754d628770b0 --- /dev/null +++ b/drivers/media/platform/samsung/fsd-csis/Makefile @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: GPL-2.0-only + +obj-$(CONFIG_VIDEO_TESLA_FSD_CSIS) +=3D fsd-csis.o diff --git a/drivers/media/platform/samsung/fsd-csis/fsd-csis.c b/drivers/m= edia/platform/samsung/fsd-csis/fsd-csis.c new file mode 100644 index 000000000000..c3029433eb27 --- /dev/null +++ b/drivers/media/platform/samsung/fsd-csis/fsd-csis.c @@ -0,0 +1,1690 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2022-2025 Samsung Electronics Co., Ltd. + * https://www.samsung.com + * + * TESLA FSD CSIS V4L2 Capture driver for TESLA FSD SoC. + */ + +#include +#include +#include +#include +#include +#include +#include + +#define FSD_CSIS_DMA_COHERENT_MASK_SIZE 32 +#define FSD_CSIS_NB_MIN_CH 2 +#define FSD_CSIS_NB_VC 4 +#define FSD_CSIS_MEDIA_NUM_PADS 2 +#define FSD_CSIS_NB_DMA_OUT_CH 8 +#define FSD_CSIS_MAX_VC 4 +#define FSD_CSIS_NB_CLOCK 2 +#define FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS 2 +#define FSD_CSIS_DMA_LINE_ALIGN_SIZE 128 +#define FSD_CSIS_DMA_CH_OFFSET 0x100 + +/** + * (Interrupt Source & mask register 1) + */ +#define FSD_CSIS_DMA_OTF_OVERLAP_MASK GENMASK(17, 14) +#define FSD_CSIS_DMA_ABORT_DONE_MASK BIT(13) +#define FSD_CSIS_DMA_ERROR_MASK BIT(12) +#define FSD_CSIS_INT_SRC1_ERR_ALL_MASK (FSD_CSIS_DMA_ERROR_MASK | \ + FSD_CSIS_DMA_ABORT_DONE_MASK | \ + FSD_CSIS_DMA_ERROR_MASK) +#define FDS_CSIS_DMA_FRM_END_MASK GENMASK(11, 8) +#define FSD_CSIS_DMA_FRM_START_MASK GENMASK(7, 4) +#define FSD_CSIS_LINE_END_MASK GENMASK(3, 0) +#define FSD_CSIS_DMA_CH0_MASK 0x4111U + +/* DMA Reg offsets */ +#define FSD_CSIS_DMA0_CTRL 0x0 +#define FSD_CSIS_DMA_CTRL(vc) (FSD_CSIS_DMA0_CTRL + (vc) * FSD_CSIS_DMA_CH= _OFFSET) +#define FSD_CSIS_DMA_DISABLE BIT(0) + +#define FSD_CSIS_DMA0_FMT 0x4 +#define FSD_CSIS_DMA_FMT(vc) (FSD_CSIS_DMA0_FMT + (vc) * FSD_CSIS_DMA_CH_O= FFSET) +#define FSD_CSIS_DMA_DIM BIT(15) +#define FSD_CSIS_DMA_DUMP BIT(13) + +#define FSD_CSIS_DMA0_ADDR1 0x10 +#define FSD_CSIS_DMA_ADDR1(vc) (FSD_CSIS_DMA0_ADDR1 + (vc) * FSD_CSIS_DMA_= CH_OFFSET) + +#define FSD_CSIS_DMA0_ACT_CTRL 0x30 +#define FSD_CSIS_DMA_ACT_CTRL(vc) (FSD_CSIS_DMA0_ACT_CTRL + (vc) * FSD_CSI= S_DMA_CH_OFFSET) +#define FSD_CSIS_ACTIVE_DMA_PACK_MASK GENMASK(17, 16) +#define FSD_CSIS_ACTIVE_DMA_PACK(n) ((n) << 16) +#define FSD_CSIS_ACTIVE_DMA_FRAMEPTR_MASK GENMASK(4, 2) + +#define FSD_CSIS_DMA_ERR_CODE 0x404 +#define FSD_CSIS_DMAFIFO_FULL_MASK BIT_MASK(5) +#define FSD_CSIS_TRXFIFO_FULL_MASK BIT_MASK(4) + +#define FSD_CSIS_DMA_CLK_CTRL 0x408 +#define FSD_CSIS_DMA_CLK_GATE_TRAIL_MASK GENMASK(4, 1) +#define FSD_CSIS_DMA_CLK_GATE_TRAIL(n) ((n) << 1) +#define FSD_CSIS_DMA_CLK_GATE_EN BIT(0) + +enum CSIS_DMA_PACK { + DMA_PACK_NORMAL, + DMA_PACK_10, + DMA_PACK_12, + DMA_PACK_14, + DMA_PACK_18, + DMA_PACK_20, +}; + +static const char * const fsd_csis_clk_id[] =3D { + "aclk", + "pclk", +}; + +struct fsd_csis_pixfmt { + u32 fourcc; + const u32 *codes; + int bpp; + bool is_yuv; +}; + +struct fsd_csis_vb2_buffer { + struct vb2_v4l2_buffer vb; + struct list_head list; + const struct fsd_csis_pixfmt *fmt; + unsigned long sequence_num; +}; + +struct fsd_csis { + struct device *dev; + const struct fsd_csis_info *info; + struct clk_bulk_data *clks; + struct clk *pll; + struct media_device mdev; + struct v4l2_device v4l2_dev; + struct v4l2_async_notifier notifier; + struct media_pipeline pipe; + + /* source node */ + struct { + struct v4l2_subdev *subdev; + struct media_pad *pad; + } source; + + /* Internal subdev */ + struct { + struct v4l2_subdev sd; + struct media_pad pad[FSD_CSIS_MEDIA_NUM_PADS]; + } subdev; + + struct video_device *vdev; + struct media_pad vdev_pad; + struct vb2_queue q; + /* Protect vdev operation */ + struct mutex vdev_mutex; + void __iomem *dma_base; + int irq; + u64 frame_addr[FSD_CSIS_NB_DMA_OUT_CH]; + struct fsd_csis_vb2_buffer *frame[FSD_CSIS_NB_DMA_OUT_CH]; + struct v4l2_pix_format vdev_fmt; + const struct fsd_csis_pixfmt *vdev_cc; + struct v4l2_rect vdev_compose; + u32 num_reqbufs; + u8 prev_dma_ptr; + u8 current_dma_ptr; + u8 number_of_ready_bufs; + u32 prev_frame_counter; + u32 current_frame_counter; + unsigned int num_active_fmt; + struct list_head ready_q; + /* Protect ready_q */ + spinlock_t q_lock; + /* Protect DMA channel register's */ + spinlock_t dma_reg_lock; + unsigned int current_vc; + unsigned long sequence; + u32 dma_error; + int is_streaming; +}; + +static inline u32 get_bits(u32 value, u32 mask) +{ + return (((value) & (mask)) >> (ffs(mask) - 1)); +} + +static inline u32 bytes_per_line(u32 width, int bpp) +{ + return (ALIGN((width * bpp), FSD_CSIS_DMA_LINE_ALIGN_SIZE) >> 3); +} + +static inline uint8_t fsd_csis_current_dma_ptr(struct fsd_csis *csis) + +{ + return (readl(csis->dma_base + FSD_CSIS_DMA_ACT_CTRL(csis->current_vc)) + & 0x01C) >> 2; +} + +#define FSD_CSIS_MODULE_NAME "fsd-csis" +#define FSD_CSIS_MODULE_VERSION "0.0.1" + +#define FSD_CSIS_DEF_MBUS_CODE MEDIA_BUS_FMT_RGB888_1X24 +#define FSD_CSIS_DEF_PIX_FORMAT V4L2_PIX_FMT_RGB24 +#define FSD_CSIS_DEF_PIX_WIDTH 1280 +#define FSD_CSIS_DEF_PIX_HEIGHT 964 + +#define FSD_CSIS_PAD_SINK 0 +#define FSD_CSIS_PAD_SRC 1 +#define FSD_CSIS_PADS_NUM 2 + +#define FSD_CSIS_BUS_FMTS(fmt...) ((const u32[]) {fmt, 0 }) + +static const struct v4l2_mbus_framefmt fsd_csis_default_format =3D { + .width =3D 640, + .height =3D 480, + .code =3D MEDIA_BUS_FMT_UYVY8_1X16, + .field =3D V4L2_FIELD_NONE, +}; + +static const struct fsd_csis_pixfmt pixel_formats[] =3D { + /* YUV formats start here */ + { + .fourcc =3D V4L2_PIX_FMT_UYVY, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_UYVY8_2X8, + MEDIA_BUS_FMT_UYVY8_1X16), + .is_yuv =3D true, + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_YUYV, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_YUYV8_2X8, + MEDIA_BUS_FMT_YUYV8_1X16), + .is_yuv =3D true, + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SBGGR8, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8), + .bpp =3D 8, + }, { + .fourcc =3D V4L2_PIX_FMT_SGBRG8, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8), + .bpp =3D 8, + }, { + .fourcc =3D V4L2_PIX_FMT_SGRBG8, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8), + .bpp =3D 8, + }, { + .fourcc =3D V4L2_PIX_FMT_SRGGB8, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8), + .bpp =3D 8, + }, { + .fourcc =3D V4L2_PIX_FMT_SBGGR10, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SBGGR10_1X10), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGBRG10, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGBRG10_1X10), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGRBG10, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGRBG10_1X10), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SRGGB10, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SRGGB10_1X10), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SBGGR12, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SBGGR12_1X12), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGBRG12, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGBRG12_1X12), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGRBG12, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGRBG12_1X12), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SRGGB12, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SRGGB12_1X12), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SBGGR14, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SBGGR14_1X14), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGBRG14, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGBRG14_1X14), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SGRBG14, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SGRBG14_1X14), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_SRGGB14, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_SRGGB14_1X14), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_GREY, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_Y8_1X8), + .bpp =3D 8, + }, { + .fourcc =3D V4L2_PIX_FMT_Y10, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_Y12, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_Y14, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_Y14_1X14), + .bpp =3D 16, + }, { + .fourcc =3D V4L2_PIX_FMT_RGB24, + .codes =3D FSD_CSIS_BUS_FMTS(MEDIA_BUS_FMT_RGB888_1X24), + .bpp =3D 24, + } +}; + +static void fsd_csis_dma_enable(struct fsd_csis *csis, bool en_dma) +{ + unsigned int dma_ctrl, vc =3D csis->current_vc; + + dma_ctrl =3D readl(csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); + dma_ctrl |=3D FSD_CSIS_DMA_DISABLE; + + if (en_dma) + dma_ctrl &=3D ~FSD_CSIS_DMA_DISABLE; + + writel(dma_ctrl, csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); +} + +static void fsd_csis_set_dma_clk(struct fsd_csis *csis) +{ + unsigned int dma_clk_ctrl; + + dma_clk_ctrl =3D readl(csis->dma_base + FSD_CSIS_DMA_CLK_CTRL); + + dma_clk_ctrl &=3D ~FSD_CSIS_DMA_CLK_GATE_EN; + dma_clk_ctrl &=3D ~FSD_CSIS_DMA_CLK_GATE_TRAIL_MASK; + dma_clk_ctrl |=3D FSD_CSIS_DMA_CLK_GATE_TRAIL(0x7); + + writel(dma_clk_ctrl, csis->dma_base + FSD_CSIS_DMA_CLK_CTRL); +} + +static void fsd_csis_set_pack(struct fsd_csis *csis, u32 vc, + enum CSIS_DMA_PACK dma_pack) +{ + u32 dma_fmt; + + dma_fmt =3D readl(csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); + dma_fmt &=3D ~FSD_CSIS_ACTIVE_DMA_PACK_MASK; + dma_fmt |=3D FSD_CSIS_ACTIVE_DMA_PACK(dma_pack); + writel(dma_fmt, csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); +} + +static void fsd_csis_set_dma_dump(struct fsd_csis *csis, unsigned int vc, + bool set_dump) +{ + u32 dma_fmt; + + dma_fmt =3D readl(csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); + dma_fmt &=3D ~FSD_CSIS_DMA_DUMP; + + if (set_dump) + dma_fmt |=3D FSD_CSIS_DMA_DUMP; + + writel(dma_fmt, csis->dma_base + FSD_CSIS_DMA_CTRL(vc)); +} + +static void fsd_csis_set_dma_dimension(struct fsd_csis *csis, u32 vc, bool= set_dim) +{ + u32 dma_fmt; + + dma_fmt =3D readl(csis->dma_base + FSD_CSIS_DMA_FMT(vc)); + dma_fmt &=3D ~FSD_CSIS_DMA_DIM; + + if (set_dim) + dma_fmt |=3D FSD_CSIS_DMA_DIM; + + writel(dma_fmt, csis->dma_base + FSD_CSIS_DMA_FMT(vc)); +} + +static void fsd_csis_set_dma_format(struct fsd_csis *csis, + const struct fsd_csis_pixfmt *cc) +{ + unsigned int fourcc =3D cc->fourcc; + + switch (fourcc) { + case V4L2_PIX_FMT_SBGGR10: + case V4L2_PIX_FMT_SGBRG10: + case V4L2_PIX_FMT_SGRBG10: + case V4L2_PIX_FMT_SRGGB10: + fsd_csis_set_pack(csis, csis->current_vc, DMA_PACK_10); + break; + case V4L2_PIX_FMT_SBGGR12: + case V4L2_PIX_FMT_SGBRG12: + case V4L2_PIX_FMT_SGRBG12: + case V4L2_PIX_FMT_SRGGB12: + fsd_csis_set_pack(csis, csis->current_vc, DMA_PACK_12); + break; + case V4L2_PIX_FMT_SBGGR14P: + fsd_csis_set_pack(csis, csis->current_vc, DMA_PACK_14); + break; + case V4L2_PIX_FMT_BGR666: + fsd_csis_set_pack(csis, csis->current_vc, DMA_PACK_18); + break; + case V4L2_PIX_FMT_UYVY: + fsd_csis_set_pack(csis, csis->current_vc, DMA_PACK_NORMAL); + break; + default: + dev_err(csis->dev, "Set DMA format %x not supported\n", fourcc); + break; + } + + fsd_csis_set_dma_dump(csis, csis->current_vc, false); + fsd_csis_set_dma_dimension(csis, csis->current_vc, false); +} + +static inline struct fsd_csis *notifier_to_csis(struct v4l2_async_notifier= *n) +{ + return container_of(n, struct fsd_csis, notifier); +} + +static int fsd_csis_queue_setup(struct vb2_queue *vq, + unsigned int *nbuffers, unsigned int *nplanes, + unsigned int sizes[], + struct device *alloc_devs[]) +{ + struct fsd_csis *csis =3D vb2_get_drv_priv(vq); + struct v4l2_pix_format *pix =3D &csis->vdev_fmt; + unsigned int size =3D pix->sizeimage; + + if (*nplanes) { + if (sizes[0] < size) + return -EINVAL; + size =3D sizes[0]; + } + + *nplanes =3D 1; + sizes[0] =3D size; + + dev_info(csis->dev, "nbuffers %d size %d\n", *nbuffers, sizes[0]); + + return 0; +} + +static int fsd_csis_buffer_prepare(struct vb2_buffer *vb) +{ + struct fsd_csis *csis =3D vb2_get_drv_priv(vb->vb2_queue); + struct fsd_csis_vb2_buffer *buf =3D container_of(vb, struct fsd_csis_vb2_= buffer, + vb.vb2_buf); + struct v4l2_pix_format *pix =3D &csis->vdev_fmt; + + if (WARN_ON(!csis->vdev_cc)) + return -EINVAL; + + if (vb2_plane_size(vb, 0) < pix->sizeimage) { + dev_info(csis->dev, "Data will not fit into plane (%lu < %u)\n", + vb2_plane_size(vb, 0), pix->sizeimage); + return -EINVAL; + } + + vb2_set_plane_payload(&buf->vb.vb2_buf, 0, pix->sizeimage); + + return 0; +} + +static void fsd_csis_buffer_queue(struct vb2_buffer *vb) +{ + unsigned long flags; + struct fsd_csis *csis =3D vb2_get_drv_priv(vb->vb2_queue); + struct fsd_csis_vb2_buffer *buf =3D + container_of(vb, struct fsd_csis_vb2_buffer, vb.vb2_buf); + + spin_lock_irqsave(&csis->q_lock, flags); + list_add_tail(&buf->list, &csis->ready_q); + buf->sequence_num =3D csis->sequence++; + spin_unlock_irqrestore(&csis->q_lock, flags); +} + +static void fsd_csis_dma_set_vid_base_addr(struct fsd_csis *csis, int frm_= no, + unsigned long addr) +{ + unsigned int dma_addr; + unsigned long flags; + + dma_addr =3D FSD_CSIS_DMA_ADDR1(csis->current_vc); + dma_addr =3D dma_addr + (frm_no * 4); + spin_lock_irqsave(&csis->dma_reg_lock, flags); + writel(addr, csis->dma_base + dma_addr); + spin_unlock_irqrestore(&csis->dma_reg_lock, flags); +} + +static void fsd_csis_add_to_ring_buffer(struct fsd_csis *csis, + struct fsd_csis_vb2_buffer *buf, + uint8_t index) +{ + u8 modulo_addr; + unsigned int i; + + for (i =3D 0; i < FSD_CSIS_NB_DMA_OUT_CH; + i +=3D FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS) { + modulo_addr =3D (index + i) % FSD_CSIS_NB_DMA_OUT_CH; + csis->frame[modulo_addr] =3D buf; + csis->frame_addr[modulo_addr] =3D + vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + fsd_csis_dma_set_vid_base_addr(csis, modulo_addr, + csis->frame_addr[modulo_addr]); + } +} + +static int fsd_csis_get_vc(struct fsd_csis *csis) +{ + struct v4l2_mbus_frame_desc fd =3D { }; + struct media_pad *remote_pad; + int ret; + + remote_pad =3D media_pad_remote_pad_unique(&csis->subdev.pad[FSD_CSIS_PAD= _SINK]); + ret =3D v4l2_subdev_call(csis->source.subdev, pad, get_frame_desc, remote= _pad->index, &fd); + if (ret < 0 && ret !=3D -ENOIOCTLCMD) { + dev_err(csis->dev, "get_frame_desc failed on source subdev\n"); + return ret; + } + + /* If remote subdev does not implement ..get_frame_desc default to VC0 */ + if (ret =3D=3D -ENOIOCTLCMD) + return 0; + + if (!fd.num_entries) { + dev_err(csis->dev, "get_frame_desc returned zero entries\n"); + return -EINVAL; + } + + return fd.entry[0].bus.csi2.vc; +} + +static int fsd_csis_start_streaming(struct vb2_queue *q, unsigned int coun= t) +{ + struct fsd_csis *csis =3D vb2_get_drv_priv(q); + struct fsd_csis_vb2_buffer *buf, *tmp; + unsigned long flags; + u8 i; + int ret; + + mutex_lock(&csis->mdev.graph_mutex); + + ret =3D __video_device_pipeline_start(csis->vdev, &csis->pipe); + if (ret) + goto err_unlock; + + ret =3D fsd_csis_get_vc(csis); + + if (ret < 0) + goto err_unlock; + + csis->current_vc =3D ret; + + ret =3D v4l2_subdev_enable_streams(&csis->subdev.sd, FSD_CSIS_PAD_SRC, + BIT(0)); + if (ret) { + dev_err(csis->dev, "stream on failed in subdev\n"); + goto err_stop; + } + + mutex_unlock(&csis->mdev.graph_mutex); + fsd_csis_set_dma_clk(csis); + fsd_csis_set_dma_format(csis, csis->vdev_cc); + + for (i =3D 0; i < FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS; i++) { + spin_lock_irqsave(&csis->q_lock, flags); + if (list_empty(&csis->ready_q)) { + spin_unlock_irqrestore(&csis->q_lock, flags); + dev_err(csis->dev, "Failed to fill buffer address!\n"); + return -EIO; + } + + buf =3D list_entry(csis->ready_q.next, struct fsd_csis_vb2_buffer, list); + list_del(&buf->list); + fsd_csis_add_to_ring_buffer(csis, buf, i); + spin_unlock_irqrestore(&csis->q_lock, flags); + } + + fsd_csis_dma_enable(csis, true); + + return 0; +err_stop: + v4l2_subdev_disable_streams(&csis->subdev.sd, FSD_CSIS_PAD_SRC, + BIT(0)); + __video_device_pipeline_stop(csis->vdev); +err_unlock: + mutex_unlock(&csis->mdev.graph_mutex); + + spin_lock_irqsave(&csis->q_lock, flags); + list_for_each_entry_safe(buf, tmp, &csis->ready_q, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED); + } + spin_unlock_irqrestore(&csis->q_lock, flags); + + dev_err(csis->dev, "pipeline start failed with %d\n", ret); + return ret; +} + +/** + * fsd_stop_streaming() - stop streaming for CSI context + * @q: pointer to vb2_queue in use + * Return: none + */ +static void fsd_csis_stop_streaming(struct vb2_queue *q) +{ + unsigned long flags; + struct fsd_csis *csis =3D vb2_get_drv_priv(q); + struct fsd_csis_vb2_buffer *buf, *tmp; + unsigned int timeout_cnt =3D 0; + int i; + void __iomem *dma_act_ctrl =3D 0; + + fsd_csis_dma_enable(csis, false); + + dma_act_ctrl =3D csis->dma_base + FSD_CSIS_DMA_ACT_CTRL(csis->current_vc); + + while ((readl(dma_act_ctrl) & 0x1) =3D=3D 0x0) { + if (timeout_cnt > 50) { + dev_dbg(csis->dev, "DMA did not finish in 500ms.\n"); + break; + } + usleep_range(10000, 20000); /* Wait min 10ms, max 20ms */ + timeout_cnt++; + } + + mutex_lock(&csis->mdev.graph_mutex); + v4l2_subdev_disable_streams(&csis->subdev.sd, FSD_CSIS_PAD_SRC, + BIT(0)); + __video_device_pipeline_stop(csis->vdev); + mutex_unlock(&csis->mdev.graph_mutex); + /* + * If still DMA operation exists after disabled irq, it will + * update dma_done part in interrupt source register. For next + * streaming session, this could be interpreted as current session's + * first frame done. To prevent this incorrect dma_done receiving, + * clearing interrupt source register here. + */ + + /* Release all active buffers */ + spin_lock_irqsave(&csis->q_lock, flags); + list_for_each_entry_safe(buf, tmp, &csis->ready_q, list) { + list_del(&buf->list); + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } + spin_unlock_irqrestore(&csis->q_lock, flags); + + for (i =3D 0; i < FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS; i++) { + buf =3D csis->frame[i]; + if (buf) + vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR); + } +} + +static int fsd_csis_video_open(struct file *file) +{ + struct fsd_csis *csis =3D video_drvdata(file); + int ret; + struct vb2_queue *q =3D &csis->q; + + if (vb2_is_busy(q)) { + dev_err(csis->dev, "device busy\n"); + return -EBUSY; + } + + ret =3D pm_runtime_resume_and_get(csis->dev); + if (ret < 0) + return ret; + + ret =3D v4l2_fh_open(file); + + if (ret) { + dev_err(csis->dev, "v4l2_fh_open failed\n"); + goto err; + } + + return ret; + +err: + pm_runtime_put(csis->dev); + return ret; +} + +static void fsd_csis_irq_worker(struct fsd_csis *csis) +{ + struct fsd_csis_vb2_buffer *buf_from; + struct fsd_csis_vb2_buffer *buf_to; + struct v4l2_subdev *subdev =3D csis->source.subdev; + u8 i; + void __iomem *dma_act_ctrl; + unsigned long flags; + + dma_act_ctrl =3D csis->dma_base + FSD_CSIS_DMA_ACT_CTRL(csis->current_vc); + csis->current_dma_ptr =3D readl(dma_act_ctrl); + csis->current_dma_ptr =3D get_bits(csis->current_dma_ptr, + FSD_CSIS_ACTIVE_DMA_FRAMEPTR_MASK); + + v4l2_subdev_call(subdev, core, command, 5, + &csis->current_frame_counter); + + if (csis->dma_error) { + dev_err(csis->dev, "prev_dma: %d, cur_dma: %d, prev_frm: %d, cur_frm: %d= \n", + csis->prev_dma_ptr, csis->current_dma_ptr, csis->prev_frame_counter, + csis->current_frame_counter); + csis->prev_dma_ptr =3D csis->current_dma_ptr; + goto update_prev_counters; + } + + if (csis->current_dma_ptr >=3D csis->prev_dma_ptr) + csis->number_of_ready_bufs =3D + csis->current_dma_ptr - csis->prev_dma_ptr; + else + csis->number_of_ready_bufs =3D + FSD_CSIS_NB_DMA_OUT_CH - csis->prev_dma_ptr + + csis->current_dma_ptr; + + if (csis->number_of_ready_bufs >=3D FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS || + ((csis->current_frame_counter - csis->prev_frame_counter) + >=3D FSD_CSIS_NB_DMA_OUT_CH)) { + /* In case of CSIS_NB_OF_BUFS_ON_DMA_CHANNELS or CSIS_NUM_DMA_OUT_CH num= ber + * of frames delays or more, set how many recent frames are ready to be = read + * in the next interrupt. This cannot be more than + * CSIS_NB_OF_BUFS_ON_DMA_CHANNELS-1 frames. + */ + csis->number_of_ready_bufs =3D FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS - 1; + csis->prev_dma_ptr =3D (csis->current_dma_ptr - + FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS) + & (FSD_CSIS_NB_DMA_OUT_CH - 1); + dev_err(csis->dev, "interrupt delayed %d frames\n", + csis->number_of_ready_bufs); + } + + if (csis->number_of_ready_bufs =3D=3D 0) { + dev_err(csis->dev, "Interrupt burst number_of_ready_bufs: %d\n", + csis->number_of_ready_bufs); + goto update_prev_counters; + } else { + if (csis->number_of_ready_bufs > 1) { + /* + * Interrupt has been missed. Do not populate DMA_ACT_CTRL pointer. + * Notify buffers ready until (DMA_ACT_CTRL - 1) pointer. + * Because,the delayed interrupt might be arrived in DMA active + * time. + */ + csis->number_of_ready_bufs--; + dev_err(csis->dev, "interrupt got delayed %d frames\n", + csis->number_of_ready_bufs); + } + } + + for (i =3D 0; i < csis->number_of_ready_bufs; i++) { + bool is_same_modulo; + + csis->prev_dma_ptr =3D (csis->prev_dma_ptr + 1) % FSD_CSIS_NB_DMA_OUT_CH; + is_same_modulo =3D !((csis->prev_dma_ptr - (csis->current_dma_ptr + 1)) % + FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS); + + spin_lock_irqsave(&csis->q_lock, flags); + + /* + * Before dequeuing buffer from DMA at least + * one buffer should be ready in vb2_queue + */ + if (list_empty(&csis->ready_q)) { + spin_unlock_irqrestore(&csis->q_lock, flags); + csis->prev_dma_ptr =3D csis->current_dma_ptr; + goto update_prev_counters; + + } else { + buf_from =3D list_entry(csis->ready_q.next, + struct fsd_csis_vb2_buffer, list); + list_del(&buf_from->list); + } + + spin_unlock_irqrestore(&csis->q_lock, flags); + + buf_to =3D csis->frame[csis->prev_dma_ptr]; + + if (is_same_modulo) { + if (csis->current_dma_ptr !=3D fsd_csis_current_dma_ptr(csis)) { + spin_lock_irqsave(&csis->q_lock, flags); + list_add_tail(&buf_from->list, &csis->ready_q); + spin_unlock_irqrestore(&csis->q_lock, flags); + continue; + } + } + + fsd_csis_add_to_ring_buffer(csis, buf_from, csis->prev_dma_ptr); + + if (buf_to) { + buf_to->vb.vb2_buf.timestamp =3D ktime_get_ns(); + vb2_buffer_done(&buf_to->vb.vb2_buf, + VB2_BUF_STATE_DONE); + } + } + +update_prev_counters: + csis->prev_frame_counter =3D csis->current_frame_counter; +} + +static irqreturn_t csis_irq_handler(int irq_csis, void *data) +{ + struct fsd_csis *csis =3D data; + struct v4l2_subdev *subdev =3D csis->source.subdev; + unsigned int int_src1 =3D 0x0; + unsigned int int1_err =3D 0x0; + unsigned int dma_error =3D 0x0, dma_err_code =3D 0x0, dma_error_vc =3D 0x= 0; + unsigned int err =3D 0x0; + unsigned int dma_frame_end =3D 0x0, dma_frame_end_vc =3D 0x0; + int i; + + v4l2_subdev_call(subdev, core, command, 2, &int_src1); + int1_err =3D get_bits(int_src1, FSD_CSIS_INT_SRC1_ERR_ALL_MASK); + + dma_frame_end =3D get_bits(int_src1, FDS_CSIS_DMA_FRM_END_MASK); + + if (int1_err) { + err =3D get_bits(int_src1, FSD_CSIS_DMA_OTF_OVERLAP_MASK); + if (err) + dev_err(csis->dev, "DMA OTF OVERLAP %x\n", err); + + dma_error =3D get_bits(int_src1, FSD_CSIS_DMA_ERROR_MASK); + + if (dma_error) { + dev_err(csis->dev, "DMA ERROR %x\n", dma_error); + dma_err_code =3D readl(csis->dma_base + FSD_CSIS_DMA_ERR_CODE); + dev_err(csis->dev, "Error code %x", dma_err_code); + } + } + + if (dma_frame_end || dma_error) { + for (i =3D 0; i < FSD_CSIS_MAX_VC; i++) { + dma_frame_end_vc =3D (dma_frame_end >> i) & 0x01; + if (dma_error) { + dma_error_vc =3D int_src1 & (FSD_CSIS_DMA_CH0_MASK << i); + dma_error_vc |=3D ((dma_err_code & (FSD_CSIS_DMAFIFO_FULL_MASK | + FSD_CSIS_TRXFIFO_FULL_MASK | + 0x01 << i)) << 18); + } + + if (dma_frame_end_vc || dma_error_vc) { + csis->dma_error =3D dma_error_vc; + fsd_csis_irq_worker(csis); + } + } + } + + v4l2_subdev_call(subdev, core, command, 3, &int_src1); + + return IRQ_HANDLED; +} + +static int fsd_csis_video_release(struct file *file) +{ + struct fsd_csis *csis =3D video_drvdata(file); + int ret; + + ret =3D vb2_fop_release(file); + + if (ret) + return ret; + + pm_runtime_put(csis->dev); + + return ret; +} + +static int fsd_csis_video_querycap(struct file *file, void *priv, + struct v4l2_capability *cap) +{ + struct fsd_csis *csis =3D video_drvdata(file); + + strscpy(cap->driver, FSD_CSIS_MODULE_NAME, sizeof(cap->driver)); + strscpy(cap->card, FSD_CSIS_MODULE_NAME, sizeof(cap->card)); + + snprintf(cap->bus_info, sizeof(cap->bus_info), + "platform:%s", dev_name(csis->dev)); + return 0; +} + +static int fsd_csis_video_enum_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_fmtdesc *f) +{ + unsigned int index =3D f->index; + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct fsd_csis_pixfmt *fmt =3D &pixel_formats[i]; + + if (f->mbus_code) { + unsigned int j; + + if (!fmt->codes) + continue; + + for (j =3D 0; fmt->codes[j]; j++) { + if (f->mbus_code =3D=3D fmt->codes[j]) + break; + } + + if (!fmt->codes[j]) + continue; + } + + if (index =3D=3D 0) { + f->pixelformat =3D fmt->fourcc; + return 0; + } + + index--; + } + + return -EINVAL; +} + +/* + * Search in the pixel_formats[] array for an entry with the given fourcc + * return it. + */ +static const struct fsd_csis_pixfmt *fsd_csis_find_pixel_format(u32 fourcc) +{ + const struct fsd_csis_pixfmt *fmt; + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(pixel_formats); i++) { + fmt =3D &pixel_formats[i]; + + if (fmt->fourcc =3D=3D fourcc) + return fmt; + } + + return NULL; +} + +/* + * Search in the pixel_formats[] array for an entry with the given media + * bus code and return it. + */ +static const struct fsd_csis_pixfmt *fsd_csis_find_mbus_format(u32 code) +{ + unsigned int i; + + for (i =3D 0; i < ARRAY_SIZE(pixel_formats); i++) { + const struct fsd_csis_pixfmt *fmt =3D &pixel_formats[i]; + unsigned int j; + + if (!fmt->codes) + continue; + + for (j =3D 0; fmt->codes[j]; j++) { + if (code =3D=3D fmt->codes[j]) + return fmt; + } + } + + return NULL; +} + +static int fsd_csis_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix, + const struct v4l2_mbus_framefmt *mbus, + const struct fsd_csis_pixfmt *cc) +{ + u32 width; + u32 stride; + + if (!cc) { + cc =3D fsd_csis_find_mbus_format(mbus->code); + if (!cc) + return -EINVAL; + } + + /* Round up width for minimum burst size */ + width =3D round_up(mbus->width, 8); + + /* Round up stride for IDMAC line start address alignment */ + stride =3D round_up((width * cc->bpp) >> 3, 8); + + pix->width =3D width; + pix->height =3D mbus->height; + pix->pixelformat =3D cc->fourcc; + pix->colorspace =3D mbus->colorspace; + pix->xfer_func =3D mbus->xfer_func; + pix->ycbcr_enc =3D mbus->ycbcr_enc; + pix->quantization =3D mbus->quantization; + pix->field =3D mbus->field; + pix->bytesperline =3D stride; + pix->sizeimage =3D stride * pix->height; + + return 0; +} + +static const struct fsd_csis_pixfmt + *__fsd_csis_video_try_fmt_vid_cap(struct fsd_csis *csis, + struct v4l2_pix_format *pixfmt) +{ + struct v4l2_mbus_framefmt fmt_src; + const struct fsd_csis_pixfmt *cc; + struct v4l2_rect *compose =3D &csis->vdev_compose; + + /* + * Find the pixel format, default to the first supported format if not + * found. + */ + cc =3D fsd_csis_find_pixel_format(pixfmt->pixelformat); + + if (!cc) { + pixfmt->pixelformat =3D FSD_CSIS_DEF_PIX_FORMAT; + pixfmt->height =3D FSD_CSIS_DEF_PIX_HEIGHT; + pixfmt->width =3D FSD_CSIS_DEF_PIX_WIDTH; + pixfmt->colorspace =3D V4L2_COLORSPACE_SRGB; + pixfmt->field =3D V4L2_FIELD_NONE; + cc =3D fsd_csis_find_pixel_format(pixfmt->pixelformat); + } + + v4l2_fill_mbus_format(&fmt_src, pixfmt, cc->codes[0]); + fsd_csis_mbus_fmt_to_pix_fmt(pixfmt, &fmt_src, cc); + + compose->width =3D fmt_src.width; + compose->height =3D fmt_src.height; + + csis->vdev_fmt =3D *pixfmt; + return cc; +} + +static int fsd_csis_video_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *f) +{ + struct fsd_csis *csis =3D video_drvdata(file); + + __fsd_csis_video_try_fmt_vid_cap(csis, &f->fmt.pix); + return 0; +} + +static int fsd_csis_video_s_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct fsd_csis *csis =3D video_drvdata(file); + struct v4l2_subdev *sd =3D &csis->subdev.sd; + const struct fsd_csis_pixfmt *cc; + struct vb2_queue *q =3D &csis->q; + int ret; + struct v4l2_subdev_format fmt =3D { + .which =3D V4L2_SUBDEV_FORMAT_ACTIVE, + .pad =3D 0, + }; + + if (vb2_is_busy(q)) { + dev_err(csis->dev, "%s queue busy\n", __func__); + return -EBUSY; + } + + cc =3D __fsd_csis_video_try_fmt_vid_cap(csis, &f->fmt.pix); + v4l2_fill_mbus_format(&fmt.format, &f->fmt.pix, cc->codes[0]); + ret =3D v4l2_subdev_call(sd, pad, set_fmt, sd->active_state, &fmt); + + if (ret < 0) { + dev_err(csis->dev, "subdev format set failed %d\n", ret); + return ret; + } + + csis->vdev_cc =3D cc; + csis->vdev_fmt =3D f->fmt.pix; + return 0; +} + +static int fsd_csis_video_g_fmt_vid_cap(struct file *file, void *priv, + struct v4l2_format *f) +{ + struct fsd_csis *csis =3D video_drvdata(file); + + f->fmt.pix =3D csis->vdev_fmt; + + return 0; +} + +static const struct vb2_ops fsd_csis_video_qops =3D { + .queue_setup =3D fsd_csis_queue_setup, + .buf_prepare =3D fsd_csis_buffer_prepare, + .buf_queue =3D fsd_csis_buffer_queue, + .start_streaming =3D fsd_csis_start_streaming, + .stop_streaming =3D fsd_csis_stop_streaming, + .wait_prepare =3D vb2_ops_wait_prepare, + .wait_finish =3D vb2_ops_wait_finish, +}; + +static const struct v4l2_ioctl_ops fsd_csis_video_ioctl_ops =3D { + .vidioc_querycap =3D fsd_csis_video_querycap, + + .vidioc_enum_fmt_vid_cap =3D fsd_csis_video_enum_fmt_vid_cap, + + .vidioc_try_fmt_vid_cap =3D fsd_csis_video_try_fmt_vid_cap, + .vidioc_s_fmt_vid_cap =3D fsd_csis_video_s_fmt_vid_cap, + .vidioc_g_fmt_vid_cap =3D fsd_csis_video_g_fmt_vid_cap, + + .vidioc_reqbufs =3D vb2_ioctl_reqbufs, + .vidioc_querybuf =3D vb2_ioctl_querybuf, + .vidioc_qbuf =3D vb2_ioctl_qbuf, + .vidioc_expbuf =3D vb2_ioctl_expbuf, + .vidioc_dqbuf =3D vb2_ioctl_dqbuf, + .vidioc_prepare_buf =3D vb2_ioctl_prepare_buf, + .vidioc_create_bufs =3D vb2_ioctl_create_bufs, + .vidioc_streamon =3D vb2_ioctl_streamon, + .vidioc_streamoff =3D vb2_ioctl_streamoff, +}; + +/** + * V4L2 File operations + */ +static const struct v4l2_file_operations fsd_csis_video_fops =3D { + .owner =3D THIS_MODULE, + .open =3D fsd_csis_video_open, + .release =3D fsd_csis_video_release, + .read =3D vb2_fop_read, + .poll =3D vb2_fop_poll, + .unlocked_ioctl =3D video_ioctl2, + .mmap =3D vb2_fop_mmap, +}; + +static int fsd_csi_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asd) +{ + struct fsd_csis *csis =3D notifier_to_csis(notifier); + struct media_pad *sink =3D &csis->subdev.pad[FSD_CSIS_PAD_SINK]; + struct media_pad *source; + int ret; + + dev_dbg(csis->dev, "Hooked csis subdevice: %s to parent\n", + subdev->name); + + ret =3D v4l2_create_fwnode_links_to_pad(subdev, sink, MEDIA_LNK_FL_ENABLE= D); + + if (ret) + return ret; + + source =3D media_pad_remote_pad_unique(sink); + if (IS_ERR(source)) { + dev_err(csis->dev, "No connected source pad\n"); + return PTR_ERR(source); + } + + csis->source.subdev =3D subdev; + csis->source.pad =3D source; + + return 0; +} + +static const struct v4l2_async_notifier_operations fsd_csi_notify_ops =3D { + .bound =3D fsd_csi_notify_bound, +}; + +static const struct media_device_ops fsd_csis_media_ops =3D { + .link_notify =3D v4l2_pipeline_link_notify, +}; + +static const struct media_entity_operations fsd_csis_entity_ops =3D { + .link_validate =3D v4l2_subdev_link_validate, + .get_fwnode_pad =3D v4l2_subdev_get_fwnode_pad_1_to_1, +}; + +static int fsd_csis_media_dev_init(struct fsd_csis *csis) +{ + int ret; + + strscpy(csis->mdev.model, "fsd-csis-media", sizeof(csis->mdev.model)); + csis->mdev.ops =3D &fsd_csis_media_ops; + csis->mdev.dev =3D csis->dev; + + csis->v4l2_dev.mdev =3D &csis->mdev; + strscpy(csis->v4l2_dev.name, "fsd-csis-media", + sizeof(csis->v4l2_dev.name)); + snprintf(csis->mdev.bus_info, sizeof(csis->mdev.bus_info), + "platform:%s", dev_name(csis->mdev.dev)); + + media_device_init(&csis->mdev); + + ret =3D v4l2_device_register(csis->dev, &csis->v4l2_dev); + + if (ret < 0) { + v4l2_err(&csis->v4l2_dev, + "Failed to register v4l2_device: %d\n", ret); + goto cleanup; + } + + return 0; + +cleanup: + media_device_cleanup(&csis->mdev); + + return ret; +} + +static void fsd_csis_media_cleanup(struct fsd_csis *csis) +{ + v4l2_device_unregister(&csis->v4l2_dev); + media_device_unregister(&csis->mdev); + v4l2_subdev_cleanup(&csis->subdev.sd); + media_device_cleanup(&csis->mdev); +} + +static int fsd_csis_video_init(struct fsd_csis *csis) +{ + struct video_device *vdev; + struct vb2_queue *vq; + int ret; + + mutex_init(&csis->vdev_mutex); + INIT_LIST_HEAD(&csis->ready_q); + spin_lock_init(&csis->q_lock); + spin_lock_init(&csis->dma_reg_lock); + + /* Allocate and initialize the video device.*/ + vdev =3D video_device_alloc(); + if (!vdev) + return -ENOMEM; + + vdev->fops =3D &fsd_csis_video_fops; + vdev->ioctl_ops =3D &fsd_csis_video_ioctl_ops; + vdev->minor =3D -1; + vdev->release =3D video_device_release; + vdev->device_caps =3D V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING; + vdev->lock =3D &csis->vdev_mutex; + vdev->queue =3D &csis->q; + + snprintf(vdev->name, sizeof(vdev->name), "%s capture", csis->subdev.sd.na= me); + + video_set_drvdata(vdev, csis); + csis->vdev =3D vdev; + + /* Initialize the video device pad. */ + csis->vdev_pad.flags =3D MEDIA_PAD_FL_SINK; + + ret =3D media_entity_pads_init(&vdev->entity, 1, &csis->vdev_pad); + if (ret) { + video_device_release(vdev); + return ret; + } + + /* Initialize the vb2 queue. */ + vq =3D &csis->q; + vq->type =3D V4L2_BUF_TYPE_VIDEO_CAPTURE; + vq->io_modes =3D VB2_MMAP | VB2_USERPTR | VB2_DMABUF; + vq->drv_priv =3D csis; + vq->buf_struct_size =3D sizeof(struct fsd_csis_vb2_buffer); + vq->ops =3D &fsd_csis_video_qops; + vq->mem_ops =3D &vb2_dma_contig_memops; + vq->timestamp_flags =3D V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC; + vq->lock =3D &csis->vdev_mutex; + vq->min_reqbufs_allocation =3D FSD_CSIS_NB_OF_BUFS_ON_DMA_CHANNELS + 1; + vq->min_queued_buffers =3D FSD_CSIS_NB_MIN_CH; + vq->dev =3D csis->dev; + + ret =3D vb2_queue_init(vq); + if (ret) { + dev_err(csis->dev, "vb2_queue_init failed\n"); + video_device_release(vdev); + return ret; + } + + return 0; +} + +static void fsd_csis_video_init_format(struct fsd_csis *csis) +{ + csis->vdev_fmt.width =3D FSD_CSIS_DEF_PIX_WIDTH; + csis->vdev_fmt.height =3D FSD_CSIS_DEF_PIX_HEIGHT; + csis->vdev_fmt.pixelformat =3D FSD_CSIS_DEF_PIX_FORMAT; + csis->vdev_fmt.colorspace =3D V4L2_COLORSPACE_SRGB; + csis->vdev_fmt.field =3D V4L2_FIELD_NONE; + + csis->vdev_cc =3D fsd_csis_find_pixel_format(csis->vdev_fmt.pixelformat); + + csis->vdev_fmt.bytesperline =3D bytes_per_line(FSD_CSIS_DEF_PIX_WIDTH, + csis->vdev_cc->bpp); + csis->vdev_fmt.sizeimage =3D csis->vdev_fmt.bytesperline * + csis->vdev_fmt.height; +} + +static int fsd_csis_video_register(struct fsd_csis *csis) +{ + struct v4l2_subdev *sd =3D &csis->subdev.sd; + struct v4l2_device *v4l2_dev =3D sd->v4l2_dev; + struct video_device *vdev =3D csis->vdev; + int ret; + + vdev->v4l2_dev =3D v4l2_dev; + + /* Initialize the default format and compose rectangle. */ + fsd_csis_video_init_format(csis); + + /* Register the video device. */ + ret =3D video_register_device(vdev, VFL_TYPE_VIDEO, -1); + if (ret) { + dev_err(csis->dev, "Failed to register video device\n"); + return ret; + } + + dev_info(csis->dev, "Registered %s as /dev/%s\n", vdev->name, + video_device_node_name(vdev)); + + /* Create the link from the CSI subdev to the video device. */ + ret =3D media_create_pad_link(&sd->entity, FSD_CSIS_PAD_SRC, + &vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE | + MEDIA_LNK_FL_ENABLED); + if (ret) { + dev_err(csis->dev, "failed to create link to device node\n"); + video_unregister_device(vdev); + return ret; + } + + return 0; +} + +static void fsd_csis_video_unregister(struct fsd_csis *csis) +{ + media_entity_cleanup(&csis->vdev->entity); + video_unregister_device(csis->vdev); +} + +static int fsd_csis_registered(struct v4l2_subdev *sd) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + int ret; + + ret =3D fsd_csis_video_init(csis); + if (ret) + return ret; + + ret =3D fsd_csis_video_register(csis); + if (ret) + return ret; + + ret =3D v4l2_device_register_subdev_nodes(&csis->v4l2_dev); + if (ret) + goto err_unregister; + + ret =3D media_device_register(&csis->mdev); + if (ret) + goto err_unregister; + + return 0; + +err_unregister: + fsd_csis_video_unregister(csis); + + return ret; +} + +static void fsd_csis_unregistered(struct v4l2_subdev *sd) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + + fsd_csis_video_unregister(csis); +} + +static int fsd_csis_sd_set_fmt(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *sdformat) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + struct v4l2_subdev *subdev =3D csis->source.subdev; + struct v4l2_mbus_framefmt *fmt; + const struct fsd_csis_pixfmt *cc; + + if (sdformat->which =3D=3D V4L2_SUBDEV_FORMAT_ACTIVE && csis->is_streamin= g) + return -EBUSY; + + if (sdformat->pad =3D=3D FSD_CSIS_PAD_SRC) + return v4l2_subdev_get_fmt(sd, sd_state, sdformat); + + if (sdformat->pad !=3D FSD_CSIS_PAD_SINK) + return -EINVAL; + + cc =3D fsd_csis_find_mbus_format(sdformat->format.code); + if (!cc) + cc =3D fsd_csis_find_mbus_format(FSD_CSIS_DEF_MBUS_CODE); + + fmt =3D v4l2_subdev_state_get_format(sd_state, sdformat->pad); + + fmt->code =3D cc->codes[0]; + fmt->width =3D sdformat->format.width; + fmt->height =3D sdformat->format.height; + fmt->field =3D V4L2_FIELD_NONE; + + sdformat->format =3D *fmt; + + /* Propagate the format from sink to source. */ + fmt =3D v4l2_subdev_state_get_format(sd_state, FSD_CSIS_PAD_SRC); + *fmt =3D sdformat->format; + + return v4l2_subdev_call(subdev, pad, set_fmt, subdev->active_state, sdfor= mat); +} + +static int __fsd_csis_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + struct v4l2_subdev_krouting *routing) +{ + struct v4l2_subdev_route *route; + int ret; + + ret =3D v4l2_subdev_routing_validate(sd, routing, + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); + if (ret) + return ret; + + ret =3D v4l2_subdev_set_routing(sd, state, routing); + if (ret) + return ret; + + for_each_active_route(&state->routing, route) { + const struct v4l2_mbus_framefmt *def_fmt; + struct v4l2_mbus_framefmt *fmt; + + def_fmt =3D &fsd_csis_default_format; + + fmt =3D v4l2_subdev_state_get_format(state, route->sink_pad, + route->sink_stream); + *fmt =3D *def_fmt; + fmt =3D v4l2_subdev_state_get_format(state, route->source_pad, + route->source_stream); + *fmt =3D *def_fmt; + } + + return 0; +} + +static int fsd_csis_sd_set_routing(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + enum v4l2_subdev_format_whence which, + struct v4l2_subdev_krouting *routing) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + + if (which =3D=3D V4L2_SUBDEV_FORMAT_ACTIVE && csis->is_streaming) + return -EBUSY; + + return __fsd_csis_sd_set_routing(sd, state, routing); +} + +static int fsd_csis_sd_enable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + + return v4l2_subdev_enable_streams(csis->source.subdev, + FSD_CSIS_PAD_SRC, BIT(0)); +} + +static int fsd_csis_sd_disable_streams(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state, + u32 pad, u64 streams_mask) +{ + struct fsd_csis *csis =3D v4l2_get_subdevdata(sd); + + return v4l2_subdev_disable_streams(csis->source.subdev, + FSD_CSIS_PAD_SRC, BIT(0)); +} + +static int fsd_csis_init_state(struct v4l2_subdev *sd, + struct v4l2_subdev_state *state) +{ + struct v4l2_subdev_route routes[] =3D { + { + .sink_pad =3D FSD_CSIS_PAD_SINK, + .sink_stream =3D 0, + .source_pad =3D FSD_CSIS_PAD_SRC, + .source_stream =3D 0, + .flags =3D V4L2_SUBDEV_ROUTE_FL_ACTIVE, + }, + }; + + struct v4l2_subdev_krouting routing =3D { + .len_routes =3D ARRAY_SIZE(routes), + .num_routes =3D ARRAY_SIZE(routes), + .routes =3D routes, + }; + + return __fsd_csis_sd_set_routing(sd, state, &routing); +} + +static const struct v4l2_subdev_internal_ops fsd_csis_internal_ops =3D { + .init_state =3D fsd_csis_init_state, + .registered =3D fsd_csis_registered, + .unregistered =3D fsd_csis_unregistered, +}; + +static const struct v4l2_subdev_pad_ops fsd_csis_pad_ops =3D { + .get_fmt =3D v4l2_subdev_get_fmt, + .set_fmt =3D fsd_csis_sd_set_fmt, + .set_routing =3D fsd_csis_sd_set_routing, + .enable_streams =3D fsd_csis_sd_enable_streams, + .disable_streams =3D fsd_csis_sd_disable_streams, +}; + +static const struct v4l2_subdev_ops fsd_csis_subdev_ops =3D { + .pad =3D &fsd_csis_pad_ops, +}; + +static int fsd_csis_media_init(struct fsd_csis *csis) +{ + struct v4l2_subdev *sd =3D &csis->subdev.sd; + int ret, i; + + /* add media device */ + ret =3D fsd_csis_media_dev_init(csis); + if (ret) + return ret; + + v4l2_subdev_init(sd, &fsd_csis_subdev_ops); + v4l2_set_subdevdata(sd, csis); + sd->internal_ops =3D &fsd_csis_internal_ops; + sd->entity.ops =3D &fsd_csis_entity_ops; + sd->entity.function =3D MEDIA_ENT_F_VID_IF_BRIDGE; + sd->dev =3D csis->dev; + sd->owner =3D THIS_MODULE; + sd->flags =3D V4L2_SUBDEV_FL_HAS_DEVNODE; + snprintf(sd->name, sizeof(sd->name), "csis"); + + for (i =3D 0; i < FSD_CSIS_PADS_NUM; i++) + csis->subdev.pad[i].flags =3D (i =3D=3D FSD_CSIS_PAD_SINK) ? + MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE; + + ret =3D media_entity_pads_init(&sd->entity, FSD_CSIS_PADS_NUM, + csis->subdev.pad); + + if (ret) + goto error; + + ret =3D v4l2_subdev_init_finalize(sd); + if (ret) + goto error; + + ret =3D v4l2_device_register_subdev(&csis->v4l2_dev, sd); + if (ret) + goto error; + + return 0; +error: + fsd_csis_media_cleanup(csis); + return ret; +} + +static int fsd_csis_async_register(struct fsd_csis *csis) +{ + struct v4l2_async_connection *asd; + struct fwnode_handle *ep; + int ret; + + v4l2_async_nf_init(&csis->notifier, &csis->v4l2_dev); + + ep =3D fwnode_graph_get_endpoint_by_id(dev_fwnode(csis->dev), 0, 0, + FWNODE_GRAPH_ENDPOINT_NEXT); + + if (ep) { + asd =3D v4l2_async_nf_add_fwnode_remote(&csis->notifier, ep, + struct v4l2_async_connection); + fwnode_handle_put(ep); + + if (IS_ERR(asd)) { + ret =3D PTR_ERR(asd); + /* OK if asd already exists */ + if (ret !=3D -EEXIST) + goto error; + } + } + + csis->notifier.ops =3D &fsd_csi_notify_ops; + + ret =3D v4l2_async_nf_register(&csis->notifier); + if (ret) + goto error; + + return 0; + +error: + v4l2_async_nf_cleanup(&csis->notifier); + return ret; +} + +static int fsd_csis_clk_get(struct fsd_csis *csis) +{ + int i; + + csis->clks =3D devm_kcalloc(csis->dev, FSD_CSIS_NB_CLOCK, sizeof(*csis->c= lks), GFP_KERNEL); + + if (!csis->clks) + return -ENOMEM; + + for (i =3D 0; i < FSD_CSIS_NB_CLOCK; i++) + csis->clks[i].id =3D fsd_csis_clk_id[i]; + + return devm_clk_bulk_get(csis->dev, FSD_CSIS_NB_CLOCK, csis->clks); +} + +static int fsd_csis_runtime_suspend(struct device *dev) +{ + struct fsd_csis *csis =3D dev_get_drvdata(dev); + + clk_bulk_disable_unprepare(FSD_CSIS_NB_CLOCK, csis->clks); + + return 0; +} + +static int fsd_csis_runtime_resume(struct device *dev) +{ + struct fsd_csis *csis =3D dev_get_drvdata(dev); + + return clk_bulk_prepare_enable(FSD_CSIS_NB_CLOCK, csis->clks); +} + +static const struct dev_pm_ops fsd_csis_pm_ops =3D { + SET_RUNTIME_PM_OPS(fsd_csis_runtime_suspend, fsd_csis_runtime_resume, + NULL) +}; + +static int fsd_csis_probe(struct platform_device *pdev) +{ + struct device *dev =3D &pdev->dev; + struct fsd_csis *csis; + int ret =3D 0; + int irq; + + csis =3D devm_kzalloc(dev, sizeof(*csis), GFP_KERNEL); + if (!csis) + return -ENOMEM; + + csis->dev =3D dev; + csis->info =3D of_device_get_match_data(dev); + + csis->dma_base =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(csis->dma_base)) + return PTR_ERR(csis->dma_base); + + irq =3D platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret =3D devm_request_irq(dev, irq, + csis_irq_handler, IRQF_SHARED, pdev->name, csis); + + ret =3D fsd_csis_clk_get(csis); + if (ret < 0) + return ret; + + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret =3D fsd_csis_runtime_resume(dev); + if (ret < 0) + return ret; + } + + platform_set_drvdata(pdev, csis); + + csis->pll =3D devm_clk_get_enabled(dev, "pll"); + if (IS_ERR(csis->pll)) { + dev_err(dev, "Failed to enable pll\n"); + return PTR_ERR(csis->pll); + } + + ret =3D fsd_csis_media_init(csis); + if (ret) + return ret; + + ret =3D fsd_csis_async_register(csis); + if (ret) + goto err_media_cleanup; + + return 0; + +err_media_cleanup: + fsd_csis_media_cleanup(csis); + + return ret; +} + +static void fsd_csis_remove(struct platform_device *pdev) +{ + struct fsd_csis *csis =3D platform_get_drvdata(pdev); + + fsd_csis_media_cleanup(csis); + + v4l2_async_nf_unregister(&csis->notifier); + v4l2_async_nf_cleanup(&csis->notifier); + v4l2_async_unregister_subdev(&csis->subdev.sd); + + if (!pm_runtime_enabled(csis->dev)) + fsd_csis_runtime_suspend(csis->dev); + + pm_runtime_disable(csis->dev); + pm_runtime_set_suspended(csis->dev); +} + +static const struct of_device_id fsd_csis_of_match[] =3D { + { .compatible =3D "tesla,fsd-csis-media", }, + { }, +}; + +MODULE_DEVICE_TABLE(of, fsd_csis_of_match); + +static struct platform_driver fsd_csis_driver =3D { + .probe =3D fsd_csis_probe, + .remove =3D fsd_csis_remove, + .driver =3D { + .name =3D FSD_CSIS_MODULE_NAME, + .of_match_table =3D fsd_csis_of_match, + .pm =3D &fsd_csis_pm_ops, + }, +}; + +module_platform_driver(fsd_csis_driver); + +MODULE_DESCRIPTION("FSD CSIS Video Capture Driver"); +MODULE_AUTHOR("Inbaraj E "); +MODULE_LICENSE("GPL"); + --=20 2.49.0