linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30
@ 2025-08-19 12:16 Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
                   ` (18 more replies)
  0 siblings, 19 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC along
with a set of changes required for that.

Svyatoslav Ryhel (19):
  clk: tegra: init CSUS clock for Tegra20 and Tegra30
  dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  clk: tegra30: add CSI PAD clock gates
  dt-bindings: display: tegra: document Tegra30 VIP
  staging: media: tegra-video: expand VI and VIP support to Tegra30
  staging: media: tegra-video: csi: move CSI helpers to header
  staging: media: tegra-video: csi: parametrize MIPI calibration device
    presence
  staging: media: tegra-video: vi: adjust get_selection op check
  staging: media: tegra-video: vi: add flip controls only if no source
    controls are provided
  staging: media: tegra-video: tegra20: set correct maximum width and
    height
  staging: media: tegra-video: tegra20: add support for second output of
    VI
  staging: media: tegra-video: tegra20: simplify format align
    calculations
  staging: media: tegra-video: tegra20: set VI HW revision
  staging: media: tegra-video: tegra20: increase maximum VI clock
    frequency
  staging: media: tegra-video: tegra20: expand format support with
    RAW8/10 and YUV422 1X16
  staging: media: tegra-video: tegra20: adjust luma buffer stride
  dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  ARM: tegra: add CSI binding for Tegra20 and Tegra30
  staging: media: tegra-video: add CSI support for Tegra20 and Tegra30

 .../display/tegra/nvidia,tegra20-vip.yaml     |   1 +
 .../display/tegra/nvidia,tegra210-csi.yaml    |  78 +-
 arch/arm/boot/dts/nvidia/tegra20.dtsi         |  17 +-
 arch/arm/boot/dts/nvidia/tegra30.dtsi         |  19 +-
 drivers/clk/tegra/clk-tegra20.c               |   1 +
 drivers/clk/tegra/clk-tegra30.c               |  16 +-
 drivers/staging/media/tegra-video/Makefile    |   1 +
 drivers/staging/media/tegra-video/csi.c       |  35 +-
 drivers/staging/media/tegra-video/csi.h       |  11 +
 drivers/staging/media/tegra-video/tegra20.c   | 771 +++++++++++++++---
 drivers/staging/media/tegra-video/tegra210.c  |   1 +
 drivers/staging/media/tegra-video/vi.c        |  20 +-
 drivers/staging/media/tegra-video/vi.h        |   4 +-
 drivers/staging/media/tegra-video/video.c     |   6 +
 drivers/staging/media/tegra-video/vip.c       |   5 +-
 include/dt-bindings/clock/tegra30-car.h       |   4 +-
 16 files changed, 842 insertions(+), 148 deletions(-)

-- 
2.48.1


^ permalink raw reply	[flat|nested] 59+ messages in thread

* [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-27  4:09   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
                   ` (17 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

CSUS clock is required to be enabled on camera device configuration or
else camera module refuses to initiate properly.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/clk/tegra/clk-tegra20.c | 1 +
 drivers/clk/tegra/clk-tegra30.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 551ef0cf0c9a..42f8150c6110 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
 	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
 	{ TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
 	{ TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
 	/* must be the last entry */
 	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
 };
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 82a8cb9545eb..70e85e2949e0 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
 	{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
 	{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
 	{ TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
+	{ TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
 	/* must be the last entry */
 	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
 };
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-22 13:59   ` Rob Herring
  2025-08-27  4:19   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
                   ` (16 subsequent siblings)
  18 siblings, 2 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
Add ids for these clocks.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 include/dt-bindings/clock/tegra30-car.h | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
index f193663e6f28..14b83e90a0fc 100644
--- a/include/dt-bindings/clock/tegra30-car.h
+++ b/include/dt-bindings/clock/tegra30-car.h
@@ -271,6 +271,8 @@
 #define TEGRA30_CLK_AUDIO3_MUX 306
 #define TEGRA30_CLK_AUDIO4_MUX 307
 #define TEGRA30_CLK_SPDIF_MUX 308
-#define TEGRA30_CLK_CLK_MAX 309
+#define TEGRA30_CLK_CSIA_PAD 309
+#define TEGRA30_CLK_CSIB_PAD 310
+#define TEGRA30_CLK_CLK_MAX 311
 
 #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-27  4:26   ` Mikko Perttunen
  2025-08-29  0:44   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
                   ` (15 subsequent siblings)
  18 siblings, 2 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
for correct work of CSI block.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 70e85e2949e0..f033eb1ac26a 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -153,6 +153,7 @@ static unsigned long input_freq;
 
 static DEFINE_SPINLOCK(cml_lock);
 static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_d2_lock);
 
 #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,	\
 			    _clk_num, _gate_flags, _clk_id)	\
@@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
 
 	/* PLLD2 */
 	clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0,
-			    &pll_d2_params, NULL);
+			    &pll_d2_params, &pll_d2_lock);
 	clks[TEGRA30_CLK_PLL_D2] = clk;
 
 	/* PLLD2_OUT0 */
@@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
 				    0, 48, periph_clk_enb_refcnt);
 	clks[TEGRA30_CLK_DSIA] = clk;
 
+	/* csia_pad */
+	clk = clk_register_gate(NULL, "csia_pad", "pll_d", CLK_SET_RATE_PARENT,
+				clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
+	clk_register_clkdev(clk, "csia_pad", NULL);
+	clks[TEGRA30_CLK_CSIA_PAD] = clk;
+
+	/* csib_pad */
+	clk = clk_register_gate(NULL, "csib_pad", "pll_d2", CLK_SET_RATE_PARENT,
+				clk_base + PLLD2_BASE, 26, 0, &pll_d2_lock);
+	clk_register_clkdev(clk, "csib_pad", NULL);
+	clks[TEGRA30_CLK_CSIB_PAD] = clk;
+
 	/* pcie */
 	clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
 				    70, periph_clk_enb_refcnt);
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (2 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 20:27   ` Rob Herring
  2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
                   ` (14 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
index 14294edb8d8c..39e9b3297dbd 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
@@ -13,6 +13,7 @@ properties:
   compatible:
     enum:
       - nvidia,tegra20-vip
+      - nvidia,tegra30-vip
 
   ports:
     $ref: /schemas/graph.yaml#/properties/ports
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (3 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-27  4:29   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
                   ` (13 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Exisitng VI and VIP implementation for Tegra20 is fully compatible with
Tegra30.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/Makefile | 1 +
 drivers/staging/media/tegra-video/vi.c     | 3 +++
 drivers/staging/media/tegra-video/vi.h     | 2 +-
 drivers/staging/media/tegra-video/video.c  | 4 ++++
 drivers/staging/media/tegra-video/vip.c    | 5 ++++-
 5 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/media/tegra-video/Makefile b/drivers/staging/media/tegra-video/Makefile
index 6c7552e05109..96380b5dbd8b 100644
--- a/drivers/staging/media/tegra-video/Makefile
+++ b/drivers/staging/media/tegra-video/Makefile
@@ -6,5 +6,6 @@ tegra-video-objs := \
 		csi.o
 
 tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC)  += tegra20.o
+tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC)  += tegra20.o
 tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
 obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index c9276ff76157..71be205cacb5 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1959,6 +1959,9 @@ static const struct of_device_id tegra_vi_of_id_table[] = {
 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 	{ .compatible = "nvidia,tegra20-vi",  .data = &tegra20_vi_soc },
 #endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-vi",  .data = &tegra20_vi_soc },
+#endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
 	{ .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
 #endif
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index 1e6a5caa7082..cac0c0d0e225 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -296,7 +296,7 @@ struct tegra_video_format {
 	u32 fourcc;
 };
 
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 extern const struct tegra_vi_soc tegra20_vi_soc;
 #endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
index 074ad0dc56ca..a25885f93cd7 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[] = {
 	{ .compatible = "nvidia,tegra20-vip", },
 	{ .compatible = "nvidia,tegra20-vi", },
 #endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-vip", },
+	{ .compatible = "nvidia,tegra30-vi", },
+#endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
 	{ .compatible = "nvidia,tegra210-csi", },
 	{ .compatible = "nvidia,tegra210-vi", },
diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c
index 5ec717f3afd5..00e08a9971d5 100644
--- a/drivers/staging/media/tegra-video/vip.c
+++ b/drivers/staging/media/tegra-video/vip.c
@@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 extern const struct tegra_vip_soc tegra20_vip_soc;
 #endif
 
 static const struct of_device_id tegra_vip_of_id_table[] = {
 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
 	{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
 #endif
 	{ }
 };
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (4 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
                   ` (12 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Move CSI helpers into the header for easier access from SoC-specific video
driver parts.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/csi.c | 11 -----------
 drivers/staging/media/tegra-video/csi.h | 10 ++++++++++
 2 files changed, 10 insertions(+), 11 deletions(-)

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 604185c00a1a..74c92db1032f 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -20,17 +20,6 @@
 
 #define MHZ			1000000
 
-static inline struct tegra_csi *
-host1x_client_to_csi(struct host1x_client *client)
-{
-	return container_of(client, struct tegra_csi, client);
-}
-
-static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev)
-{
-	return container_of(subdev, struct tegra_csi_channel, subdev);
-}
-
 /*
  * CSI is a separate subdevice which has 6 source pads to generate
  * test pattern. CSI subdevice pad ops are used only for TPG and
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 3e6e5ee1bb1e..3ed2dbc73ce9 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -151,6 +151,16 @@ struct tegra_csi {
 	struct list_head csi_chans;
 };
 
+static inline struct tegra_csi *host1x_client_to_csi(struct host1x_client *client)
+{
+	return container_of(client, struct tegra_csi, client);
+}
+
+static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev)
+{
+	return container_of(subdev, struct tegra_csi_channel, subdev);
+}
+
 void tegra_csi_error_recover(struct v4l2_subdev *subdev);
 void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
 				u8 csi_port_num,
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (5 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  0:46   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
                   ` (11 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
all MIPI calibration pads were part of VI block.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/csi.c      | 12 +++++++-----
 drivers/staging/media/tegra-video/csi.h      |  1 +
 drivers/staging/media/tegra-video/tegra210.c |  1 +
 3 files changed, 9 insertions(+), 5 deletions(-)

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 74c92db1032f..2f9907a20db1 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
 	if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
 		return 0;
 
-	chan->mipi = tegra_mipi_request(csi->dev, node);
-	if (IS_ERR(chan->mipi)) {
-		ret = PTR_ERR(chan->mipi);
-		chan->mipi = NULL;
-		dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
+	if (csi->soc->has_mipi_calibration) {
+		chan->mipi = tegra_mipi_request(csi->dev, node);
+		if (IS_ERR(chan->mipi)) {
+			ret = PTR_ERR(chan->mipi);
+			chan->mipi = NULL;
+			dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
+		}
 	}
 
 	return ret;
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 3ed2dbc73ce9..400b913bb1cb 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -128,6 +128,7 @@ struct tegra_csi_soc {
 	unsigned int num_clks;
 	const struct tpg_framerate *tpg_frmrate_table;
 	unsigned int tpg_frmrate_table_size;
+	bool has_mipi_calibration;
 };
 
 /**
diff --git a/drivers/staging/media/tegra-video/tegra210.c b/drivers/staging/media/tegra-video/tegra210.c
index da99f19a39e7..305472e94af4 100644
--- a/drivers/staging/media/tegra-video/tegra210.c
+++ b/drivers/staging/media/tegra-video/tegra210.c
@@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
 	.num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
 	.tpg_frmrate_table = tegra210_tpg_frmrate_table,
 	.tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
+	.has_mipi_calibration = true,
 };
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (6 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
                   ` (10 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Get_selection operation may be implemented only for sink pad and may
return error code. Set try_crop to 0 instead of returning error.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/vi.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 71be205cacb5..4f67adc395ac 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -476,15 +476,11 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
 	fse.code = fmtinfo->code;
 	ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse);
 	if (ret) {
-		if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
+		if (!v4l2_subdev_has_op(subdev, pad, get_selection) ||
+		    v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel)) {
 			try_crop->width = 0;
 			try_crop->height = 0;
 		} else {
-			ret = v4l2_subdev_call(subdev, pad, get_selection,
-					       NULL, &sdsel);
-			if (ret)
-				return -EINVAL;
-
 			try_crop->width = sdsel.r.width;
 			try_crop->height = sdsel.r.height;
 		}
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (7 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
                   ` (9 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Add HFLIP and VFLIP from SoC only if camera sensor does not provide those
controls.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/vi.c | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 4f67adc395ac..61b65a2c1436 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -961,6 +961,7 @@ static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
 	}
 #else
 	struct v4l2_subdev *subdev;
+	struct v4l2_ctrl *hflip, *vflip;
 
 	/* custom control */
 	v4l2_ctrl_new_custom(&chan->ctrl_handler, &syncpt_timeout_ctrl, NULL);
@@ -986,11 +987,13 @@ static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
 		return ret;
 	}
 
-	if (chan->vi->soc->has_h_v_flip) {
+	hflip = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_HFLIP);
+	if (chan->vi->soc->has_h_v_flip && !hflip)
 		v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
-		v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
-	}
 
+	vflip = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_VFLIP);
+	if (chan->vi->soc->has_h_v_flip && !vflip)
+		v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
 #endif
 
 	/* setup the controls */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (8 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  0:51   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
                   ` (8 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Maximum width and height for Tegra20 and Tegra30 is determined by
respective register field, rounded down to factor of 2, which is 8191U
rounded down to 8190U.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 7b8f8f810b35..3e2d746638b6 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -23,11 +23,10 @@
 
 #define TEGRA_VI_SYNCPT_WAIT_TIMEOUT			msecs_to_jiffies(200)
 
-/* This are just good-sense numbers. The actual min/max is not documented. */
 #define TEGRA20_MIN_WIDTH	32U
+#define TEGRA20_MAX_WIDTH	8190U
 #define TEGRA20_MIN_HEIGHT	32U
-#define TEGRA20_MAX_WIDTH	2048U
-#define TEGRA20_MAX_HEIGHT	2048U
+#define TEGRA20_MAX_HEIGHT	8190U
 
 /* --------------------------------------------------------------------------
  * Registers
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (9 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  1:00   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
                   ` (7 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

VI in Tegra20/Tegra30 has 2 VI outputs with different set of supported
formats. Convert output registers to macros for simpler work with both
outputs since apart formats their layout matches.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 80 ++++++++++++---------
 1 file changed, 45 insertions(+), 35 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 3e2d746638b6..54512d1ecf83 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -28,13 +28,19 @@
 #define TEGRA20_MIN_HEIGHT	32U
 #define TEGRA20_MAX_HEIGHT	8190U
 
+/* Tegra20/Tegra30 has 2 outputs in VI */
+enum {
+	OUT_1,
+	OUT_2,
+};
+
 /* --------------------------------------------------------------------------
  * Registers
  */
 
-#define TEGRA_VI_CONT_SYNCPT_OUT_1			0x0060
-#define       VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT	BIT(8)
-#define       VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT	0
+#define TEGRA_VI_CONT_SYNCPT_OUT(n)			(0x0060 + (n) * 4)
+#define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT	BIT(8)
+#define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT		0
 
 #define TEGRA_VI_VI_INPUT_CONTROL			0x0088
 #define       VI_INPUT_FIELD_DETECT			BIT(27)
@@ -46,6 +52,7 @@
 #define       VI_INPUT_YUV_INPUT_FORMAT_YVYU		(3 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
 #define       VI_INPUT_INPUT_FORMAT_SFT			2  /* bits [5:2] */
 #define       VI_INPUT_INPUT_FORMAT_YUV422		(0 << VI_INPUT_INPUT_FORMAT_SFT)
+#define       VI_INPUT_INPUT_FORMAT_BAYER		(2 << VI_INPUT_INPUT_FORMAT_SFT)
 #define       VI_INPUT_VIP_INPUT_ENABLE			BIT(1)
 
 #define TEGRA_VI_VI_CORE_CONTROL			0x008c
@@ -66,7 +73,7 @@
 #define       VI_VI_CORE_CONTROL_OUTPUT_TO_EPP_SFT	2
 #define       VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_SFT	0
 
-#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL		0x0090
+#define TEGRA_VI_VI_OUTPUT_CONTROL(n)			(0x0090 + (n) * 4)
 #define       VI_OUTPUT_FORMAT_EXT			BIT(22)
 #define       VI_OUTPUT_V_DIRECTION			BIT(20)
 #define       VI_OUTPUT_H_DIRECTION			BIT(19)
@@ -80,6 +87,7 @@
 #define       VI_OUTPUT_OUTPUT_FORMAT_SFT		0
 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST	(3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR	(6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT	(9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
 
 #define TEGRA_VI_VIP_H_ACTIVE				0x00a4
 #define       VI_VIP_H_ACTIVE_PERIOD_SFT		16 /* active pixels/line, must be even */
@@ -89,26 +97,26 @@
 #define       VI_VIP_V_ACTIVE_PERIOD_SFT		16 /* active lines */
 #define       VI_VIP_V_ACTIVE_START_SFT			0
 
-#define TEGRA_VI_VB0_START_ADDRESS_FIRST		0x00c4
-#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST			0x00c8
+#define TEGRA_VI_VB0_START_ADDRESS(n)			(0x00c4 + (n) * 44)
+#define TEGRA_VI_VB0_BASE_ADDRESS(n)			(0x00c8 + (n) * 44)
 #define TEGRA_VI_VB0_START_ADDRESS_U			0x00cc
 #define TEGRA_VI_VB0_BASE_ADDRESS_U			0x00d0
 #define TEGRA_VI_VB0_START_ADDRESS_V			0x00d4
 #define TEGRA_VI_VB0_BASE_ADDRESS_V			0x00d8
 
-#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE		0x00e0
-#define       VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT		16
-#define       VI_FIRST_OUTPUT_FRAME_WIDTH_SFT		0
+#define TEGRA_VI_OUTPUT_FRAME_SIZE(n)			(0x00e0 + (n) * 24)
+#define       VI_OUTPUT_FRAME_HEIGHT_SFT		16
+#define       VI_OUTPUT_FRAME_WIDTH_SFT			0
 
-#define TEGRA_VI_VB0_COUNT_FIRST			0x00e4
+#define TEGRA_VI_VB0_COUNT(n)				(0x00e4 + (n) * 24)
 
-#define TEGRA_VI_VB0_SIZE_FIRST				0x00e8
-#define       VI_VB0_SIZE_FIRST_V_SFT			16
-#define       VI_VB0_SIZE_FIRST_H_SFT			0
+#define TEGRA_VI_VB0_SIZE(n)				(0x00e8 + (n) * 24)
+#define       VI_VB0_SIZE_V_SFT				16
+#define       VI_VB0_SIZE_H_SFT				0
 
-#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST		0x00ec
-#define       VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT	30
-#define       VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT	0
+#define TEGRA_VI_VB0_BUFFER_STRIDE(n)			(0x00ec + (n) * 24)
+#define       VI_VB0_BUFFER_STRIDE_CHROMA_SFT		30
+#define       VI_VB0_BUFFER_STRIDE_LUMA_SFT		0
 
 #define TEGRA_VI_H_LPF_CONTROL				0x0108
 #define       VI_H_LPF_CONTROL_CHROMA_SFT		16
@@ -136,7 +144,7 @@
 #define       VI_CAMERA_CONTROL_TEST_MODE		BIT(1)
 #define       VI_CAMERA_CONTROL_VIP_ENABLE		BIT(0)
 
-#define TEGRA_VI_VI_ENABLE				0x01a4
+#define TEGRA_VI_VI_ENABLE(n)				(0x01a4 + (n) * 4)
 #define       VI_VI_ENABLE_SW_FLOW_CONTROL_OUT1		BIT(1)
 #define       VI_VI_ENABLE_FIRST_OUTPUT_TO_MEM_DISABLE	BIT(0)
 
@@ -366,8 +374,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
 	case V4L2_PIX_FMT_VYUY:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_YVYU:
-		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,  base);
-		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_FIRST, base + chan->start_offset);
+		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_1),  base);
+		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset);
 		break;
 	}
 }
@@ -455,6 +463,7 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	int stride_l = chan->format.bytesperline;
 	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
 			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
+	int output_channel = OUT_1;
 	int main_output_format;
 	int yuv_output_format;
 
@@ -472,33 +481,33 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	/* Set up raise-on-edge, so we get an interrupt on end of frame. */
 	tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
 
-	tegra20_vi_write(chan, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
+	tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
 			 (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
 			 (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
 			 yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
 			 main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
 
 	/* Set up frame size */
-	tegra20_vi_write(chan, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
-			 height << VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT |
-			 width  << VI_FIRST_OUTPUT_FRAME_WIDTH_SFT);
+	tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
+			 height << VI_OUTPUT_FRAME_HEIGHT_SFT |
+			 width  << VI_OUTPUT_FRAME_WIDTH_SFT);
 
 	/* First output memory enabled */
-	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
+	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
 
 	/* Set the number of frames in the buffer */
-	tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT_FIRST, 1);
+	tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT(output_channel), 1);
 
 	/* Set up buffer frame size */
-	tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE_FIRST,
-			 height << VI_VB0_SIZE_FIRST_V_SFT |
-			 width  << VI_VB0_SIZE_FIRST_H_SFT);
+	tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE(output_channel),
+			 height << VI_VB0_SIZE_V_SFT |
+			 width  << VI_VB0_SIZE_H_SFT);
 
-	tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
-			 stride_l << VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT |
-			 stride_c << VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT);
+	tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE(output_channel),
+			 stride_l << VI_VB0_BUFFER_STRIDE_LUMA_SFT |
+			 stride_c << VI_VB0_BUFFER_STRIDE_CHROMA_SFT);
 
-	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
+	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
 }
 
 static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
@@ -607,6 +616,7 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 	struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&vip_chan->subdev);
 	int width  = vi_chan->format.width;
 	int height = vi_chan->format.height;
+	int output_channel = OUT_1;
 
 	unsigned int main_input_format;
 	unsigned int yuv_input_format;
@@ -637,10 +647,10 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 			 GENMASK(9, 2) << VI_DATA_INPUT_SFT);
 	tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INVERSION, 0);
 
-	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT_1,
-			 VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT |
+	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
+			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
 			 host1x_syncpt_id(vi_chan->mw_ack_sp[0])
-			 << VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT);
+			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
 
 	tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (10 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
                   ` (6 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Simplify format align calculations by slightly modifying supported formats
structure.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 41 ++++++++-------------
 1 file changed, 16 insertions(+), 25 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 54512d1ecf83..735611c3c47d 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -279,20 +279,8 @@ static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
 	pix->width  = clamp(pix->width,  TEGRA20_MIN_WIDTH,  TEGRA20_MAX_WIDTH);
 	pix->height = clamp(pix->height, TEGRA20_MIN_HEIGHT, TEGRA20_MAX_HEIGHT);
 
-	switch (pix->pixelformat) {
-	case V4L2_PIX_FMT_UYVY:
-	case V4L2_PIX_FMT_VYUY:
-	case V4L2_PIX_FMT_YUYV:
-	case V4L2_PIX_FMT_YVYU:
-		pix->bytesperline = roundup(pix->width, 2) * 2;
-		pix->sizeimage = roundup(pix->width, 2) * 2 * pix->height;
-		break;
-	case V4L2_PIX_FMT_YUV420:
-	case V4L2_PIX_FMT_YVU420:
-		pix->bytesperline = roundup(pix->width, 8);
-		pix->sizeimage = roundup(pix->width, 8) * pix->height * 3 / 2;
-		break;
-	}
+	pix->bytesperline = DIV_ROUND_UP(pix->width * bpp, 8);
+	pix->sizeimage = pix->bytesperline * pix->height;
 }
 
 /*
@@ -575,20 +563,23 @@ static const struct tegra_vi_ops tegra20_vi_ops = {
 	.vi_stop_streaming = tegra20_vi_stop_streaming,
 };
 
-#define TEGRA20_VIDEO_FMT(MBUS_CODE, BPP, FOURCC)	\
-{							\
-	.code    = MEDIA_BUS_FMT_##MBUS_CODE,		\
-	.bpp     = BPP,					\
-	.fourcc  = V4L2_PIX_FMT_##FOURCC,		\
+#define TEGRA20_VIDEO_FMT(DATA_TYPE, BIT_WIDTH, MBUS_CODE, BPP, FOURCC)	\
+{									\
+	.img_dt		= TEGRA_IMAGE_DT_##DATA_TYPE,			\
+	.bit_width	= BIT_WIDTH,					\
+	.code		= MEDIA_BUS_FMT_##MBUS_CODE,			\
+	.bpp		= BPP,						\
+	.fourcc		= V4L2_PIX_FMT_##FOURCC,			\
 }
 
 static const struct tegra_video_format tegra20_video_formats[] = {
-	TEGRA20_VIDEO_FMT(UYVY8_2X8, 2, UYVY),
-	TEGRA20_VIDEO_FMT(VYUY8_2X8, 2, VYUY),
-	TEGRA20_VIDEO_FMT(YUYV8_2X8, 2, YUYV),
-	TEGRA20_VIDEO_FMT(YVYU8_2X8, 2, YVYU),
-	TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YUV420),
-	TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YVU420),
+	/* YUV422 */
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 16, UYVY),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_2X8, 16, VYUY),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_2X8, 16, YUYV),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16, YVYU),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
 };
 
 const struct tegra_vi_soc tegra20_vi_soc = {
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (11 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
                   ` (5 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Tegra20, Tegra30 and Tegra114 have VI revision 1.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 735611c3c47d..71dcb982c97b 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -587,6 +587,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 	.nformats = ARRAY_SIZE(tegra20_video_formats),
 	.default_video_format = &tegra20_video_formats[0],
 	.ops = &tegra20_vi_ops,
+	.hw_revision = 1,
 	.vi_max_channels = 1, /* parallel input (VIP) */
 	.vi_max_clk_hz = 150000000,
 	.has_h_v_flip = true,
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (12 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
                   ` (4 subsequent siblings)
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Increase maximum VI clock frequency to 450MHz to allow correct work with
high resolution camera sensors.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 71dcb982c97b..67631e0c9ffc 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -589,7 +589,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 	.ops = &tegra20_vi_ops,
 	.hw_revision = 1,
 	.vi_max_channels = 1, /* parallel input (VIP) */
-	.vi_max_clk_hz = 150000000,
+	.vi_max_clk_hz = 450000000,
 	.has_h_v_flip = true,
 };
 
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (13 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  1:09   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
                   ` (3 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
of existing YUV422_8 2X8.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
 1 file changed, 69 insertions(+), 2 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 67631e0c9ffc..b466fe7f4504 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct tegra_vi_channel *chan,
 	case MEDIA_BUS_FMT_YVYU8_2X8:
 		(*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
 		break;
+	/* RAW8 */
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	/* RAW10 */
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+		(*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
+		break;
 	}
 }
 
@@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct tegra_vi_channel *chan,
 	case V4L2_PIX_FMT_YVU420:
 		(*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
 		break;
+	/* RAW8 */
+	case V4L2_PIX_FMT_SBGGR8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SRGGB8:
+	/* RAW10 */
+	case V4L2_PIX_FMT_SBGGR10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SRGGB10:
+		(*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
+		break;
 	}
 }
 
@@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct tegra_vi_channel *chan)
 	case V4L2_PIX_FMT_VYUY:
 	case V4L2_PIX_FMT_YUYV:
 	case V4L2_PIX_FMT_YVYU:
+	/* RAW8 */
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+	/* RAW10 */
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
 		if (chan->vflip)
 			chan->start_offset += stride * (height - 1);
 		if (chan->hflip)
@@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
 		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_1),  base);
 		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset);
 		break;
+	/* RAW8 */
+	case V4L2_PIX_FMT_SRGGB8:
+	case V4L2_PIX_FMT_SGRBG8:
+	case V4L2_PIX_FMT_SGBRG8:
+	case V4L2_PIX_FMT_SBGGR8:
+	/* RAW10 */
+	case V4L2_PIX_FMT_SRGGB10:
+	case V4L2_PIX_FMT_SGRBG10:
+	case V4L2_PIX_FMT_SGBRG10:
+	case V4L2_PIX_FMT_SBGGR10:
+		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2),  base);
+		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2), base + chan->start_offset);
+		break;
 	}
 }
 
@@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void *data)
 static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 {
 	u32 output_fourcc = chan->format.pixelformat;
+	u32 data_type = chan->fmtinfo->img_dt;
 	int width  = chan->format.width;
 	int height = chan->format.height;
 	int stride_l = chan->format.bytesperline;
 	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
 			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
-	int output_channel = OUT_1;
+	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+			      data_type == TEGRA_IMAGE_DT_RAW10) ?
+			      OUT_2 : OUT_1;
 	int main_output_format;
 	int yuv_output_format;
 
@@ -580,6 +630,20 @@ static const struct tegra_video_format tegra20_video_formats[] = {
 	TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16, YVYU),
 	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
 	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
+	TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
+	/* RAW 8 */
+	TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
+	TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
+	TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
+	TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
+	/* RAW 10 */
+	TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
+	TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
+	TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
+	TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
 };
 
 const struct tegra_vi_soc tegra20_vi_soc = {
@@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 {
 	struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&vip_chan->subdev);
+	u32 data_type = vi_chan->fmtinfo->img_dt;
 	int width  = vi_chan->format.width;
 	int height = vi_chan->format.height;
-	int output_channel = OUT_1;
+	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+			      data_type == TEGRA_IMAGE_DT_RAW10) ?
+			      OUT_2 : OUT_1;
 
 	unsigned int main_input_format;
 	unsigned int yuv_input_format;
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (14 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  1:16   ` Mikko Perttunen
  2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
                   ` (2 subsequent siblings)
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Luma buffer stride is calculated by multiplying height in pixels of image
by bytes per line. Adjust that value accordingly.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/tegra20.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index b466fe7f4504..a06afe91d2de 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -496,7 +496,7 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	u32 data_type = chan->fmtinfo->img_dt;
 	int width  = chan->format.width;
 	int height = chan->format.height;
-	int stride_l = chan->format.bytesperline;
+	int stride_l = chan->format.bytesperline * height;
 	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
 			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
 	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (15 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 20:30   ` Rob Herring
  2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Document CSI hw block found in Tegra20 and Tegra30 SoC.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../display/tegra/nvidia,tegra210-csi.yaml    | 78 +++++++++++++++----
 1 file changed, 63 insertions(+), 15 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
index fa07a40d1004..a5669447a33b 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
@@ -16,30 +16,78 @@ properties:
 
   compatible:
     enum:
+      - nvidia,tegra20-csi
+      - nvidia,tegra30-csi
       - nvidia,tegra210-csi
 
   reg:
     maxItems: 1
 
-  clocks:
-    items:
-      - description: module clock
-      - description: A/B lanes clock
-      - description: C/D lanes clock
-      - description: E lane clock
-      - description: test pattern generator clock
-
-  clock-names:
-    items:
-      - const: csi
-      - const: cilab
-      - const: cilcd
-      - const: cile
-      - const: csi_tpg
+  clocks: true
+  clock-names: true
 
   power-domains:
     maxItems: 1
 
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - nvidia,tegra20-csi
+    then:
+      properties:
+        clocks:
+          items:
+            - description: module clock
+
+        clock-names:
+          items:
+            - const: csi
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - nvidia,tegra30-csi
+    then:
+      properties:
+        clocks:
+          items:
+            - description: module clock
+            - description: PAD A clock
+            - description: PAD B clock
+
+        clock-names:
+          items:
+            - const: csi
+            - const: csia_pad
+            - const: csib_pad
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - nvidia,tegra210-csi
+    then:
+      properties:
+        clocks:
+          items:
+            - description: module clock
+            - description: A/B lanes clock
+            - description: C/D lanes clock
+            - description: E lane clock
+            - description: test pattern generator clock
+
+        clock-names:
+          items:
+            - const: csi
+            - const: cilab
+            - const: cilcd
+            - const: cile
+            - const: csi_tpg
+
 additionalProperties: false
 
 required:
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (16 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
  18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Add CSI node to Tegra20 and Tegra30 device trees.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 arch/arm/boot/dts/nvidia/tegra20.dtsi | 17 ++++++++++++++++-
 arch/arm/boot/dts/nvidia/tegra30.dtsi | 19 ++++++++++++++++++-
 2 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/nvidia/tegra20.dtsi b/arch/arm/boot/dts/nvidia/tegra20.dtsi
index 606839fd40bb..d00786368115 100644
--- a/arch/arm/boot/dts/nvidia/tegra20.dtsi
+++ b/arch/arm/boot/dts/nvidia/tegra20.dtsi
@@ -64,7 +64,7 @@ mpe@54040000 {
 
 		vi@54080000 {
 			compatible = "nvidia,tegra20-vi";
-			reg = <0x54080000 0x00040000>;
+			reg = <0x54080000 0x00000800>;
 			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA20_CLK_VI>;
 			resets = <&tegra_car 20>;
@@ -72,6 +72,21 @@ vi@54080000 {
 			power-domains = <&pd_venc>;
 			operating-points-v2 = <&vi_dvfs_opp_table>;
 			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ranges = <0x0 0x54080000 0x4000>;
+
+			csi@800 {
+				compatible = "nvidia,tegra20-csi";
+				reg = <0x800 0x200>;
+				clocks = <&tegra_car TEGRA20_CLK_CSI>;
+				clock-names = "csi";
+				power-domains = <&pd_venc>;
+
+				status = "disabled";
+			};
 		};
 
 		/* DSI MIPI calibration logic is a part of VI/CSI */
diff --git a/arch/arm/boot/dts/nvidia/tegra30.dtsi b/arch/arm/boot/dts/nvidia/tegra30.dtsi
index d9223bd7cf3b..c3e9212d5edf 100644
--- a/arch/arm/boot/dts/nvidia/tegra30.dtsi
+++ b/arch/arm/boot/dts/nvidia/tegra30.dtsi
@@ -151,7 +151,7 @@ mpe@54040000 {
 
 		vi@54080000 {
 			compatible = "nvidia,tegra30-vi";
-			reg = <0x54080000 0x00040000>;
+			reg = <0x54080000 0x00000800>;
 			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_VI>;
 			resets = <&tegra_car 20>;
@@ -162,6 +162,23 @@ vi@54080000 {
 			iommus = <&mc TEGRA_SWGROUP_VI>;
 
 			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ranges = <0x0 0x54080000 0x4000>;
+
+			csi@800 {
+				compatible = "nvidia,tegra30-csi";
+				reg = <0x800 0x200>;
+				clocks = <&tegra_car TEGRA30_CLK_CSI>,
+					 <&tegra_car TEGRA30_CLK_CSIA_PAD>,
+					 <&tegra_car TEGRA30_CLK_CSIB_PAD>;
+				clock-names = "csi", "csia_pad", "csib_pad";
+				power-domains = <&pd_venc>;
+
+				status = "disabled";
+			};
 		};
 
 		/* DSI MIPI calibration logic is a part of VI/CSI */
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (17 preceding siblings ...)
  2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
  2025-09-02  2:38   ` Mikko Perttunen
  18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.

Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/csi.c     |  12 +
 drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
 drivers/staging/media/tegra-video/vi.h      |   2 +
 drivers/staging/media/tegra-video/video.c   |   2 +
 4 files changed, 553 insertions(+), 38 deletions(-)

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 2f9907a20db1..714ce52a793c 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 }
 
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+extern const struct tegra_csi_soc tegra20_csi_soc;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+extern const struct tegra_csi_soc tegra30_csi_soc;
+#endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
 extern const struct tegra_csi_soc tegra210_csi_soc;
 #endif
 
 static const struct of_device_id tegra_csi_of_id_table[] = {
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+	{ .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
+#endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
 	{ .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
 #endif
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index a06afe91d2de..e528ba280ae4 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -4,6 +4,9 @@
  *
  * Copyright (C) 2023 SKIDATA GmbH
  * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
+ *
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
  */
 
 /*
@@ -12,12 +15,16 @@
  */
 
 #include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk/tegra.h>
 #include <linux/delay.h>
 #include <linux/host1x.h>
+#include <linux/iopoll.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
 #include <linux/v4l2-mediabus.h>
 
+#include "csi.h"
 #include "vip.h"
 #include "vi.h"
 
@@ -42,6 +49,9 @@ enum {
 #define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT	BIT(8)
 #define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT		0
 
+#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n)	(0x0070 + (n) * 8)
+#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n)	(0x0074 + (n) * 8)
+
 #define TEGRA_VI_VI_INPUT_CONTROL			0x0088
 #define       VI_INPUT_FIELD_DETECT			BIT(27)
 #define       VI_INPUT_BT656				BIT(25)
@@ -87,6 +97,8 @@ enum {
 #define       VI_OUTPUT_OUTPUT_FORMAT_SFT		0
 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST	(3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
 #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR	(6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER	(7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER	(8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
 #define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT	(9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
 
 #define TEGRA_VI_VIP_H_ACTIVE				0x00a4
@@ -151,8 +163,106 @@ enum {
 #define TEGRA_VI_VI_RAISE				0x01ac
 #define       VI_VI_RAISE_ON_EDGE			BIT(0)
 
+#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n)		(0x01d8 + (n) * 8)
+#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n)		(0x01dc + (n) * 8)
+#define TEGRA_VI_CSI_PP_H_ACTIVE(n)			(0x01e8 + (n) * 8)
+#define TEGRA_VI_CSI_PP_V_ACTIVE(n)			(0x01ec + (n) * 8)
+
+/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
+#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL		0x0000
+#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL		0x0008
+#define TEGRA_CSI_INPUT_STREAM_CONTROL(n)		(0x0010 + (n) * 0x2c)
+#define       CSI_SKIP_PACKET_THRESHOLD(n)		(((n) & 0xff) << 16)
+#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n)		(0x0018 + (n) * 0x2c)
+#define       CSI_PP_PAD_FRAME_PAD0S			(0 << 28)
+#define       CSI_PP_PAD_FRAME_PAD1S			(1 << 28)
+#define       CSI_PP_PAD_FRAME_NOPAD			(2 << 28)
+#define       CSI_PP_HEADER_EC_ENABLE			BIT(27)
+#define       CSI_PP_PAD_SHORT_LINE_PAD0S		(0 << 24)
+#define       CSI_PP_PAD_SHORT_LINE_PAD1S		(1 << 24)
+#define       CSI_PP_PAD_SHORT_LINE_NOPAD		(2 << 24)
+#define       CSI_PP_EMBEDDED_DATA_EMBEDDED		BIT(20)
+#define       CSI_PP_OUTPUT_FORMAT_ARBITRARY		(0 << 16)
+#define       CSI_PP_OUTPUT_FORMAT_PIXEL		(1 << 16)
+#define       CSI_PP_OUTPUT_FORMAT_PIXEL_REP		(2 << 16)
+#define       CSI_PP_OUTPUT_FORMAT_STORE		(3 << 16)
+#define       CSI_PP_VIRTUAL_CHANNEL_ID(n)		(((n) - 1) << 14)
+#define       CSI_PP_DATA_TYPE(n)			((n) << 8)
+#define       CSI_PP_CRC_CHECK_ENABLE			BIT(7)
+#define       CSI_PP_WORD_COUNT_HEADER			BIT(6)
+#define       CSI_PP_DATA_IDENTIFIER_ENABLE		BIT(5)
+#define       CSI_PP_PACKET_HEADER_SENT			BIT(4)
+#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n)		(0x001c + (n) * 0x2c)
+#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n)		(0x0020 + (n) * 0x2c)
+#define TEGRA_CSI_PIXEL_STREAM_GAP(n)			(0x0024 + (n) * 0x2c)
+#define       CSI_PP_FRAME_MIN_GAP(n)			(((n) & 0xffff) << 16)
+#define       CSI_PP_LINE_MIN_GAP(n)			(((n) & 0xffff))
+#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n)		(0x0028 + (n) * 0x2c)
+#define       CSI_PP_START_MARKER_FRAME_MAX(n)		(((n) & 0xf) << 12)
+#define       CSI_PP_START_MARKER_FRAME_MIN(n)		(((n) & 0xf) << 8)
+#define       CSI_PP_VSYNC_START_MARKER			BIT(4)
+#define       CSI_PP_SINGLE_SHOT			BIT(2)
+#define       CSI_PP_NOP				0
+#define       CSI_PP_ENABLE				1
+#define       CSI_PP_DISABLE				2
+#define       CSI_PP_RST				3
+#define TEGRA_CSI_PHY_CIL_COMMAND			0x0068
+#define       CSI_A_PHY_CIL_NOP				0x0
+#define       CSI_A_PHY_CIL_ENABLE			0x1
+#define       CSI_A_PHY_CIL_DISABLE			0x2
+#define       CSI_A_PHY_CIL_ENABLE_MASK			0x3
+#define       CSI_B_PHY_CIL_NOP				(0x0 << 16)
+#define       CSI_B_PHY_CIL_ENABLE			(0x1 << 16)
+#define       CSI_B_PHY_CIL_DISABLE			(0x2 << 16)
+#define       CSI_B_PHY_CIL_ENABLE_MASK			(0x3 << 16)
+#define TEGRA_CSI_PHY_CIL_CONTROL0(n)			(0x006c + (n) * 4)
+#define       CSI_CONTINUOUS_CLOCK_MODE_ENABLE		BIT(5)
+#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS		0x0078
+#define TEGRA_CSI_CSI_CIL_STATUS			0x007c
+#define       CSI_MIPI_AUTO_CAL_DONE			BIT(15)
+#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK	0x0080
+#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK		0x0084
+#define TEGRA_CSI_CSI_READONLY_STATUS			0x0088
+#define TEGRA_CSI_ESCAPE_MODE_COMMAND			0x008c
+#define TEGRA_CSI_ESCAPE_MODE_DATA			0x0090
+#define TEGRA_CSI_CIL_PAD_CONFIG0(n)			(0x0094 + (n) * 8)
+#define TEGRA_CSI_CIL_PAD_CONFIG1(n)			(0x0098 + (n) * 8)
+#define TEGRA_CSI_CIL_PAD_CONFIG			0x00a4
+#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG			0x00a8
+#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG			0x00ac
+#define       CSI_CIL_MIPI_CAL_STARTCAL			BIT(31)
+#define       CSI_CIL_MIPI_CAL_OVERIDE_A		BIT(30)
+#define       CSI_CIL_MIPI_CAL_OVERIDE_B		BIT(30)
+#define       CSI_CIL_MIPI_CAL_NOISE_FLT(n)		(((n) & 0xf) << 26)
+#define       CSI_CIL_MIPI_CAL_PRESCALE(n)		(((n) & 0x3) << 24)
+#define       CSI_CIL_MIPI_CAL_SEL_A			BIT(21)
+#define       CSI_CIL_MIPI_CAL_SEL_B			BIT(21)
+#define       CSI_CIL_MIPI_CAL_HSPDOS(n)		(((n) & 0x1f) << 16)
+#define       CSI_CIL_MIPI_CAL_HSPUOS(n)		(((n) & 0x1f) << 8)
+#define       CSI_CIL_MIPI_CAL_TERMOS(n)		(((n) & 0x1f))
+#define TEGRA_CSI_CIL_MIPI_CAL_STATUS			0x00b0
+#define TEGRA_CSI_CLKEN_OVERRIDE			0x00b4
+#define TEGRA_CSI_DEBUG_CONTROL				0x00b8
+#define       CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED	BIT(0)
+#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0		BIT(4)
+#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1		BIT(5)
+#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2		BIT(6)
+#define       CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v)	((v) << (8 + 8 * (n)))
+#define TEGRA_CSI_DEBUG_COUNTER(n)			(0x00bc + (n) * 4)
+#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n)	(0x00c8 + (n) * 4)
+#define       CSI_PP_EXP_FRAME_HEIGHT(n)		(((n) & 0x1fff) << 16)
+#define       CSI_PP_MAX_CLOCKS(n)			(((n) & 0xfff) << 4)
+#define       CSI_PP_LINE_TIMEOUT_ENABLE		BIT(0)
+#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG			0x00d0
+#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0			0x00d4
+#define       CSI_PAD_DRIV_DN_REF(n)			(((n) & 0x7) << 16)
+#define       CSI_PAD_DRIV_UP_REF(n)			(((n) & 0x7) << 8)
+#define       CSI_PAD_TERM_REF(n)			(((n) & 0x7) << 0)
+#define TEGRA_CSI_CSI_CILA_STATUS			0x00d8
+#define TEGRA_CSI_CSI_CILB_STATUS			0x00dc
+
 /* --------------------------------------------------------------------------
- * VI
+ * Read and Write helpers
  */
 
 static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
@@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
 	writel(val, chan->vi->iomem + addr);
 }
 
+static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
+{
+	return readl(chan->vi->iomem + addr);
+}
+
+static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
+{
+	writel(val, csi_chan->csi->iomem + addr);
+}
+
+static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
+{
+	return readl(csi_chan->csi->iomem + addr);
+}
+
+/* --------------------------------------------------------------------------
+ * VI
+ */
+
 /*
  * Get the main input format (YUV/RGB...) and the YUV variant as values to
  * be written into registers for the current VI input mbus code.
@@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
 static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
 {
 	struct tegra_vi *vi = chan->vi;
-	struct host1x_syncpt *out_sp;
+	struct host1x_syncpt *out_sp, *fs_sp;
 
 	out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
 	if (!out_sp)
-		return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
+		return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
 
 	chan->mw_ack_sp[0] = out_sp;
 
+	fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
+	if (!fs_sp)
+		return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
+
+	chan->frame_start_sp[0] = fs_sp;
+
 	return 0;
 }
 
 static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
 {
 	host1x_syncpt_put(chan->mw_ack_sp[0]);
+	host1x_syncpt_put(chan->frame_start_sp[0]);
 }
 
 static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
@@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
 static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
 					 struct tegra_channel_buffer *buf)
 {
+	struct v4l2_subdev *csi_subdev = NULL;
+	struct tegra_csi_channel *csi_chan = NULL;
+	u32 port;
 	int err;
 
-	chan->next_out_sp_idx++;
+	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
+	if (csi_subdev) {
+		/* CSI subdevs are named after nodes, channel@0 or channel@1 */
+		if (!strncmp(csi_subdev->name, "channel", 7)) {
+			csi_chan = to_csi_chan(csi_subdev);
+			port = csi_chan->csi_port_nums[0] & 1;
+		}
+	}
 
 	tegra20_channel_vi_buffer_setup(chan, buf);
 
-	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
+	if (csi_chan) {
+		tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+				  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+				  CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
+
+		chan->next_fs_sp_idx++;
+		err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
+					 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
+		if (err) {
+			host1x_syncpt_incr(chan->frame_start_sp[0]);
+			if (err != -ERESTARTSYS)
+				dev_err_ratelimited(&chan->video.dev,
+						    "frame start syncpt timeout: %d\n", err);
+		}
+
+		tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+				  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+				  CSI_PP_DISABLE);
+	} else {
+		tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
+	}
 
-	/* Wait for syncpt counter to reach frame start event threshold */
+	chan->next_out_sp_idx++;
 	err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
 				 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
 	if (err) {
 		host1x_syncpt_incr(chan->mw_ack_sp[0]);
-		dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
-		release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
-		return err;
+		if (err != -ERESTARTSYS)
+			dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
 	}
 
-	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
-			 VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
+	if (!csi_chan)
+		tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
+				 VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
 
 	release_buffer(chan, buf, VB2_BUF_STATE_DONE);
 
-	return 0;
+	return err;
 }
 
 static int tegra20_chan_capture_kthread_start(void *data)
@@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
 			      data_type == TEGRA_IMAGE_DT_RAW10) ?
 			      OUT_2 : OUT_1;
-	int main_output_format;
-	int yuv_output_format;
-
-	tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
-
-	/*
-	 * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
-	 * for luminance, which is the default and means not to touch
-	 * anything.
-	 */
-	tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
-			 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
-			 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
-
-	/* Set up raise-on-edge, so we get an interrupt on end of frame. */
-	tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
-
-	tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
-			 (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
-			 (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
-			 yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
-			 main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
 
 	/* Set up frame size */
 	tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
@@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
 }
 
+static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
+{
+	struct tegra_csi *csi = csi_chan->csi;
+	void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
+	unsigned int port = csi_chan->csi_port_nums[0] & 1;
+	u32 value, pp, cil;
+	int ret;
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
+			  CSI_CIL_MIPI_CAL_HSPDOS(4) |
+			  CSI_CIL_MIPI_CAL_HSPUOS(3) |
+			  CSI_CIL_MIPI_CAL_TERMOS(0));
+	tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
+			  CSI_PAD_DRIV_DN_REF(5) |
+			  CSI_PAD_DRIV_UP_REF(7) |
+			  CSI_PAD_TERM_REF(0));
+
+	/* CSI B */
+	value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
+		CSI_CIL_MIPI_CAL_HSPUOS(0) |
+		CSI_CIL_MIPI_CAL_TERMOS(4);
+
+	if (port == PORT_B || csi_chan->numlanes == 4)
+		value |= CSI_CIL_MIPI_CAL_SEL_B;
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
+
+	/* CSI A */
+	value = CSI_CIL_MIPI_CAL_STARTCAL |
+		CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
+		CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
+		CSI_CIL_MIPI_CAL_HSPDOS(0) |
+		CSI_CIL_MIPI_CAL_HSPUOS(0) |
+		CSI_CIL_MIPI_CAL_TERMOS(4);
+
+	if (port == PORT_A)
+		value |= CSI_CIL_MIPI_CAL_SEL_A;
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
+
+	ret = readl_relaxed_poll_timeout(cil_status_reg, value,
+					 value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
+	if (ret < 0) {
+		dev_warn(csi->dev, "MIPI calibration timeout!\n");
+		goto exit;
+	}
+
+	/* clear status */
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
+	ret = readl_relaxed_poll_timeout(cil_status_reg, value,
+					 !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
+	if (ret < 0) {
+		dev_warn(csi->dev, "MIPI calibration status timeout!\n");
+		goto exit;
+	}
+
+	pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+	cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
+	if (pp | cil) {
+		dev_warn(csi->dev, "Calibration status not been cleared!\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
+
+	/* un-select to avoid interference with DSI */
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
+			  CSI_CIL_MIPI_CAL_HSPDOS(0) |
+			  CSI_CIL_MIPI_CAL_HSPUOS(0) |
+			  CSI_CIL_MIPI_CAL_TERMOS(4));
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
+			  CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
+			  CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
+			  CSI_CIL_MIPI_CAL_HSPDOS(0) |
+			  CSI_CIL_MIPI_CAL_HSPUOS(0) |
+			  CSI_CIL_MIPI_CAL_TERMOS(4));
+
+	return ret;
+}
+
 static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
 {
 	struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
 	struct media_pipeline *pipe = &chan->video.pipe;
+	struct v4l2_subdev *csi_subdev, *src_subdev;
+	struct tegra_csi_channel *csi_chan = NULL;
 	int err;
 
+	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
+	if (csi_subdev) {
+		if (!strncmp(csi_subdev->name, "channel", 7))
+			csi_chan = to_csi_chan(csi_subdev);
+	}
+
+	chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
 	chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
 
 	err = video_device_pipeline_start(&chan->video, pipe);
 	if (err)
 		goto error_pipeline_start;
 
-	tegra20_camera_capture_setup(chan);
+	/*
+	 * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
+	 * for luminance, which is the default and means not to touch
+	 * anything.
+	 */
+	tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
+			 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
+			 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
+
+	/* Set up raise-on-edge, so we get an interrupt on end of frame. */
+	tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
 
 	err = tegra_channel_set_stream(chan, true);
 	if (err)
 		goto error_set_stream;
 
+	tegra20_camera_capture_setup(chan);
+
+	if (csi_chan) {
+		/*
+		 * TRM has incorrectly documented to wait for done status from
+		 * calibration logic after CSI interface power on.
+		 * As per the design, calibration results are latched and applied
+		 * to the pads only when the link is in LP11 state which will happen
+		 * during the sensor stream-on.
+		 * CSI subdev stream-on triggers start of MIPI pads calibration.
+		 * Wait for calibration to finish here after sensor subdev stream-on.
+		 */
+		src_subdev = tegra_channel_get_remote_source_subdev(chan);
+		if (!src_subdev->s_stream_enabled) {
+			err = v4l2_subdev_call(src_subdev, video, s_stream, true);
+			if (err < 0 && err != -ENOIOCTLCMD)
+				goto error_set_stream;
+		}
+
+		tegra20_csi_pad_calibration(csi_chan);
+	}
+
 	chan->sequence = 0;
 
 	chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
@@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
 static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
 {
 	struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
+	struct v4l2_subdev *src_subdev;
 
 	if (chan->kthread_start_capture) {
 		kthread_stop(chan->kthread_start_capture);
 		chan->kthread_start_capture = NULL;
 	}
 
+	src_subdev = tegra_channel_get_remote_source_subdev(chan);
+	if (src_subdev->s_stream_enabled)
+		v4l2_subdev_call(src_subdev, video, s_stream, false);
+
 	tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
 	tegra_channel_set_stream(chan, false);
 	video_device_pipeline_stop(&chan->video);
@@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 	.default_video_format = &tegra20_video_formats[0],
 	.ops = &tegra20_vi_ops,
 	.hw_revision = 1,
-	.vi_max_channels = 1, /* parallel input (VIP) */
+	.vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
 	.vi_max_clk_hz = 450000000,
 	.has_h_v_flip = true,
 };
 
+/* --------------------------------------------------------------------------
+ * CSI
+ */
+static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
+{
+	tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
+			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
+			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
+			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
+}
+
+static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
+					    u8 portno)
+{
+	struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
+	int width  = vi_chan->format.width;
+	int height = vi_chan->format.height;
+	u32 data_type = vi_chan->fmtinfo->img_dt;
+	u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
+	int output_channel = OUT_1;
+
+	unsigned int main_output_format, yuv_output_format;
+	unsigned int port = portno & 1;
+	u32 value;
+
+	tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
+
+	switch (data_type) {
+	case TEGRA_IMAGE_DT_RAW8:
+	case TEGRA_IMAGE_DT_RAW10:
+		output_channel = OUT_2;
+		if (port == PORT_A)
+			main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
+		else
+			main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
+		break;
+	}
+
+	tegra20_csi_capture_clean(csi_chan);
+
+	/* CSI port cleanup */
+	tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
+	tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
+	tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
+			  CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
+			  CSI_PP_EXP_FRAME_HEIGHT(height) |
+			  CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
+			  CSI_PP_LINE_TIMEOUT_ENABLE);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
+			  CSI_PP_OUTPUT_FORMAT_PIXEL |
+			  CSI_PP_DATA_TYPE(data_type) |
+			  CSI_PP_CRC_CHECK_ENABLE |
+			  CSI_PP_WORD_COUNT_HEADER |
+			  CSI_PP_DATA_IDENTIFIER_ENABLE |
+			  CSI_PP_PACKET_HEADER_SENT |
+			  port);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
+			  CSI_SKIP_PACKET_THRESHOLD(0x3f) |
+			  (csi_chan->numlanes - 1));
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
+			  CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
+			  0x5); /* Clock settle time */
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
+			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
+			 host1x_syncpt_id(vi_chan->frame_start_sp[0])
+			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
+			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
+			 host1x_syncpt_id(vi_chan->mw_ack_sp[0])
+			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
+
+	value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
+		CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+			  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+			  CSI_PP_DISABLE);
+
+	tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
+			 (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
+			 (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
+			 yuv_output_format | main_output_format);
+
+	return 0;
+};
+
+static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
+{
+	struct tegra_csi *csi = csi_chan->csi;
+	unsigned int port = portno & 1;
+	u32 value;
+
+	value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+	dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
+
+	value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
+	dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
+	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
+
+	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+			  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+			  CSI_PP_DISABLE);
+
+	if (csi_chan->numlanes == 4) {
+		tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
+				  CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
+	} else {
+		value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
+			CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
+		tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
+	}
+}
+
+static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
+{
+	u8 *portnos = csi_chan->csi_port_nums;
+	int ret, i;
+
+	for (i = 0; i < csi_chan->numgangports; i++) {
+		ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
+		if (ret)
+			goto stream_start_fail;
+	}
+
+	return 0;
+
+stream_start_fail:
+	for (i = i - 1; i >= 0; i--)
+		tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
+
+	return ret;
+}
+
+static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
+{
+	u8 *portnos = csi_chan->csi_port_nums;
+	int i;
+
+	for (i = 0; i < csi_chan->numgangports; i++)
+		tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
+}
+
+/* Tegra20 CSI operations */
+static const struct tegra_csi_ops tegra20_csi_ops = {
+	.csi_start_streaming = tegra20_csi_start_streaming,
+	.csi_stop_streaming = tegra20_csi_stop_streaming,
+};
+
+static const char * const tegra20_csi_clks[] = {
+	"csi",
+};
+
+/* Tegra20 CSI SoC data */
+const struct tegra_csi_soc tegra20_csi_soc = {
+	.ops = &tegra20_csi_ops,
+	.csi_max_channels = 2, /* CSI-A and CSI-B */
+	.clk_names = tegra20_csi_clks,
+	.num_clks = ARRAY_SIZE(tegra20_csi_clks),
+	.has_mipi_calibration = false,
+};
+
+static const char * const tegra30_csi_clks[] = {
+	"csi",
+	"csia_pad",
+	"csib_pad",
+};
+
+/* Tegra30 CSI SoC data */
+const struct tegra_csi_soc tegra30_csi_soc = {
+	.ops = &tegra20_csi_ops,
+	.csi_max_channels = 2, /* CSI-A and CSI-B */
+	.clk_names = tegra30_csi_clks,
+	.num_clks = ARRAY_SIZE(tegra30_csi_clks),
+	.has_mipi_calibration = false,
+};
+
 /* --------------------------------------------------------------------------
  * VIP
  */
@@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 			      data_type == TEGRA_IMAGE_DT_RAW10) ?
 			      OUT_2 : OUT_1;
 
-	unsigned int main_input_format;
-	unsigned int yuv_input_format;
+	unsigned int main_input_format, yuv_input_format;
+	unsigned int main_output_format, yuv_output_format;
 
 	tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
+	tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
 
 	tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
 
@@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 
 	tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
 
+	tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
+			 (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
+			 (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
+			  yuv_output_format | main_output_format);
+
 	return 0;
 }
 
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index cac0c0d0e225..c02517c9e09b 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -127,6 +127,7 @@ struct tegra_vi {
  *		frame through host1x syncpoint counters (On Tegra20 used for the
  *              OUT_1 syncpt)
  * @sp_incr_lock: protects cpu syncpoint increment.
+ * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
  * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
  *
  * @kthread_start_capture: kthread to start capture of single frame when
@@ -191,6 +192,7 @@ struct tegra_vi_channel {
 	/* protects the cpu syncpoint increment */
 	spinlock_t sp_incr_lock[GANG_PORTS_MAX];
 	u32 next_out_sp_idx;
+	u32 next_fs_sp_idx;
 
 	struct task_struct *kthread_start_capture;
 	wait_queue_head_t start_wait;
diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
index a25885f93cd7..8fa660431eb0 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
 
 static const struct of_device_id host1x_video_subdevs[] = {
 #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+	{ .compatible = "nvidia,tegra20-csi", },
 	{ .compatible = "nvidia,tegra20-vip", },
 	{ .compatible = "nvidia,tegra20-vi", },
 #endif
 #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-csi", },
 	{ .compatible = "nvidia,tegra30-vip", },
 	{ .compatible = "nvidia,tegra30-vi", },
 #endif
-- 
2.48.1


^ permalink raw reply related	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
  2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
@ 2025-08-19 20:27   ` Rob Herring
  2025-08-20  5:36     ` Svyatoslav Ryhel
  2025-08-29  6:42     ` Svyatoslav Ryhel
  0 siblings, 2 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-19 20:27 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.

That's not what the compatible schema says. 'exactly the same' implies a 
fallback to whatever it is exactly the same as.

> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml    | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> index 14294edb8d8c..39e9b3297dbd 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> @@ -13,6 +13,7 @@ properties:
>    compatible:
>      enum:
>        - nvidia,tegra20-vip
> +      - nvidia,tegra30-vip
>  
>    ports:
>      $ref: /schemas/graph.yaml#/properties/ports
> -- 
> 2.48.1
> 

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-08-19 20:30   ` Rob Herring
  2025-08-20  5:39     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2025-08-19 20:30 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> Document CSI hw block found in Tegra20 and Tegra30 SoC.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../display/tegra/nvidia,tegra210-csi.yaml    | 78 +++++++++++++++----
>  1 file changed, 63 insertions(+), 15 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> index fa07a40d1004..a5669447a33b 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> @@ -16,30 +16,78 @@ properties:
>  
>    compatible:
>      enum:
> +      - nvidia,tegra20-csi
> +      - nvidia,tegra30-csi
>        - nvidia,tegra210-csi
>  
>    reg:
>      maxItems: 1
>  
> -  clocks:
> -    items:
> -      - description: module clock
> -      - description: A/B lanes clock
> -      - description: C/D lanes clock
> -      - description: E lane clock
> -      - description: test pattern generator clock
> -
> -  clock-names:
> -    items:
> -      - const: csi
> -      - const: cilab
> -      - const: cilcd
> -      - const: cile
> -      - const: csi_tpg
> +  clocks: true
> +  clock-names: true
>  
>    power-domains:
>      maxItems: 1
>  
> +allOf:
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - nvidia,tegra20-csi
> +    then:
> +      properties:
> +        clocks:
> +          items:
> +            - description: module clock
> +
> +        clock-names:
> +          items:
> +            - const: csi
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - nvidia,tegra30-csi
> +    then:
> +      properties:
> +        clocks:
> +          items:
> +            - description: module clock
> +            - description: PAD A clock
> +            - description: PAD B clock
> +
> +        clock-names:
> +          items:
> +            - const: csi
> +            - const: csia_pad
> +            - const: csib_pad
> +  - if:
> +      properties:
> +        compatible:
> +          contains:
> +            enum:
> +              - nvidia,tegra210-csi
> +    then:
> +      properties:
> +        clocks:
> +          items:
> +            - description: module clock
> +            - description: A/B lanes clock
> +            - description: C/D lanes clock
> +            - description: E lane clock
> +            - description: test pattern generator clock
> +
> +        clock-names:
> +          items:
> +            - const: csi
> +            - const: cilab
> +            - const: cilcd
> +            - const: cile
> +            - const: csi_tpg
> +

This is longer that what's the same. I think this should be a separate 
schema doc.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
  2025-08-19 20:27   ` Rob Herring
@ 2025-08-20  5:36     ` Svyatoslav Ryhel
  2025-08-29  6:42     ` Svyatoslav Ryhel
  1 sibling, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-20  5:36 UTC (permalink / raw)
  To: Rob Herring
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 19 серп. 2025 р. о 23:27 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> > Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
>
> That's not what the compatible schema says. 'exactly the same' implies a
> fallback to whatever it is exactly the same as.
>

I will reword commit message. Thank you.

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-08-19 20:30   ` Rob Herring
@ 2025-08-20  5:39     ` Svyatoslav Ryhel
  2025-08-22 14:06       ` Rob Herring
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-20  5:39 UTC (permalink / raw)
  To: Rob Herring
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 19 серп. 2025 р. о 23:30 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> > Document CSI hw block found in Tegra20 and Tegra30 SoC.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  .../display/tegra/nvidia,tegra210-csi.yaml    | 78 +++++++++++++++----
> >  1 file changed, 63 insertions(+), 15 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > index fa07a40d1004..a5669447a33b 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > @@ -16,30 +16,78 @@ properties:
> >
> >    compatible:
> >      enum:
> > +      - nvidia,tegra20-csi
> > +      - nvidia,tegra30-csi
> >        - nvidia,tegra210-csi
> >
> >    reg:
> >      maxItems: 1
> >
> > -  clocks:
> > -    items:
> > -      - description: module clock
> > -      - description: A/B lanes clock
> > -      - description: C/D lanes clock
> > -      - description: E lane clock
> > -      - description: test pattern generator clock
> > -
> > -  clock-names:
> > -    items:
> > -      - const: csi
> > -      - const: cilab
> > -      - const: cilcd
> > -      - const: cile
> > -      - const: csi_tpg
> > +  clocks: true
> > +  clock-names: true
> >
> >    power-domains:
> >      maxItems: 1
> >
> > +allOf:
> > +  - if:
> > +      properties:
> > +        compatible:
> > +          contains:
> > +            enum:
> > +              - nvidia,tegra20-csi
> > +    then:
> > +      properties:
> > +        clocks:
> > +          items:
> > +            - description: module clock
> > +
> > +        clock-names:
> > +          items:
> > +            - const: csi
> > +  - if:
> > +      properties:
> > +        compatible:
> > +          contains:
> > +            enum:
> > +              - nvidia,tegra30-csi
> > +    then:
> > +      properties:
> > +        clocks:
> > +          items:
> > +            - description: module clock
> > +            - description: PAD A clock
> > +            - description: PAD B clock
> > +
> > +        clock-names:
> > +          items:
> > +            - const: csi
> > +            - const: csia_pad
> > +            - const: csib_pad
> > +  - if:
> > +      properties:
> > +        compatible:
> > +          contains:
> > +            enum:
> > +              - nvidia,tegra210-csi
> > +    then:
> > +      properties:
> > +        clocks:
> > +          items:
> > +            - description: module clock
> > +            - description: A/B lanes clock
> > +            - description: C/D lanes clock
> > +            - description: E lane clock
> > +            - description: test pattern generator clock
> > +
> > +        clock-names:
> > +          items:
> > +            - const: csi
> > +            - const: cilab
> > +            - const: cilcd
> > +            - const: cile
> > +            - const: csi_tpg
> > +
>
> This is longer that what's the same. I think this should be a separate
> schema doc.
>

CSI hw block configuration is similar between generations, the main
difference is the amount of clocks routed. Not sure if it is worth it
to create duplicates with sole difference in number of clocks used.

> Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
@ 2025-08-22 13:59   ` Rob Herring
  2025-08-27  4:19   ` Mikko Perttunen
  1 sibling, 0 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-22 13:59 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Tue, Aug 19, 2025 at 03:16:14PM +0300, Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> Add ids for these clocks.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  include/dt-bindings/clock/tegra30-car.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
> index f193663e6f28..14b83e90a0fc 100644
> --- a/include/dt-bindings/clock/tegra30-car.h
> +++ b/include/dt-bindings/clock/tegra30-car.h
> @@ -271,6 +271,8 @@
>  #define TEGRA30_CLK_AUDIO3_MUX 306
>  #define TEGRA30_CLK_AUDIO4_MUX 307
>  #define TEGRA30_CLK_SPDIF_MUX 308
> -#define TEGRA30_CLK_CLK_MAX 309
> +#define TEGRA30_CLK_CSIA_PAD 309
> +#define TEGRA30_CLK_CSIB_PAD 310
> +#define TEGRA30_CLK_CLK_MAX 311

Please drop the MAX. This header is ABI and if a define can change, then 
it's not ABI.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-08-20  5:39     ` Svyatoslav Ryhel
@ 2025-08-22 14:06       ` Rob Herring
  0 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-22 14:06 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Wed, Aug 20, 2025 at 08:39:36AM +0300, Svyatoslav Ryhel wrote:
> вт, 19 серп. 2025 р. о 23:30 Rob Herring <robh@kernel.org> пише:
> >
> > On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> > > Document CSI hw block found in Tegra20 and Tegra30 SoC.
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > >  .../display/tegra/nvidia,tegra210-csi.yaml    | 78 +++++++++++++++----
> > >  1 file changed, 63 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > index fa07a40d1004..a5669447a33b 100644
> > > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > @@ -16,30 +16,78 @@ properties:
> > >
> > >    compatible:
> > >      enum:
> > > +      - nvidia,tegra20-csi
> > > +      - nvidia,tegra30-csi
> > >        - nvidia,tegra210-csi
> > >
> > >    reg:
> > >      maxItems: 1
> > >
> > > -  clocks:
> > > -    items:
> > > -      - description: module clock
> > > -      - description: A/B lanes clock
> > > -      - description: C/D lanes clock
> > > -      - description: E lane clock
> > > -      - description: test pattern generator clock
> > > -
> > > -  clock-names:
> > > -    items:
> > > -      - const: csi
> > > -      - const: cilab
> > > -      - const: cilcd
> > > -      - const: cile
> > > -      - const: csi_tpg
> > > +  clocks: true
> > > +  clock-names: true
> > >
> > >    power-domains:
> > >      maxItems: 1
> > >
> > > +allOf:
> > > +  - if:
> > > +      properties:
> > > +        compatible:
> > > +          contains:
> > > +            enum:
> > > +              - nvidia,tegra20-csi
> > > +    then:
> > > +      properties:
> > > +        clocks:
> > > +          items:
> > > +            - description: module clock
> > > +
> > > +        clock-names:
> > > +          items:
> > > +            - const: csi
> > > +  - if:
> > > +      properties:
> > > +        compatible:
> > > +          contains:
> > > +            enum:
> > > +              - nvidia,tegra30-csi
> > > +    then:
> > > +      properties:
> > > +        clocks:
> > > +          items:
> > > +            - description: module clock
> > > +            - description: PAD A clock
> > > +            - description: PAD B clock
> > > +
> > > +        clock-names:
> > > +          items:
> > > +            - const: csi
> > > +            - const: csia_pad
> > > +            - const: csib_pad
> > > +  - if:
> > > +      properties:
> > > +        compatible:
> > > +          contains:
> > > +            enum:
> > > +              - nvidia,tegra210-csi
> > > +    then:
> > > +      properties:
> > > +        clocks:
> > > +          items:
> > > +            - description: module clock
> > > +            - description: A/B lanes clock
> > > +            - description: C/D lanes clock
> > > +            - description: E lane clock
> > > +            - description: test pattern generator clock
> > > +
> > > +        clock-names:
> > > +          items:
> > > +            - const: csi
> > > +            - const: cilab
> > > +            - const: cilcd
> > > +            - const: cile
> > > +            - const: csi_tpg
> > > +
> >
> > This is longer that what's the same. I think this should be a separate
> > schema doc.
> >
> 
> CSI hw block configuration is similar between generations, the main
> difference is the amount of clocks routed. Not sure if it is worth it
> to create duplicates with sole difference in number of clocks used.

If the clock names were at least the same I might agree, but the only 
common one is 'csi'. How similar the h/w is doesn't matter, how similar 
the binding is is what matters.

Rob

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
@ 2025-08-27  4:09   ` Mikko Perttunen
  2025-08-27  4:32     ` Svyatoslav
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27  4:09 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> CSUS clock is required to be enabled on camera device configuration or
> else camera module refuses to initiate properly.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra20.c | 1 +
>  drivers/clk/tegra/clk-tegra30.c | 1 +
>  2 files changed, 2 insertions(+)
> 
> diff --git a/drivers/clk/tegra/clk-tegra20.c
> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> --- a/drivers/clk/tegra/clk-tegra20.c
> +++ b/drivers/clk/tegra/clk-tegra20.c
> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
>  	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
>  	{ TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
>  	{ TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> +	{ TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
>  	/* must be the last entry */
>  	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
>  };
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
>  	{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
>  	{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
>  	{ TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> +	{ TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
>  	/* must be the last entry */
>  	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
>  };

I looked into what this clock does and it seems to be a gate for the CSUS pin, 
which provides an output clock for camera sensors (VI MCLK). Default source 
seems to be PLLC_OUT1. It would be good to note that on the commit message, as 
I can't find any documentation about the CSUS clock elsewhere.

What is the 6MHz rate based on?

Since this seems to be a clock consumed by the sensor, it seems to me that 
rather than making it always on, we could point to it in the sensor's device 
tree entry.

Cheers,
Mikko




^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
  2025-08-22 13:59   ` Rob Herring
@ 2025-08-27  4:19   ` Mikko Perttunen
  2025-08-27  4:28     ` Svyatoslav
  1 sibling, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27  4:19 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> Add ids for these clocks.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  include/dt-bindings/clock/tegra30-car.h | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/include/dt-bindings/clock/tegra30-car.h
> b/include/dt-bindings/clock/tegra30-car.h index f193663e6f28..14b83e90a0fc
> 100644
> --- a/include/dt-bindings/clock/tegra30-car.h
> +++ b/include/dt-bindings/clock/tegra30-car.h
> @@ -271,6 +271,8 @@
>  #define TEGRA30_CLK_AUDIO3_MUX 306
>  #define TEGRA30_CLK_AUDIO4_MUX 307
>  #define TEGRA30_CLK_SPDIF_MUX 308
> -#define TEGRA30_CLK_CLK_MAX 309
> +#define TEGRA30_CLK_CSIA_PAD 309
> +#define TEGRA30_CLK_CSIB_PAD 310
> +#define TEGRA30_CLK_CLK_MAX 311
> 
>  #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */

The commit message refers to tegra20, but contents are tegra30.

Regarding the CLK_MAX define, I agree that it would be better to get rid of 
it. Perhaps you can check if it would be reasonable to calculate it 
dynamically in the driver, but a define and sanity check in the driver would 
work too, I think.

Cheers,
Mikko



^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
  2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
@ 2025-08-27  4:26   ` Mikko Perttunen
  2025-08-29  0:44   ` Mikko Perttunen
  1 sibling, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27  4:26 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
> for correct work of CSI block.

'pad' is just an english word, so please write it in lowercase. Same applies 
to the previous patch.

> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 70e85e2949e0..f033eb1ac26a 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -153,6 +153,7 @@ static unsigned long input_freq;
> 
>  static DEFINE_SPINLOCK(cml_lock);
>  static DEFINE_SPINLOCK(pll_d_lock);
> +static DEFINE_SPINLOCK(pll_d2_lock);
> 
>  #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,	\
>  			    _clk_num, _gate_flags, _clk_id)	\
> @@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
> 
>  	/* PLLD2 */
>  	clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 
0,
> -			    &pll_d2_params, NULL);
> +			    &pll_d2_params, &pll_d2_lock);

Please mention adding this lock in the commit message.

>  	clks[TEGRA30_CLK_PLL_D2] = clk;
> 
>  	/* PLLD2_OUT0 */
> @@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
>  				    0, 48, periph_clk_enb_refcnt);
>  	clks[TEGRA30_CLK_DSIA] = clk;
> 
> +	/* csia_pad */
> +	clk = clk_register_gate(NULL, "csia_pad", "pll_d", 
CLK_SET_RATE_PARENT,
> +				clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
> +	clk_register_clkdev(clk, "csia_pad", NULL);
> +	clks[TEGRA30_CLK_CSIA_PAD] = clk;
> +
> +	/* csib_pad */
> +	clk = clk_register_gate(NULL, "csib_pad", "pll_d2", 
CLK_SET_RATE_PARENT,
> +				clk_base + PLLD2_BASE, 26, 0, 
&pll_d2_lock);
> +	clk_register_clkdev(clk, "csib_pad", NULL);
> +	clks[TEGRA30_CLK_CSIB_PAD] = clk;
> +
>  	/* pcie */
>  	clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
>  				    70, periph_clk_enb_refcnt);





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-27  4:19   ` Mikko Perttunen
@ 2025-08-27  4:28     ` Svyatoslav
  2025-08-27 10:27       ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27  4:28 UTC (permalink / raw)
  To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging



27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
>> Add ids for these clocks.
>> 
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>>  include/dt-bindings/clock/tegra30-car.h | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>> 
>> diff --git a/include/dt-bindings/clock/tegra30-car.h
>> b/include/dt-bindings/clock/tegra30-car.h index f193663e6f28..14b83e90a0fc
>> 100644
>> --- a/include/dt-bindings/clock/tegra30-car.h
>> +++ b/include/dt-bindings/clock/tegra30-car.h
>> @@ -271,6 +271,8 @@
>>  #define TEGRA30_CLK_AUDIO3_MUX 306
>>  #define TEGRA30_CLK_AUDIO4_MUX 307
>>  #define TEGRA30_CLK_SPDIF_MUX 308
>> -#define TEGRA30_CLK_CLK_MAX 309
>> +#define TEGRA30_CLK_CSIA_PAD 309
>> +#define TEGRA30_CLK_CSIB_PAD 310
>> +#define TEGRA30_CLK_CLK_MAX 311
>> 
>>  #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
>
>The commit message refers to tegra20, but contents are tegra30.
>

My, bad, it should be tegra30

>Regarding the CLK_MAX define, I agree that it would be better to get rid of 
>it. Perhaps you can check if it would be reasonable to calculate it 
>dynamically in the driver, but a define and sanity check in the driver would 
>work too, I think.
>

It is not unreasonable, but moving this elsewhere may cause issues with adding new clocks. Addind new clocks would require updating not only header but also a place where max clocks are moved to and ai am not sure how can I dinamically calculate amount of clocks in the driver without updating both header and driver with each new clock added. Maybe you can propose a method?

>Cheers,
>Mikko
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-08-27  4:29   ` Mikko Perttunen
  2025-08-27  4:47     ` Svyatoslav
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27  4:29 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
> Tegra30.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/Makefile | 1 +
>  drivers/staging/media/tegra-video/vi.c     | 3 +++
>  drivers/staging/media/tegra-video/vi.h     | 2 +-
>  drivers/staging/media/tegra-video/video.c  | 4 ++++
>  drivers/staging/media/tegra-video/vip.c    | 5 ++++-
>  5 files changed, 13 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/Makefile
> b/drivers/staging/media/tegra-video/Makefile index
> 6c7552e05109..96380b5dbd8b 100644
> --- a/drivers/staging/media/tegra-video/Makefile
> +++ b/drivers/staging/media/tegra-video/Makefile
> @@ -6,5 +6,6 @@ tegra-video-objs := \
>  		csi.o
> 
>  tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC)  += tegra20.o
> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC)  += tegra20.o
>  tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
>  obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
> diff --git a/drivers/staging/media/tegra-video/vi.c
> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
> 100644
> --- a/drivers/staging/media/tegra-video/vi.c
> +++ b/drivers/staging/media/tegra-video/vi.c
> @@ -1959,6 +1959,9 @@ static const struct of_device_id
> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>  	{ .compatible = "nvidia,tegra20-vi",  .data = &tegra20_vi_soc },
>  #endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-vi",  .data = &tegra20_vi_soc },
> +#endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>  	{ .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
>  #endif
> diff --git a/drivers/staging/media/tegra-video/vi.h
> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
> 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -296,7 +296,7 @@ struct tegra_video_format {
>  	u32 fourcc;
>  };
> 
> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>  extern const struct tegra_vi_soc tegra20_vi_soc;
>  #endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> diff --git a/drivers/staging/media/tegra-video/video.c
> b/drivers/staging/media/tegra-video/video.c index
> 074ad0dc56ca..a25885f93cd7 100644
> --- a/drivers/staging/media/tegra-video/video.c
> +++ b/drivers/staging/media/tegra-video/video.c
> @@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[]
> = { { .compatible = "nvidia,tegra20-vip", },
>  	{ .compatible = "nvidia,tegra20-vi", },
>  #endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-vip", },
> +	{ .compatible = "nvidia,tegra30-vi", },
> +#endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>  	{ .compatible = "nvidia,tegra210-csi", },
>  	{ .compatible = "nvidia,tegra210-vi", },
> diff --git a/drivers/staging/media/tegra-video/vip.c
> b/drivers/staging/media/tegra-video/vip.c index 5ec717f3afd5..00e08a9971d5
> 100644
> --- a/drivers/staging/media/tegra-video/vip.c
> +++ b/drivers/staging/media/tegra-video/vip.c
> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
> *pdev) pm_runtime_disable(&pdev->dev);
>  }
> 
> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>  extern const struct tegra_vip_soc tegra20_vip_soc;
>  #endif
> 
>  static const struct of_device_id tegra_vip_of_id_table[] = {
>  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>  	{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
>  #endif
>  	{ }
>  };

If tegra30-vip is compatible with tegra20-vip, we don't need to add the 
compatible string into the driver. Just mark it as 'compatible = 
"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob 
alluded, have this compat string pair as an option in the device tree schema).

Cheers,
Mikko




^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-27  4:09   ` Mikko Perttunen
@ 2025-08-27  4:32     ` Svyatoslav
  2025-08-27 10:36       ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27  4:32 UTC (permalink / raw)
  To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging



27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> CSUS clock is required to be enabled on camera device configuration or
>> else camera module refuses to initiate properly.
>> 
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>>  drivers/clk/tegra/clk-tegra20.c | 1 +
>>  drivers/clk/tegra/clk-tegra30.c | 1 +
>>  2 files changed, 2 insertions(+)
>> 
>> diff --git a/drivers/clk/tegra/clk-tegra20.c
>> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
>> --- a/drivers/clk/tegra/clk-tegra20.c
>> +++ b/drivers/clk/tegra/clk-tegra20.c
>> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
>>  	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
>>  	{ TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
>>  	{ TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
>> +	{ TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
>>  	/* must be the last entry */
>>  	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
>>  };
>> diff --git a/drivers/clk/tegra/clk-tegra30.c
>> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
>> --- a/drivers/clk/tegra/clk-tegra30.c
>> +++ b/drivers/clk/tegra/clk-tegra30.c
>> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
>>  	{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
>>  	{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
>>  	{ TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
>> +	{ TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
>>  	/* must be the last entry */
>>  	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
>>  };
>
>I looked into what this clock does and it seems to be a gate for the CSUS pin, 
>which provides an output clock for camera sensors (VI MCLK). Default source 
>seems to be PLLC_OUT1. It would be good to note that on the commit message, as 
>I can't find any documentation about the CSUS clock elsewhere.
>
>What is the 6MHz rate based on?
>

6mhz is the statistic value which I was not able to alter while testing. I have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.

>Since this seems to be a clock consumed by the sensor, it seems to me that 
>rather than making it always on, we could point to it in the sensor's device 
>tree entry.
>

Sensor device tree uses vi_sensor as clocks source and sensor drivers don't support multiple linked clocks.

>Cheers,
>Mikko
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-08-27  4:29   ` Mikko Perttunen
@ 2025-08-27  4:47     ` Svyatoslav
  2025-08-29  0:56       ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27  4:47 UTC (permalink / raw)
  To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging



27 серпня 2025 р. 07:29:40 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
>> Tegra30.
>> 
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>>  drivers/staging/media/tegra-video/Makefile | 1 +
>>  drivers/staging/media/tegra-video/vi.c     | 3 +++
>>  drivers/staging/media/tegra-video/vi.h     | 2 +-
>>  drivers/staging/media/tegra-video/video.c  | 4 ++++
>>  drivers/staging/media/tegra-video/vip.c    | 5 ++++-
>>  5 files changed, 13 insertions(+), 2 deletions(-)
>> 
>> diff --git a/drivers/staging/media/tegra-video/Makefile
>> b/drivers/staging/media/tegra-video/Makefile index
>> 6c7552e05109..96380b5dbd8b 100644
>> --- a/drivers/staging/media/tegra-video/Makefile
>> +++ b/drivers/staging/media/tegra-video/Makefile
>> @@ -6,5 +6,6 @@ tegra-video-objs := \
>>  		csi.o
>> 
>>  tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC)  += tegra20.o
>> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC)  += tegra20.o
>>  tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
>>  obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
>> diff --git a/drivers/staging/media/tegra-video/vi.c
>> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
>> 100644
>> --- a/drivers/staging/media/tegra-video/vi.c
>> +++ b/drivers/staging/media/tegra-video/vi.c
>> @@ -1959,6 +1959,9 @@ static const struct of_device_id
>> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>>  	{ .compatible = "nvidia,tegra20-vi",  .data = &tegra20_vi_soc },
>>  #endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> +	{ .compatible = "nvidia,tegra30-vi",  .data = &tegra20_vi_soc },
>> +#endif
>>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>>  	{ .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
>>  #endif
>> diff --git a/drivers/staging/media/tegra-video/vi.h
>> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
>> 100644
>> --- a/drivers/staging/media/tegra-video/vi.h
>> +++ b/drivers/staging/media/tegra-video/vi.h
>> @@ -296,7 +296,7 @@ struct tegra_video_format {
>>  	u32 fourcc;
>>  };
>> 
>> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>>  extern const struct tegra_vi_soc tegra20_vi_soc;
>>  #endif
>>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>> diff --git a/drivers/staging/media/tegra-video/video.c
>> b/drivers/staging/media/tegra-video/video.c index
>> 074ad0dc56ca..a25885f93cd7 100644
>> --- a/drivers/staging/media/tegra-video/video.c
>> +++ b/drivers/staging/media/tegra-video/video.c
>> @@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[]
>> = { { .compatible = "nvidia,tegra20-vip", },
>>  	{ .compatible = "nvidia,tegra20-vi", },
>>  #endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> +	{ .compatible = "nvidia,tegra30-vip", },
>> +	{ .compatible = "nvidia,tegra30-vi", },
>> +#endif
>>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>>  	{ .compatible = "nvidia,tegra210-csi", },
>>  	{ .compatible = "nvidia,tegra210-vi", },
>> diff --git a/drivers/staging/media/tegra-video/vip.c
>> b/drivers/staging/media/tegra-video/vip.c index 5ec717f3afd5..00e08a9971d5
>> 100644
>> --- a/drivers/staging/media/tegra-video/vip.c
>> +++ b/drivers/staging/media/tegra-video/vip.c
>> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
>> *pdev) pm_runtime_disable(&pdev->dev);
>>  }
>> 
>> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>>  extern const struct tegra_vip_soc tegra20_vip_soc;
>>  #endif
>> 
>>  static const struct of_device_id tegra_vip_of_id_table[] = {
>>  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>>  	{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
>> +#endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> +	{ .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
>>  #endif
>>  	{ }
>>  };
>
>If tegra30-vip is compatible with tegra20-vip, we don't need to add the 
>compatible string into the driver. Just mark it as 'compatible = 
>"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob 
>alluded, have this compat string pair as an option in the device tree schema).
>

While I am fine with using fallback but it may be a good idea to have a separate compatible so in case tegra30 would need a specific set of ops (tegra20 and tegra30 VIs are not exact match) no additional changes into schema would be required.

>Cheers,
>Mikko
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-27  4:28     ` Svyatoslav
@ 2025-08-27 10:27       ` Mikko Perttunen
  2025-08-29  6:54         ` Krzysztof Kozlowski
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 10:27 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, Svyatoslav
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Wednesday, August 27, 2025 1:28 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen 
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> >> Add ids for these clocks.
> >> 
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >> 
> >>  include/dt-bindings/clock/tegra30-car.h | 4 +++-
> >>  1 file changed, 3 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/include/dt-bindings/clock/tegra30-car.h
> >> b/include/dt-bindings/clock/tegra30-car.h index
> >> f193663e6f28..14b83e90a0fc
> >> 100644
> >> --- a/include/dt-bindings/clock/tegra30-car.h
> >> +++ b/include/dt-bindings/clock/tegra30-car.h
> >> @@ -271,6 +271,8 @@
> >> 
> >>  #define TEGRA30_CLK_AUDIO3_MUX 306
> >>  #define TEGRA30_CLK_AUDIO4_MUX 307
> >>  #define TEGRA30_CLK_SPDIF_MUX 308
> >> 
> >> -#define TEGRA30_CLK_CLK_MAX 309
> >> +#define TEGRA30_CLK_CSIA_PAD 309
> >> +#define TEGRA30_CLK_CSIB_PAD 310
> >> +#define TEGRA30_CLK_CLK_MAX 311
> >> 
> >>  #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
> >
> >The commit message refers to tegra20, but contents are tegra30.
> 
> My, bad, it should be tegra30
> 
> >Regarding the CLK_MAX define, I agree that it would be better to get rid of
> >it. Perhaps you can check if it would be reasonable to calculate it
> >dynamically in the driver, but a define and sanity check in the driver
> >would work too, I think.
> 
> It is not unreasonable, but moving this elsewhere may cause issues with
> adding new clocks. Addind new clocks would require updating not only header
> but also a place where max clocks are moved to and ai am not sure how can I
> dinamically calculate amount of clocks in the driver without updating both
> header and driver with each new clock added. Maybe you can propose a
> method?

Looking at the code, it's probably better to just move the CLK_MAX define into 
the source code. We can leave a comment here as reminder to update the define 
in the code if any new clocks are added. This happens so rarely that I don't 
think it should be a problem.

> >Cheers,
> >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-27  4:32     ` Svyatoslav
@ 2025-08-27 10:36       ` Mikko Perttunen
  2025-08-27 10:45         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 10:36 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, Svyatoslav
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen 
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> CSUS clock is required to be enabled on camera device configuration or
> >> else camera module refuses to initiate properly.
> >> 
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >> 
> >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> >>  2 files changed, 2 insertions(+)
> >> 
> >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> >> --- a/drivers/clk/tegra/clk-tegra20.c
> >> +++ b/drivers/clk/tegra/clk-tegra20.c
> >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
> >> 
> >>  	{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >>  	{ TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >>  	{ TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> >> 
> >> +	{ TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> >> 
> >>  	/* must be the last entry */
> >>  	{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> >>  
> >>  };
> >> 
> >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> >> --- a/drivers/clk/tegra/clk-tegra30.c
> >> +++ b/drivers/clk/tegra/clk-tegra30.c
> >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
> >> 
> >>  	{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> >>  	{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> >>  	{ TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> >> 
> >> +	{ TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> >> 
> >>  	/* must be the last entry */
> >>  	{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> >>  
> >>  };
> >
> >I looked into what this clock does and it seems to be a gate for the CSUS
> >pin, which provides an output clock for camera sensors (VI MCLK). Default
> >source seems to be PLLC_OUT1. It would be good to note that on the commit
> >message, as I can't find any documentation about the CSUS clock elsewhere.
> >
> >What is the 6MHz rate based on?
> 
> 6mhz is the statistic value which I was not able to alter while testing. I
> have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> >Since this seems to be a clock consumed by the sensor, it seems to me that
> >rather than making it always on, we could point to it in the sensor's
> >device tree entry.
> 
> Sensor device tree uses vi_sensor as clocks source and sensor drivers don't
> support multiple linked clocks.

AIUI vi_sensor is an internal clock so the sensor cannot be receiving it 
directly. Perhaps the sensor is actually connected to csus, and the reason we 
need to enable it is to allow the vi_sensor clock to pass through the csus 
gate?

That leaves the question of why the csus pad would be muxed to vi_sensor by 
default, but perhaps there's an explanation for that.

> >Cheers,
> >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-27 10:36       ` Mikko Perttunen
@ 2025-08-27 10:45         ` Svyatoslav Ryhel
  2025-08-28  8:13           ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-27 10:45 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> <mperttunen@nvidia.com> пише:
> > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > >> CSUS clock is required to be enabled on camera device configuration or
> > >> else camera module refuses to initiate properly.
> > >>
> > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > >> ---
> > >>
> > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > >>  2 files changed, 2 insertions(+)
> > >>
> > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
> > >>
> > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > >>
> > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > >>
> > >>    /* must be the last entry */
> > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > >>
> > >>  };
> > >>
> > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
> > >>
> > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > >>
> > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > >>
> > >>    /* must be the last entry */
> > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > >>
> > >>  };
> > >
> > >I looked into what this clock does and it seems to be a gate for the CSUS
> > >pin, which provides an output clock for camera sensors (VI MCLK). Default
> > >source seems to be PLLC_OUT1. It would be good to note that on the commit
> > >message, as I can't find any documentation about the CSUS clock elsewhere.
> > >
> > >What is the 6MHz rate based on?
> >
> > 6mhz is the statistic value which I was not able to alter while testing. I
> > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > >Since this seems to be a clock consumed by the sensor, it seems to me that
> > >rather than making it always on, we could point to it in the sensor's
> > >device tree entry.
> >
> > Sensor device tree uses vi_sensor as clocks source and sensor drivers don't
> > support multiple linked clocks.
>
> AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> directly. Perhaps the sensor is actually connected to csus, and the reason we
> need to enable it is to allow the vi_sensor clock to pass through the csus
> gate?
>
> That leaves the question of why the csus pad would be muxed to vi_sensor by
> default, but perhaps there's an explanation for that.
>

From downstream T30 sources csus and vi_sensor are always called in
pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
latter is used as camera reference clock since most sensors has
reference clock around 24 MHz

> > >Cheers,
> > >Mikko
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-27 10:45         ` Svyatoslav Ryhel
@ 2025-08-28  8:13           ` Mikko Perttunen
  2025-08-28  8:28             ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-28  8:13 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > 
> > <mperttunen@nvidia.com> пише:
> > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > >> CSUS clock is required to be enabled on camera device configuration
> > > >> or
> > > >> else camera module refuses to initiate properly.
> > > >> 
> > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > >> ---
> > > >> 
> > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > >>  2 files changed, 2 insertions(+)
> > > >> 
> > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110
> > > >> 100644
> > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[]
> > > >> = {
> > > >> 
> > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > >> 
> > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > >> 
> > > >>    /* must be the last entry */
> > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > >>  
> > > >>  };
> > > >> 
> > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0
> > > >> 100644
> > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[]
> > > >> = {
> > > >> 
> > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > >> 
> > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > >> 
> > > >>    /* must be the last entry */
> > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > >>  
> > > >>  };
> > > >
> > > >I looked into what this clock does and it seems to be a gate for the
> > > >CSUS
> > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > >Default
> > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > >commit
> > > >message, as I can't find any documentation about the CSUS clock
> > > >elsewhere.
> > > >
> > > >What is the 6MHz rate based on?
> > > 
> > > 6mhz is the statistic value which I was not able to alter while testing.
> > > I
> > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > > 
> > > >Since this seems to be a clock consumed by the sensor, it seems to me
> > > >that
> > > >rather than making it always on, we could point to it in the sensor's
> > > >device tree entry.
> > > 
> > > Sensor device tree uses vi_sensor as clocks source and sensor drivers
> > > don't
> > > support multiple linked clocks.
> > 
> > AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> > directly. Perhaps the sensor is actually connected to csus, and the reason
> > we need to enable it is to allow the vi_sensor clock to pass through the
> > csus gate?
> > 
> > That leaves the question of why the csus pad would be muxed to vi_sensor
> > by
> > default, but perhaps there's an explanation for that.
> 
> From downstream T30 sources csus and vi_sensor are always called in
> pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> latter is used as camera reference clock since most sensors has
> reference clock around 24 MHz

It's possible that the csus pad is still outputting 24MHz. The pinmux options 
for the csus pad are various clocks, so it would seem logical that the clock 
source for the pad is one of those clocks. However, on the clock framework 
side, the csus clock is just a gate. What I'm confused about is that since on 
the clock framework side the parent of csus is currently set to clk_m, I don't 
know why setting the rate of csus would affect the output of the pad, given 
clk_m is not one of the options for the pinmux.

It's be good to verify the register value for the csus pinmux to see where it 
thinks the clock is coming from, and then check how that matches with what we 
are seeing.

> 
> > > >Cheers,
> > > >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-28  8:13           ` Mikko Perttunen
@ 2025-08-28  8:28             ` Svyatoslav Ryhel
  2025-08-28 10:15               ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-28  8:28 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > >
> > > <mperttunen@nvidia.com> пише:
> > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > >> CSUS clock is required to be enabled on camera device configuration
> > > > >> or
> > > > >> else camera module refuses to initiate properly.
> > > > >>
> > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > >> ---
> > > > >>
> > > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > >>  2 files changed, 2 insertions(+)
> > > > >>
> > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110
> > > > >> 100644
> > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[]
> > > > >> = {
> > > > >>
> > > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > >>
> > > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > >>
> > > > >>    /* must be the last entry */
> > > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > >>
> > > > >>  };
> > > > >>
> > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0
> > > > >> 100644
> > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[]
> > > > >> = {
> > > > >>
> > > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > >>
> > > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > >>
> > > > >>    /* must be the last entry */
> > > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > >>
> > > > >>  };
> > > > >
> > > > >I looked into what this clock does and it seems to be a gate for the
> > > > >CSUS
> > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > >Default
> > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > >commit
> > > > >message, as I can't find any documentation about the CSUS clock
> > > > >elsewhere.
> > > > >
> > > > >What is the 6MHz rate based on?
> > > >
> > > > 6mhz is the statistic value which I was not able to alter while testing.
> > > > I
> > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > > >
> > > > >Since this seems to be a clock consumed by the sensor, it seems to me
> > > > >that
> > > > >rather than making it always on, we could point to it in the sensor's
> > > > >device tree entry.
> > > >
> > > > Sensor device tree uses vi_sensor as clocks source and sensor drivers
> > > > don't
> > > > support multiple linked clocks.
> > >
> > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> > > directly. Perhaps the sensor is actually connected to csus, and the reason
> > > we need to enable it is to allow the vi_sensor clock to pass through the
> > > csus gate?
> > >
> > > That leaves the question of why the csus pad would be muxed to vi_sensor
> > > by
> > > default, but perhaps there's an explanation for that.
> >
> > From downstream T30 sources csus and vi_sensor are always called in
> > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > latter is used as camera reference clock since most sensors has
> > reference clock around 24 MHz
>
> It's possible that the csus pad is still outputting 24MHz. The pinmux options
> for the csus pad are various clocks, so it would seem logical that the clock
> source for the pad is one of those clocks. However, on the clock framework
> side, the csus clock is just a gate. What I'm confused about is that since on
> the clock framework side the parent of csus is currently set to clk_m, I don't
> know why setting the rate of csus would affect the output of the pad, given
> clk_m is not one of the options for the pinmux.
>
> It's be good to verify the register value for the csus pinmux to see where it
> thinks the clock is coming from, and then check how that matches with what we
> are seeing.
>

TRM does not provide such data, it has only register address with
layout for it as a plain pad control, that register has only DRVDN,
DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
parent or anything similar. If you give me a method I will calculate
those values.

Another theory is that maybe csus is used for VIP cameras only and
vi_sensor is used for CSI cameras, but they both have to be on in
order to work correctly. Csus was removed from Tegra114 along with
VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
camera mclk source.

Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)

         pll_p                                 on     13  x34      408000000
            vi_sensor2                       $ off    0   3.0      136000000
               mclk2                         $ off    0            136000000
            vi_sensor                        $ off    0   3.0      136000000
               mclk                          $ off    0            136000000

> >
> > > > >Cheers,
> > > > >Mikko
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-28  8:28             ` Svyatoslav Ryhel
@ 2025-08-28 10:15               ` Mikko Perttunen
  2025-08-28 10:23                 ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-28 10:15 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> 
пише:
> > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > 
> > > > <mperttunen@nvidia.com> пише:
> > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > >> CSUS clock is required to be enabled on camera device
> > > > > >> configuration
> > > > > >> or
> > > > > >> else camera module refuses to initiate properly.
> > > > > >> 
> > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > >> ---
> > > > > >> 
> > > > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > >>  2 files changed, 2 insertions(+)
> > > > > >> 
> > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > >> 100644
> > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > >> init_table[]
> > > > > >> = {
> > > > > >> 
> > > > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > >> 
> > > > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > >> 
> > > > > >>    /* must be the last entry */
> > > > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > >>  
> > > > > >>  };
> > > > > >> 
> > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > >> 100644
> > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > >> init_table[]
> > > > > >> = {
> > > > > >> 
> > > > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > >> 
> > > > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > >> 
> > > > > >>    /* must be the last entry */
> > > > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > >>  
> > > > > >>  };
> > > > > >
> > > > > >I looked into what this clock does and it seems to be a gate for
> > > > > >the
> > > > > >CSUS
> > > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > > >Default
> > > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > > >commit
> > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > >elsewhere.
> > > > > >
> > > > > >What is the 6MHz rate based on?
> > > > > 
> > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > testing.
> > > > > I
> > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it
> > > > > 6mhz.
> > > > > 
> > > > > >Since this seems to be a clock consumed by the sensor, it seems to
> > > > > >me
> > > > > >that
> > > > > >rather than making it always on, we could point to it in the
> > > > > >sensor's
> > > > > >device tree entry.
> > > > > 
> > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > drivers
> > > > > don't
> > > > > support multiple linked clocks.
> > > > 
> > > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving
> > > > it
> > > > directly. Perhaps the sensor is actually connected to csus, and the
> > > > reason
> > > > we need to enable it is to allow the vi_sensor clock to pass through
> > > > the
> > > > csus gate?
> > > > 
> > > > That leaves the question of why the csus pad would be muxed to
> > > > vi_sensor
> > > > by
> > > > default, but perhaps there's an explanation for that.
> > > 
> > > From downstream T30 sources csus and vi_sensor are always called in
> > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > latter is used as camera reference clock since most sensors has
> > > reference clock around 24 MHz
> > 
> > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > options for the csus pad are various clocks, so it would seem logical
> > that the clock source for the pad is one of those clocks. However, on the
> > clock framework side, the csus clock is just a gate. What I'm confused
> > about is that since on the clock framework side the parent of csus is
> > currently set to clk_m, I don't know why setting the rate of csus would
> > affect the output of the pad, given clk_m is not one of the options for
> > the pinmux.
> > 
> > It's be good to verify the register value for the csus pinmux to see where
> > it thinks the clock is coming from, and then check how that matches with
> > what we are seeing.
> 
> TRM does not provide such data, it has only register address with
> layout for it as a plain pad control, that register has only DRVDN,
> DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> parent or anything similar. If you give me a method I will calculate
> those values.

I notice that on Tegra20, there is a mux pingroup called 'csus', which has the 
mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based on 
upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS pad.' 
about the CSUS (or SUS) clock.

On Tegra30, however, which I guess you refer to, I guess mux pingroups are 
gone and each pin has its own mux (again looking at upstream pinctrl-
tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1, 
VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by 
that name it only has the drive settings as you mention.

Are you testing on Tegra20, Tegra30, or both?

I've looked at some Tegra30 schematics, and they show a signal called VI_MCLK 
being routed to CSI cameras.

> 
> Another theory is that maybe csus is used for VIP cameras only and
> vi_sensor is used for CSI cameras, but they both have to be on in
> order to work correctly. Csus was removed from Tegra114 along with
> VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> camera mclk source.

I see the CSUS clock still on Tegra124 based on the upstream kernel. There is 
also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK pins, 
which both can output the clock. After Tegra30 there is only CAM_MCLK.

Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and mclk2. 
There is a comment on mclk saying:

	               .clk_num = 92, /* csus */

whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with 
vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.

All of that wasn't very coherently written, but to summarize my thoughts:

On Tegra30, we have
- Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which also 
goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as 
parent.
On Tegra114 and later,
- Same situation, but vi_mclk is gone, so instead we have cam_mclk (possibly 
multiple with associated mclkN and vi_sensorN clocks)
On Tegra20,
- The vi_mclk pin has a variety of mux options, one of which is VI_SENSOR_CLK. 
I expect this to correspond to the same behavior as later chips, i.e. sources 
from the csus(/mclk) clock, which sources from vi_sensor.

> 
> Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> 
>          pll_p                                 on     13  x34      408000000
> vi_sensor2                       $ off    0   3.0      136000000 mclk2     
>                    $ off    0            136000000 vi_sensor               
>         $ off    0   3.0      136000000 mclk                          $ off
>    0            136000000
> > > > > >Cheers,
> > > > > >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-28 10:15               ` Mikko Perttunen
@ 2025-08-28 10:23                 ` Svyatoslav Ryhel
  2025-08-29  0:29                   ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-28 10:23 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> пише:
> > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > >
> > > > > <mperttunen@nvidia.com> пише:
> > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > >> configuration
> > > > > > >> or
> > > > > > >> else camera module refuses to initiate properly.
> > > > > > >>
> > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > >> ---
> > > > > > >>
> > > > > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > >>  2 files changed, 2 insertions(+)
> > > > > > >>
> > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > >> 100644
> > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > >> init_table[]
> > > > > > >> = {
> > > > > > >>
> > > > > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > >>
> > > > > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > >>
> > > > > > >>    /* must be the last entry */
> > > > > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > >>
> > > > > > >>  };
> > > > > > >>
> > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > >> 100644
> > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > >> init_table[]
> > > > > > >> = {
> > > > > > >>
> > > > > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > >>
> > > > > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > >>
> > > > > > >>    /* must be the last entry */
> > > > > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > >>
> > > > > > >>  };
> > > > > > >
> > > > > > >I looked into what this clock does and it seems to be a gate for
> > > > > > >the
> > > > > > >CSUS
> > > > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > > > >Default
> > > > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > > > >commit
> > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > >elsewhere.
> > > > > > >
> > > > > > >What is the 6MHz rate based on?
> > > > > >
> > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > testing.
> > > > > > I
> > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it
> > > > > > 6mhz.
> > > > > >
> > > > > > >Since this seems to be a clock consumed by the sensor, it seems to
> > > > > > >me
> > > > > > >that
> > > > > > >rather than making it always on, we could point to it in the
> > > > > > >sensor's
> > > > > > >device tree entry.
> > > > > >
> > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > drivers
> > > > > > don't
> > > > > > support multiple linked clocks.
> > > > >
> > > > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving
> > > > > it
> > > > > directly. Perhaps the sensor is actually connected to csus, and the
> > > > > reason
> > > > > we need to enable it is to allow the vi_sensor clock to pass through
> > > > > the
> > > > > csus gate?
> > > > >
> > > > > That leaves the question of why the csus pad would be muxed to
> > > > > vi_sensor
> > > > > by
> > > > > default, but perhaps there's an explanation for that.
> > > >
> > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > latter is used as camera reference clock since most sensors has
> > > > reference clock around 24 MHz
> > >
> > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > options for the csus pad are various clocks, so it would seem logical
> > > that the clock source for the pad is one of those clocks. However, on the
> > > clock framework side, the csus clock is just a gate. What I'm confused
> > > about is that since on the clock framework side the parent of csus is
> > > currently set to clk_m, I don't know why setting the rate of csus would
> > > affect the output of the pad, given clk_m is not one of the options for
> > > the pinmux.
> > >
> > > It's be good to verify the register value for the csus pinmux to see where
> > > it thinks the clock is coming from, and then check how that matches with
> > > what we are seeing.
> >
> > TRM does not provide such data, it has only register address with
> > layout for it as a plain pad control, that register has only DRVDN,
> > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > parent or anything similar. If you give me a method I will calculate
> > those values.
>
> I notice that on Tegra20, there is a mux pingroup called 'csus', which has the
> mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based on
> upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS pad.'
> about the CSUS (or SUS) clock.
>
> On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> gone and each pin has its own mux (again looking at upstream pinctrl-
> tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> that name it only has the drive settings as you mention.
>
> Are you testing on Tegra20, Tegra30, or both?
>

I am testing on Tegra30 since I did not have compatible Tegra20 device
(with supported camera).

> I've looked at some Tegra30 schematics, and they show a signal called VI_MCLK
> being routed to CSI cameras.
>
> >
> > Another theory is that maybe csus is used for VIP cameras only and
> > vi_sensor is used for CSI cameras, but they both have to be on in
> > order to work correctly. Csus was removed from Tegra114 along with
> > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > camera mclk source.
>
> I see the CSUS clock still on Tegra124 based on the upstream kernel. There is
> also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK pins,
> which both can output the clock. After Tegra30 there is only CAM_MCLK.
>
> Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and mclk2.
> There is a comment on mclk saying:
>
>                        .clk_num = 92, /* csus */
>
> whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
>
> All of that wasn't very coherently written, but to summarize my thoughts:
>
> On Tegra30, we have
> - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which also
> goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> parent.
> On Tegra114 and later,
> - Same situation, but vi_mclk is gone, so instead we have cam_mclk (possibly
> multiple with associated mclkN and vi_sensorN clocks)
> On Tegra20,
> - The vi_mclk pin has a variety of mux options, one of which is VI_SENSOR_CLK.
> I expect this to correspond to the same behavior as later chips, i.e. sources
> from the csus(/mclk) clock, which sources from vi_sensor.
>

While this is all quite interesting, how to configure this properly?

> >
> > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> >
> >          pll_p                                 on     13  x34      408000000
> > vi_sensor2                       $ off    0   3.0      136000000 mclk2
> >                    $ off    0            136000000 vi_sensor
> >         $ off    0   3.0      136000000 mclk                          $ off
> >    0            136000000
> > > > > > >Cheers,
> > > > > > >Mikko
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-28 10:23                 ` Svyatoslav Ryhel
@ 2025-08-29  0:29                   ` Mikko Perttunen
  2025-08-29  7:05                     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29  0:29 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Thursday, August 28, 2025 7:23 PM Svyatoslav Ryhel wrote:
> чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> 
пише:
> > > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> > 
> > пише:
> > > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > > > 
> > > > > > <mperttunen@nvidia.com> пише:
> > > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > > >> configuration
> > > > > > > >> or
> > > > > > > >> else camera module refuses to initiate properly.
> > > > > > > >> 
> > > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > > >> ---
> > > > > > > >> 
> > > > > > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > > >>  2 files changed, 2 insertions(+)
> > > > > > > >> 
> > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > > >> 100644
> > > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > > >> init_table[]
> > > > > > > >> = {
> > > > > > > >> 
> > > > > > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > > >> 
> > > > > > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > >> 
> > > > > > > >>    /* must be the last entry */
> > > > > > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > > >>  
> > > > > > > >>  };
> > > > > > > >> 
> > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > > >> 100644
> > > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > > >> init_table[]
> > > > > > > >> = {
> > > > > > > >> 
> > > > > > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0
> > > > > > > >>    },
> > > > > > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > > >> 
> > > > > > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > >> 
> > > > > > > >>    /* must be the last entry */
> > > > > > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > > >>  
> > > > > > > >>  };
> > > > > > > >
> > > > > > > >I looked into what this clock does and it seems to be a gate
> > > > > > > >for
> > > > > > > >the
> > > > > > > >CSUS
> > > > > > > >pin, which provides an output clock for camera sensors (VI
> > > > > > > >MCLK).
> > > > > > > >Default
> > > > > > > >source seems to be PLLC_OUT1. It would be good to note that on
> > > > > > > >the
> > > > > > > >commit
> > > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > > >elsewhere.
> > > > > > > >
> > > > > > > >What is the 6MHz rate based on?
> > > > > > > 
> > > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > > testing.
> > > > > > > I
> > > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left
> > > > > > > it
> > > > > > > 6mhz.
> > > > > > > 
> > > > > > > >Since this seems to be a clock consumed by the sensor, it seems
> > > > > > > >to
> > > > > > > >me
> > > > > > > >that
> > > > > > > >rather than making it always on, we could point to it in the
> > > > > > > >sensor's
> > > > > > > >device tree entry.
> > > > > > > 
> > > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > > drivers
> > > > > > > don't
> > > > > > > support multiple linked clocks.
> > > > > > 
> > > > > > AIUI vi_sensor is an internal clock so the sensor cannot be
> > > > > > receiving
> > > > > > it
> > > > > > directly. Perhaps the sensor is actually connected to csus, and
> > > > > > the
> > > > > > reason
> > > > > > we need to enable it is to allow the vi_sensor clock to pass
> > > > > > through
> > > > > > the
> > > > > > csus gate?
> > > > > > 
> > > > > > That leaves the question of why the csus pad would be muxed to
> > > > > > vi_sensor
> > > > > > by
> > > > > > default, but perhaps there's an explanation for that.
> > > > > 
> > > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > > latter is used as camera reference clock since most sensors has
> > > > > reference clock around 24 MHz
> > > > 
> > > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > > options for the csus pad are various clocks, so it would seem logical
> > > > that the clock source for the pad is one of those clocks. However, on
> > > > the
> > > > clock framework side, the csus clock is just a gate. What I'm confused
> > > > about is that since on the clock framework side the parent of csus is
> > > > currently set to clk_m, I don't know why setting the rate of csus
> > > > would
> > > > affect the output of the pad, given clk_m is not one of the options
> > > > for
> > > > the pinmux.
> > > > 
> > > > It's be good to verify the register value for the csus pinmux to see
> > > > where
> > > > it thinks the clock is coming from, and then check how that matches
> > > > with
> > > > what we are seeing.
> > > 
> > > TRM does not provide such data, it has only register address with
> > > layout for it as a plain pad control, that register has only DRVDN,
> > > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > > parent or anything similar. If you give me a method I will calculate
> > > those values.
> > 
> > I notice that on Tegra20, there is a mux pingroup called 'csus', which has
> > the mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based
> > on upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS
> > pad.' about the CSUS (or SUS) clock.
> > 
> > On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> > gone and each pin has its own mux (again looking at upstream pinctrl-
> > tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> > VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> > that name it only has the drive settings as you mention.
> > 
> > Are you testing on Tegra20, Tegra30, or both?
> 
> I am testing on Tegra30 since I did not have compatible Tegra20 device
> (with supported camera).
> 
> > I've looked at some Tegra30 schematics, and they show a signal called
> > VI_MCLK being routed to CSI cameras.
> > 
> > > Another theory is that maybe csus is used for VIP cameras only and
> > > vi_sensor is used for CSI cameras, but they both have to be on in
> > > order to work correctly. Csus was removed from Tegra114 along with
> > > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > > camera mclk source.
> > 
> > I see the CSUS clock still on Tegra124 based on the upstream kernel. There
> > is also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK
> > pins, which both can output the clock. After Tegra30 there is only
> > CAM_MCLK.
> > 
> > Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and
> > mclk2.> 
> > There is a comment on mclk saying:
> >                        .clk_num = 92, /* csus */
> > 
> > whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> > vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
> > 
> > All of that wasn't very coherently written, but to summarize my thoughts:
> > 
> > On Tegra30, we have
> > - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which
> > also
> > goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> > parent.
> > On Tegra114 and later,
> > - Same situation, but vi_mclk is gone, so instead we have cam_mclk
> > (possibly multiple with associated mclkN and vi_sensorN clocks)
> > On Tegra20,
> > - The vi_mclk pin has a variety of mux options, one of which is
> > VI_SENSOR_CLK. I expect this to correspond to the same behavior as later
> > chips, i.e. sources from the csus(/mclk) clock, which sources from
> > vi_sensor.
> 
> While this is all quite interesting, how to configure this properly?

Fix the csus clock's parent to be vi_sensor. Point the sensor's device tree 
clock entry to csus. The sensor's clk_enable should then ungate csus and 
clk_set_rate should flow to vi_sensor to set the rate appropriately. In the 
board device tree pinctrl section, set the vi_mclk pin's function to VI 
(should be default on Tegra30, but best to be explicit).

I think that should do it, but it's all theoretical of course :)

> 
> > > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> > > 
> > >          pll_p                                 on     13  x34     
> > >          408000000
> > > 
> > > vi_sensor2                       $ off    0   3.0      136000000 mclk2
> > > 
> > >                    $ off    0            136000000 vi_sensor
> > >         
> > >         $ off    0   3.0      136000000 mclk                          $
> > >         off
> > >    
> > >    0            136000000
> > >    
> > > > > > > >Cheers,
> > > > > > > >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
  2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
  2025-08-27  4:26   ` Mikko Perttunen
@ 2025-08-29  0:44   ` Mikko Perttunen
  1 sibling, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29  0:44 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
> for correct work of CSI block.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
>  1 file changed, 14 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 70e85e2949e0..f033eb1ac26a 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -153,6 +153,7 @@ static unsigned long input_freq;
> 
>  static DEFINE_SPINLOCK(cml_lock);
>  static DEFINE_SPINLOCK(pll_d_lock);
> +static DEFINE_SPINLOCK(pll_d2_lock);
> 
>  #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset,	\
>  			    _clk_num, _gate_flags, _clk_id)	\
> @@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
> 
>  	/* PLLD2 */
>  	clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 
0,
> -			    &pll_d2_params, NULL);
> +			    &pll_d2_params, &pll_d2_lock);
>  	clks[TEGRA30_CLK_PLL_D2] = clk;
> 
>  	/* PLLD2_OUT0 */
> @@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
>  				    0, 48, periph_clk_enb_refcnt);
>  	clks[TEGRA30_CLK_DSIA] = clk;
> 
> +	/* csia_pad */
> +	clk = clk_register_gate(NULL, "csia_pad", "pll_d", 
CLK_SET_RATE_PARENT,
> +				clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
> +	clk_register_clkdev(clk, "csia_pad", NULL);

I believe clkdevs are obsolete, so we can drop the clkdev registrations.

> +	clks[TEGRA30_CLK_CSIA_PAD] = clk;
> +
> +	/* csib_pad */
> +	clk = clk_register_gate(NULL, "csib_pad", "pll_d2", 
CLK_SET_RATE_PARENT,
> +				clk_base + PLLD2_BASE, 26, 0, 
&pll_d2_lock);
> +	clk_register_clkdev(clk, "csib_pad", NULL);
> +	clks[TEGRA30_CLK_CSIB_PAD] = clk;
> +
>  	/* pcie */
>  	clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
>  				    70, periph_clk_enb_refcnt);





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-08-27  4:47     ` Svyatoslav
@ 2025-08-29  0:56       ` Mikko Perttunen
  0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29  0:56 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, Svyatoslav
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Wednesday, August 27, 2025 1:47 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:29:40 GMT+03:00, Mikko Perttunen 
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
> >> Tegra30.
> >> 
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >> 
> >>  drivers/staging/media/tegra-video/Makefile | 1 +
> >>  drivers/staging/media/tegra-video/vi.c     | 3 +++
> >>  drivers/staging/media/tegra-video/vi.h     | 2 +-
> >>  drivers/staging/media/tegra-video/video.c  | 4 ++++
> >>  drivers/staging/media/tegra-video/vip.c    | 5 ++++-
> >>  5 files changed, 13 insertions(+), 2 deletions(-)
> >> 
> >> diff --git a/drivers/staging/media/tegra-video/Makefile
> >> b/drivers/staging/media/tegra-video/Makefile index
> >> 6c7552e05109..96380b5dbd8b 100644
> >> --- a/drivers/staging/media/tegra-video/Makefile
> >> +++ b/drivers/staging/media/tegra-video/Makefile
> >> @@ -6,5 +6,6 @@ tegra-video-objs := \
> >> 
> >>  		csi.o
> >>  
> >>  tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC)  += tegra20.o
> >> 
> >> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC)  += tegra20.o
> >> 
> >>  tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
> >>  obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
> >> 
> >> diff --git a/drivers/staging/media/tegra-video/vi.c
> >> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vi.c
> >> +++ b/drivers/staging/media/tegra-video/vi.c
> >> @@ -1959,6 +1959,9 @@ static const struct of_device_id
> >> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >> 
> >>  	{ .compatible = "nvidia,tegra20-vi",  .data = &tegra20_vi_soc },
> >>  
> >>  #endif
> >> 
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> +	{ .compatible = "nvidia,tegra30-vi",  .data = &tegra20_vi_soc },
> >> +#endif
> >> 
> >>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >>  
> >>  	{ .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
> >>  
> >>  #endif
> >> 
> >> diff --git a/drivers/staging/media/tegra-video/vi.h
> >> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vi.h
> >> +++ b/drivers/staging/media/tegra-video/vi.h
> >> @@ -296,7 +296,7 @@ struct tegra_video_format {
> >> 
> >>  	u32 fourcc;
> >>  
> >>  };
> >> 
> >> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) ||
> >> defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> 
> >>  extern const struct tegra_vi_soc tegra20_vi_soc;
> >>  #endif
> >>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >> 
> >> diff --git a/drivers/staging/media/tegra-video/video.c
> >> b/drivers/staging/media/tegra-video/video.c index
> >> 074ad0dc56ca..a25885f93cd7 100644
> >> --- a/drivers/staging/media/tegra-video/video.c
> >> +++ b/drivers/staging/media/tegra-video/video.c
> >> @@ -127,6 +127,10 @@ static const struct of_device_id
> >> host1x_video_subdevs[] = { { .compatible = "nvidia,tegra20-vip", },
> >> 
> >>  	{ .compatible = "nvidia,tegra20-vi", },
> >>  
> >>  #endif
> >> 
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> +	{ .compatible = "nvidia,tegra30-vip", },
> >> +	{ .compatible = "nvidia,tegra30-vi", },
> >> +#endif
> >> 
> >>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >>  
> >>  	{ .compatible = "nvidia,tegra210-csi", },
> >>  	{ .compatible = "nvidia,tegra210-vi", },
> >> 
> >> diff --git a/drivers/staging/media/tegra-video/vip.c
> >> b/drivers/staging/media/tegra-video/vip.c index
> >> 5ec717f3afd5..00e08a9971d5
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vip.c
> >> +++ b/drivers/staging/media/tegra-video/vip.c
> >> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
> >> *pdev) pm_runtime_disable(&pdev->dev);
> >> 
> >>  }
> >> 
> >> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) ||
> >> defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> 
> >>  extern const struct tegra_vip_soc tegra20_vip_soc;
> >>  #endif
> >>  
> >>  static const struct of_device_id tegra_vip_of_id_table[] = {
> >>  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >>  
> >>  	{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
> >> 
> >> +#endif
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> +	{ .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
> >> 
> >>  #endif
> >>  
> >>  	{ }
> >>  
> >>  };
> >
> >If tegra30-vip is compatible with tegra20-vip, we don't need to add the
> >compatible string into the driver. Just mark it as 'compatible =
> >"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob
> >alluded, have this compat string pair as an option in the device tree
> >schema).
> While I am fine with using fallback but it may be a good idea to have a
> separate compatible so in case tegra30 would need a specific set of ops
> (tegra20 and tegra30 VIs are not exact match) no additional changes into
> schema would be required.

The standard practice is to use the compatible string fallback in device tree 
when we believe the hardware to be compatible. If that later turns out not to 
be the case (which should be unlikely), the schema can be adjusted along with 
the source code changes.

> >Cheers,
> >Mikko





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
  2025-08-19 20:27   ` Rob Herring
  2025-08-20  5:36     ` Svyatoslav Ryhel
@ 2025-08-29  6:42     ` Svyatoslav Ryhel
  1 sibling, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-29  6:42 UTC (permalink / raw)
  To: Rob Herring
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 19 серп. 2025 р. о 23:27 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> > Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
>
> That's not what the compatible schema says. 'exactly the same' implies a
> fallback to whatever it is exactly the same as.
>
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  .../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml    | 1 +
> >  1 file changed, 1 insertion(+)
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > index 14294edb8d8c..39e9b3297dbd 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > @@ -13,6 +13,7 @@ properties:
> >    compatible:
> >      enum:
> >        - nvidia,tegra20-vip
> > +      - nvidia,tegra30-vip
> >

Rob, may I use this:

properties:
  compatible:
    one0f:
      - const: nvidia,tegra20-vip
      - items:
          - const: nvidia,tegra30-vip
          - const: nvidia,tegra20-vip

Among all Tegra SoC only 2 have VIP support Tegra20 and Tegra30.
Tegra30 is backwards compatible with Tegra20 so we can use fallback.
There should be no new generation added to this schema.

OR should I use enum?

properties:
  compatible:
      one0f:
        - enum:
          - nvidia,tegra20-vip

        - items:
          - const: nvidia,tegra30-vip
          - const: nvidia,tegra20-vip

> >    ports:
> >      $ref: /schemas/graph.yaml#/properties/ports
> > --
> > 2.48.1
> >

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
  2025-08-27 10:27       ` Mikko Perttunen
@ 2025-08-29  6:54         ` Krzysztof Kozlowski
  0 siblings, 0 replies; 59+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-29  6:54 UTC (permalink / raw)
  To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, Svyatoslav
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On 27/08/2025 12:27, Mikko Perttunen wrote:
> On Wednesday, August 27, 2025 1:28 PM Svyatoslav wrote:
>> 27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen 
> <mperttunen@nvidia.com> пише:
>>> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>>>> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
>>>> Add ids for these clocks.
>>>>
>>>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>>>> ---
>>>>
>>>>  include/dt-bindings/clock/tegra30-car.h | 4 +++-
>>>>  1 file changed, 3 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/include/dt-bindings/clock/tegra30-car.h
>>>> b/include/dt-bindings/clock/tegra30-car.h index
>>>> f193663e6f28..14b83e90a0fc
>>>> 100644
>>>> --- a/include/dt-bindings/clock/tegra30-car.h
>>>> +++ b/include/dt-bindings/clock/tegra30-car.h
>>>> @@ -271,6 +271,8 @@
>>>>
>>>>  #define TEGRA30_CLK_AUDIO3_MUX 306
>>>>  #define TEGRA30_CLK_AUDIO4_MUX 307
>>>>  #define TEGRA30_CLK_SPDIF_MUX 308
>>>>
>>>> -#define TEGRA30_CLK_CLK_MAX 309
>>>> +#define TEGRA30_CLK_CSIA_PAD 309
>>>> +#define TEGRA30_CLK_CSIB_PAD 310
>>>> +#define TEGRA30_CLK_CLK_MAX 311
>>>>
>>>>  #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
>>>
>>> The commit message refers to tegra20, but contents are tegra30.
>>
>> My, bad, it should be tegra30
>>
>>> Regarding the CLK_MAX define, I agree that it would be better to get rid of
>>> it. Perhaps you can check if it would be reasonable to calculate it
>>> dynamically in the driver, but a define and sanity check in the driver
>>> would work too, I think.
>>
>> It is not unreasonable, but moving this elsewhere may cause issues with
>> adding new clocks. Addind new clocks would require updating not only header

No, there are no such issues.

>> but also a place where max clocks are moved to and ai am not sure how can I
>> dinamically calculate amount of clocks in the driver without updating both
>> header and driver with each new clock added. Maybe you can propose a
>> method?
> 
> Looking at the code, it's probably better to just move the CLK_MAX define into 

Just like every other driver.

> the source code. We can leave a comment here as reminder to update the define 
> in the code if any new clocks are added. This happens so rarely that I don't 
> think it should be a problem.
No, don't leave comments here. There is no single risk of breakage,
there is no issue to fix with that comment.

If you add clock to the driver WITHOUT binding, nothing, absolutely
nothing bad will happen. You will just not have a way to use that clock
in DTS.

Best regards,
Krzysztof

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
  2025-08-29  0:29                   ` Mikko Perttunen
@ 2025-08-29  7:05                     ` Svyatoslav Ryhel
  0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-29  7:05 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

пт, 29 серп. 2025 р. о 03:30 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Thursday, August 28, 2025 7:23 PM Svyatoslav Ryhel wrote:
> > чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > > > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com>
> пише:
> > > > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> > >
> > > пише:
> > > > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > > > >
> > > > > > > <mperttunen@nvidia.com> пише:
> > > > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > > > >> configuration
> > > > > > > > >> or
> > > > > > > > >> else camera module refuses to initiate properly.
> > > > > > > > >>
> > > > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > > > >> ---
> > > > > > > > >>
> > > > > > > > >>  drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > > > >>  drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > > > >>  2 files changed, 2 insertions(+)
> > > > > > > > >>
> > > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > > > >> 100644
> > > > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > > > >> init_table[]
> > > > > > > > >> = {
> > > > > > > > >>
> > > > > > > > >>    { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > > >>    { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > > >>    { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > > > >>
> > > > > > > > >> +  { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > > >>
> > > > > > > > >>    /* must be the last entry */
> > > > > > > > >>    { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > > > >>
> > > > > > > > >>  };
> > > > > > > > >>
> > > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > > > >> 100644
> > > > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > > > >> init_table[]
> > > > > > > > >> = {
> > > > > > > > >>
> > > > > > > > >>    { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > > > >>    { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0
> > > > > > > > >>    },
> > > > > > > > >>    { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > > > >>
> > > > > > > > >> +  { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > > >>
> > > > > > > > >>    /* must be the last entry */
> > > > > > > > >>    { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > > > >>
> > > > > > > > >>  };
> > > > > > > > >
> > > > > > > > >I looked into what this clock does and it seems to be a gate
> > > > > > > > >for
> > > > > > > > >the
> > > > > > > > >CSUS
> > > > > > > > >pin, which provides an output clock for camera sensors (VI
> > > > > > > > >MCLK).
> > > > > > > > >Default
> > > > > > > > >source seems to be PLLC_OUT1. It would be good to note that on
> > > > > > > > >the
> > > > > > > > >commit
> > > > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > > > >elsewhere.
> > > > > > > > >
> > > > > > > > >What is the 6MHz rate based on?
> > > > > > > >
> > > > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > > > testing.
> > > > > > > > I
> > > > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left
> > > > > > > > it
> > > > > > > > 6mhz.
> > > > > > > >
> > > > > > > > >Since this seems to be a clock consumed by the sensor, it seems
> > > > > > > > >to
> > > > > > > > >me
> > > > > > > > >that
> > > > > > > > >rather than making it always on, we could point to it in the
> > > > > > > > >sensor's
> > > > > > > > >device tree entry.
> > > > > > > >
> > > > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > > > drivers
> > > > > > > > don't
> > > > > > > > support multiple linked clocks.
> > > > > > >
> > > > > > > AIUI vi_sensor is an internal clock so the sensor cannot be
> > > > > > > receiving
> > > > > > > it
> > > > > > > directly. Perhaps the sensor is actually connected to csus, and
> > > > > > > the
> > > > > > > reason
> > > > > > > we need to enable it is to allow the vi_sensor clock to pass
> > > > > > > through
> > > > > > > the
> > > > > > > csus gate?
> > > > > > >
> > > > > > > That leaves the question of why the csus pad would be muxed to
> > > > > > > vi_sensor
> > > > > > > by
> > > > > > > default, but perhaps there's an explanation for that.
> > > > > >
> > > > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > > > latter is used as camera reference clock since most sensors has
> > > > > > reference clock around 24 MHz
> > > > >
> > > > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > > > options for the csus pad are various clocks, so it would seem logical
> > > > > that the clock source for the pad is one of those clocks. However, on
> > > > > the
> > > > > clock framework side, the csus clock is just a gate. What I'm confused
> > > > > about is that since on the clock framework side the parent of csus is
> > > > > currently set to clk_m, I don't know why setting the rate of csus
> > > > > would
> > > > > affect the output of the pad, given clk_m is not one of the options
> > > > > for
> > > > > the pinmux.
> > > > >
> > > > > It's be good to verify the register value for the csus pinmux to see
> > > > > where
> > > > > it thinks the clock is coming from, and then check how that matches
> > > > > with
> > > > > what we are seeing.
> > > >
> > > > TRM does not provide such data, it has only register address with
> > > > layout for it as a plain pad control, that register has only DRVDN,
> > > > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > > > parent or anything similar. If you give me a method I will calculate
> > > > those values.
> > >
> > > I notice that on Tegra20, there is a mux pingroup called 'csus', which has
> > > the mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based
> > > on upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS
> > > pad.' about the CSUS (or SUS) clock.
> > >
> > > On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> > > gone and each pin has its own mux (again looking at upstream pinctrl-
> > > tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> > > VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> > > that name it only has the drive settings as you mention.
> > >
> > > Are you testing on Tegra20, Tegra30, or both?
> >
> > I am testing on Tegra30 since I did not have compatible Tegra20 device
> > (with supported camera).
> >
> > > I've looked at some Tegra30 schematics, and they show a signal called
> > > VI_MCLK being routed to CSI cameras.
> > >
> > > > Another theory is that maybe csus is used for VIP cameras only and
> > > > vi_sensor is used for CSI cameras, but they both have to be on in
> > > > order to work correctly. Csus was removed from Tegra114 along with
> > > > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > > > camera mclk source.
> > >
> > > I see the CSUS clock still on Tegra124 based on the upstream kernel. There
> > > is also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK
> > > pins, which both can output the clock. After Tegra30 there is only
> > > CAM_MCLK.
> > >
> > > Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and
> > > mclk2.>
> > > There is a comment on mclk saying:
> > >                        .clk_num = 92, /* csus */
> > >
> > > whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> > > vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
> > >
> > > All of that wasn't very coherently written, but to summarize my thoughts:
> > >
> > > On Tegra30, we have
> > > - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which
> > > also
> > > goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> > > parent.
> > > On Tegra114 and later,
> > > - Same situation, but vi_mclk is gone, so instead we have cam_mclk
> > > (possibly multiple with associated mclkN and vi_sensorN clocks)
> > > On Tegra20,
> > > - The vi_mclk pin has a variety of mux options, one of which is
> > > VI_SENSOR_CLK. I expect this to correspond to the same behavior as later
> > > chips, i.e. sources from the csus(/mclk) clock, which sources from
> > > vi_sensor.
> >
> > While this is all quite interesting, how to configure this properly?
>
> Fix the csus clock's parent to be vi_sensor. Point the sensor's device tree
> clock entry to csus. The sensor's clk_enable should then ungate csus and
> clk_set_rate should flow to vi_sensor to set the rate appropriately. In the
> board device tree pinctrl section, set the vi_mclk pin's function to VI
> (should be default on Tegra30, but best to be explicit).
>
> I think that should do it, but it's all theoretical of course :)
>

Ok, seems to work correctly. I will add same setup to Tegra114 since
camera is not operational without same CSUS gate if you don't mind.

> >
> > > > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> > > >
> > > >          pll_p                                 on     13  x34
> > > >          408000000
> > > >
> > > > vi_sensor2                       $ off    0   3.0      136000000 mclk2
> > > >
> > > >                    $ off    0            136000000 vi_sensor
> > > >
> > > >         $ off    0   3.0      136000000 mclk                          $
> > > >         off
> > > >
> > > >    0            136000000
> > > >
> > > > > > > > >Cheers,
> > > > > > > > >Mikko
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
  2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
@ 2025-09-02  0:46   ` Mikko Perttunen
  2025-09-02  5:05     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  0:46 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> all MIPI calibration pads were part of VI block.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/csi.c      | 12 +++++++-----
>  drivers/staging/media/tegra-video/csi.h      |  1 +
>  drivers/staging/media/tegra-video/tegra210.c |  1 +
>  3 files changed, 9 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/csi.c
> b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
>  		return 0;
> 
> -	chan->mipi = tegra_mipi_request(csi->dev, node);
> -	if (IS_ERR(chan->mipi)) {
> -		ret = PTR_ERR(chan->mipi);
> -		chan->mipi = NULL;
> -		dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> +	if (csi->soc->has_mipi_calibration) {
> +		chan->mipi = tegra_mipi_request(csi->dev, node);

The way I would read 'soc->has_mipi_calibration' is that this device (CSI) 
contains the MIPI calibration hardware. I.e. the opposite of here. I would 
invert the logic and optionally call it e.g. 'internal_mipi_calib'.

A cleaner way to do this might be to always call tegra_mipi_request et al. -- 
on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the 
callbacks registered in the MIPI driver as we discussed before. That way the 
CSI driver won't need separate code paths for SoCs with internal MIPI 
calibration and SoCs with the external MIPI calibration device.

Cheers,
Mikko

> +		if (IS_ERR(chan->mipi)) {
> +			ret = PTR_ERR(chan->mipi);
> +			chan->mipi = NULL;
> +			dev_err(csi->dev, "failed to get mipi device: 
%d\n", ret);
> +		}
>  	}
> 
>  	return ret;
> diff --git a/drivers/staging/media/tegra-video/csi.h
> b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> 100644
> --- a/drivers/staging/media/tegra-video/csi.h
> +++ b/drivers/staging/media/tegra-video/csi.h
> @@ -128,6 +128,7 @@ struct tegra_csi_soc {
>  	unsigned int num_clks;
>  	const struct tpg_framerate *tpg_frmrate_table;
>  	unsigned int tpg_frmrate_table_size;
> +	bool has_mipi_calibration;
>  };
> 
>  /**
> diff --git a/drivers/staging/media/tegra-video/tegra210.c
> b/drivers/staging/media/tegra-video/tegra210.c index
> da99f19a39e7..305472e94af4 100644
> --- a/drivers/staging/media/tegra-video/tegra210.c
> +++ b/drivers/staging/media/tegra-video/tegra210.c
> @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
>  	.num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
>  	.tpg_frmrate_table = tegra210_tpg_frmrate_table,
>  	.tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> +	.has_mipi_calibration = true,
>  };





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height
  2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
@ 2025-09-02  0:51   ` Mikko Perttunen
  0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  0:51 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Maximum width and height for Tegra20 and Tegra30 is determined by
> respective register field, rounded down to factor of 2, which is 8191U
> rounded down to 8190U.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/tegra20.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 7b8f8f810b35..3e2d746638b6 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -23,11 +23,10 @@
> 
>  #define TEGRA_VI_SYNCPT_WAIT_TIMEOUT			
msecs_to_jiffies(200)
> 
> -/* This are just good-sense numbers. The actual min/max is not documented.
> */ #define TEGRA20_MIN_WIDTH	32U
> +#define TEGRA20_MAX_WIDTH	8190U
>  #define TEGRA20_MIN_HEIGHT	32U
> -#define TEGRA20_MAX_WIDTH	2048U
> -#define TEGRA20_MAX_HEIGHT	2048U
> +#define TEGRA20_MAX_HEIGHT	8190U
> 
>  /*
> --------------------------------------------------------------------------
> * Registers

Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI
  2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-09-02  1:00   ` Mikko Perttunen
  0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  1:00 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> VI in Tegra20/Tegra30 has 2 VI outputs with different set of supported
> formats. Convert output registers to macros for simpler work with both
> outputs since apart formats their layout matches.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/tegra20.c | 80 ++++++++++++---------
>  1 file changed, 45 insertions(+), 35 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 3e2d746638b6..54512d1ecf83 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -28,13 +28,19 @@
>  #define TEGRA20_MIN_HEIGHT	32U
>  #define TEGRA20_MAX_HEIGHT	8190U
> 
> +/* Tegra20/Tegra30 has 2 outputs in VI */
> +enum {
> +	OUT_1,
> +	OUT_2,
> +};
> +

I would prefer ..

enum tegra_vi_out {
	TEGRA_VI_OUT_1 = 0, // explicit since the values are important here
	TEGRA_VI_OUT_2 = 1,
};

and then using the type instead of int.

>  /*
> --------------------------------------------------------------------------
> * Registers
>   */
> 
> -#define TEGRA_VI_CONT_SYNCPT_OUT_1			0x0060
> -#define       VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT	BIT(8)
> -#define       VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT	0
> +#define TEGRA_VI_CONT_SYNCPT_OUT(n)			(0x0060 + (n) * 
4)
> +#define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT	BIT(8)
> +#define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT		0
> 
>  #define TEGRA_VI_VI_INPUT_CONTROL			0x0088
>  #define       VI_INPUT_FIELD_DETECT			BIT(27)
> @@ -46,6 +52,7 @@
>  #define       VI_INPUT_YUV_INPUT_FORMAT_YVYU		(3 <<
> VI_INPUT_YUV_INPUT_FORMAT_SFT) #define       VI_INPUT_INPUT_FORMAT_SFT		
	2 
> /* bits [5:2] */
>  #define       VI_INPUT_INPUT_FORMAT_YUV422		(0 <<
> VI_INPUT_INPUT_FORMAT_SFT) +#define       VI_INPUT_INPUT_FORMAT_BAYER		
(2
> << VI_INPUT_INPUT_FORMAT_SFT) #define      
> VI_INPUT_VIP_INPUT_ENABLE			BIT(1)
> 
>  #define TEGRA_VI_VI_CORE_CONTROL			0x008c
> @@ -66,7 +73,7 @@
>  #define       VI_VI_CORE_CONTROL_OUTPUT_TO_EPP_SFT	2
>  #define       VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_SFT	0
> 
> -#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL		0x0090
> +#define TEGRA_VI_VI_OUTPUT_CONTROL(n)			(0x0090 + (n) * 
4)
>  #define       VI_OUTPUT_FORMAT_EXT			BIT(22)
>  #define       VI_OUTPUT_V_DIRECTION			BIT(20)
>  #define       VI_OUTPUT_H_DIRECTION			BIT(19)
> @@ -80,6 +87,7 @@
>  #define       VI_OUTPUT_OUTPUT_FORMAT_SFT		0
>  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST	(3 <<
> VI_OUTPUT_OUTPUT_FORMAT_SFT) #define      
> VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR	(6 << 
VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT	(9 <<
> VI_OUTPUT_OUTPUT_FORMAT_SFT)
> 
>  #define TEGRA_VI_VIP_H_ACTIVE				0x00a4
>  #define       VI_VIP_H_ACTIVE_PERIOD_SFT		16 /* active pixels/
line, must be
> even */ @@ -89,26 +97,26 @@
>  #define       VI_VIP_V_ACTIVE_PERIOD_SFT		16 /* active lines */
>  #define       VI_VIP_V_ACTIVE_START_SFT			0
> 
> -#define TEGRA_VI_VB0_START_ADDRESS_FIRST		0x00c4
> -#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST			0x00c8
> +#define TEGRA_VI_VB0_START_ADDRESS(n)			(0x00c4 + (n) * 
44)
> +#define TEGRA_VI_VB0_BASE_ADDRESS(n)			(0x00c8 + (n) * 
44)
>  #define TEGRA_VI_VB0_START_ADDRESS_U			0x00cc
>  #define TEGRA_VI_VB0_BASE_ADDRESS_U			0x00d0
>  #define TEGRA_VI_VB0_START_ADDRESS_V			0x00d4
>  #define TEGRA_VI_VB0_BASE_ADDRESS_V			0x00d8
> 
> -#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE		0x00e0
> -#define       VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT		16
> -#define       VI_FIRST_OUTPUT_FRAME_WIDTH_SFT		0
> +#define TEGRA_VI_OUTPUT_FRAME_SIZE(n)			(0x00e0 + (n) * 
24)
> +#define       VI_OUTPUT_FRAME_HEIGHT_SFT		16
> +#define       VI_OUTPUT_FRAME_WIDTH_SFT			0
> 
> -#define TEGRA_VI_VB0_COUNT_FIRST			0x00e4
> +#define TEGRA_VI_VB0_COUNT(n)				(0x00e4 + (n) * 
24)
> 
> -#define TEGRA_VI_VB0_SIZE_FIRST				0x00e8
> -#define       VI_VB0_SIZE_FIRST_V_SFT			16
> -#define       VI_VB0_SIZE_FIRST_H_SFT			0
> +#define TEGRA_VI_VB0_SIZE(n)				(0x00e8 + (n) * 
24)
> +#define       VI_VB0_SIZE_V_SFT				16
> +#define       VI_VB0_SIZE_H_SFT				0
> 
> -#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST		0x00ec
> -#define       VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT	30
> -#define       VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT	0
> +#define TEGRA_VI_VB0_BUFFER_STRIDE(n)			(0x00ec + (n) * 
24)
> +#define       VI_VB0_BUFFER_STRIDE_CHROMA_SFT		30
> +#define       VI_VB0_BUFFER_STRIDE_LUMA_SFT		0
> 
>  #define TEGRA_VI_H_LPF_CONTROL				0x0108
>  #define       VI_H_LPF_CONTROL_CHROMA_SFT		16
> @@ -136,7 +144,7 @@
>  #define       VI_CAMERA_CONTROL_TEST_MODE		BIT(1)
>  #define       VI_CAMERA_CONTROL_VIP_ENABLE		BIT(0)
> 
> -#define TEGRA_VI_VI_ENABLE				0x01a4
> +#define TEGRA_VI_VI_ENABLE(n)				(0x01a4 + (n) * 
4)
>  #define       VI_VI_ENABLE_SW_FLOW_CONTROL_OUT1		BIT(1)
>  #define       VI_VI_ENABLE_FIRST_OUTPUT_TO_MEM_DISABLE	BIT(0)
> 
> @@ -366,8 +374,8 @@ static void tegra20_channel_vi_buffer_setup(struct
> tegra_vi_channel *chan, case V4L2_PIX_FMT_VYUY:
>  	case V4L2_PIX_FMT_YUYV:
>  	case V4L2_PIX_FMT_YVYU:
> -		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,  
base);
> -		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_FIRST, 
base +
> chan->start_offset); +		tegra20_vi_write(chan,
> TEGRA_VI_VB0_BASE_ADDRESS(OUT_1),  base); +		tegra20_vi_write(chan,
> TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
>  	}
>  }
> @@ -455,6 +463,7 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) int stride_l = chan->format.bytesperline;
>  	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
>  			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> +	int output_channel = OUT_1;
>  	int main_output_format;
>  	int yuv_output_format;
> 
> @@ -472,33 +481,33 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) /* Set up raise-on-edge, so we get an interrupt on
> end of frame. */ tegra20_vi_write(chan, TEGRA_VI_VI_RAISE,
> VI_VI_RAISE_ON_EDGE);
> 
> -	tegra20_vi_write(chan, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
> +	tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
>  			 (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
>  			 (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
>  			 yuv_output_format << 
VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
>  			 main_output_format << 
VI_OUTPUT_OUTPUT_FORMAT_SFT);
> 
>  	/* Set up frame size */
> -	tegra20_vi_write(chan, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
> -			 height << VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT |
> -			 width  << VI_FIRST_OUTPUT_FRAME_WIDTH_SFT);
> +	tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> +			 height << VI_OUTPUT_FRAME_HEIGHT_SFT |
> +			 width  << VI_OUTPUT_FRAME_WIDTH_SFT);
> 
>  	/* First output memory enabled */
> -	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
> +	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> 
>  	/* Set the number of frames in the buffer */
> -	tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT_FIRST, 1);
> +	tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT(output_channel), 1);
> 
>  	/* Set up buffer frame size */
> -	tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE_FIRST,
> -			 height << VI_VB0_SIZE_FIRST_V_SFT |
> -			 width  << VI_VB0_SIZE_FIRST_H_SFT);
> +	tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE(output_channel),
> +			 height << VI_VB0_SIZE_V_SFT |
> +			 width  << VI_VB0_SIZE_H_SFT);
> 
> -	tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
> -			 stride_l << VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT |
> -			 stride_c << 
VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT);
> +	tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE(output_channel),
> +			 stride_l << VI_VB0_BUFFER_STRIDE_LUMA_SFT |
> +			 stride_c << VI_VB0_BUFFER_STRIDE_CHROMA_SFT);
> 
> -	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
> +	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
>  }
> 
>  static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> @@ -607,6 +616,7 @@ static int tegra20_vip_start_streaming(struct
> tegra_vip_channel *vip_chan) struct tegra_vi_channel *vi_chan =
> v4l2_get_subdev_hostdata(&vip_chan->subdev); int width  =
> vi_chan->format.width;
>  	int height = vi_chan->format.height;
> +	int output_channel = OUT_1;
> 
>  	unsigned int main_input_format;
>  	unsigned int yuv_input_format;
> @@ -637,10 +647,10 @@ static int tegra20_vip_start_streaming(struct
> tegra_vip_channel *vip_chan) GENMASK(9, 2) << VI_DATA_INPUT_SFT);
>  	tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INVERSION, 0);
> 
> -	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT_1,
> -			 VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT |
> +	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> +			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
>  			 host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> -			 << VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT);
> +			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> 
>  	tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL,
> VI_CAMERA_CONTROL_STOP_CAPTURE);





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
  2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-09-02  1:09   ` Mikko Perttunen
  2025-09-02  5:11     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  1:09 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
> of existing YUV422_8 2X8.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
>  1 file changed, 69 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 67631e0c9ffc..b466fe7f4504 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct
> tegra_vi_channel *chan, case MEDIA_BUS_FMT_YVYU8_2X8:
>  		(*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
>  		break;
> +	/* RAW8 */
> +	case MEDIA_BUS_FMT_SBGGR8_1X8:
> +	case MEDIA_BUS_FMT_SGBRG8_1X8:
> +	case MEDIA_BUS_FMT_SGRBG8_1X8:
> +	case MEDIA_BUS_FMT_SRGGB8_1X8:
> +	/* RAW10 */
> +	case MEDIA_BUS_FMT_SBGGR10_1X10:
> +	case MEDIA_BUS_FMT_SGBRG10_1X10:
> +	case MEDIA_BUS_FMT_SGRBG10_1X10:
> +	case MEDIA_BUS_FMT_SRGGB10_1X10:
> +		(*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;

Should this be main_input_format instead of yuv_input_format?

> +		break;
>  	}
>  }
> 
> @@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct
> tegra_vi_channel *chan, case V4L2_PIX_FMT_YVU420:
>  		(*main_output_format) = 
VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
>  		break;
> +	/* RAW8 */
> +	case V4L2_PIX_FMT_SBGGR8:
> +	case V4L2_PIX_FMT_SGBRG8:
> +	case V4L2_PIX_FMT_SGRBG8:
> +	case V4L2_PIX_FMT_SRGGB8:
> +	/* RAW10 */
> +	case V4L2_PIX_FMT_SBGGR10:
> +	case V4L2_PIX_FMT_SGBRG10:
> +	case V4L2_PIX_FMT_SGRBG10:
> +	case V4L2_PIX_FMT_SRGGB10:
> +		(*main_output_format) = 
VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
> +		break;
>  	}
>  }
> 
> @@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct
> tegra_vi_channel *chan) case V4L2_PIX_FMT_VYUY:
>  	case V4L2_PIX_FMT_YUYV:
>  	case V4L2_PIX_FMT_YVYU:
> +	/* RAW8 */
> +	case V4L2_PIX_FMT_SRGGB8:
> +	case V4L2_PIX_FMT_SGRBG8:
> +	case V4L2_PIX_FMT_SGBRG8:
> +	case V4L2_PIX_FMT_SBGGR8:
> +	/* RAW10 */
> +	case V4L2_PIX_FMT_SRGGB10:
> +	case V4L2_PIX_FMT_SGRBG10:
> +	case V4L2_PIX_FMT_SGBRG10:
> +	case V4L2_PIX_FMT_SBGGR10:
>  		if (chan->vflip)
>  			chan->start_offset += stride * (height - 1);
>  		if (chan->hflip)
> @@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct
> tegra_vi_channel *chan, tegra20_vi_write(chan,
> TEGRA_VI_VB0_BASE_ADDRESS(OUT_1),  base); tegra20_vi_write(chan,
> TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
> +	/* RAW8 */
> +	case V4L2_PIX_FMT_SRGGB8:
> +	case V4L2_PIX_FMT_SGRBG8:
> +	case V4L2_PIX_FMT_SGBRG8:
> +	case V4L2_PIX_FMT_SBGGR8:
> +	/* RAW10 */
> +	case V4L2_PIX_FMT_SRGGB10:
> +	case V4L2_PIX_FMT_SGRBG10:
> +	case V4L2_PIX_FMT_SGBRG10:
> +	case V4L2_PIX_FMT_SBGGR10:
> +		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2),  
base);
> +		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2), 
base +
> chan->start_offset); +		break;
>  	}
>  }
> 
> @@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void
> *data) static void tegra20_camera_capture_setup(struct tegra_vi_channel
> *chan) {
>  	u32 output_fourcc = chan->format.pixelformat;
> +	u32 data_type = chan->fmtinfo->img_dt;
>  	int width  = chan->format.width;
>  	int height = chan->format.height;
>  	int stride_l = chan->format.bytesperline;
>  	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
>  			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> -	int output_channel = OUT_1;
> +	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> +			      data_type == TEGRA_IMAGE_DT_RAW10) ?
> +			      OUT_2 : OUT_1;
>  	int main_output_format;
>  	int yuv_output_format;
> 
> @@ -580,6 +630,20 @@ static const struct tegra_video_format
> tegra20_video_formats[] = { TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16,
> YVYU),
>  	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
>  	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
> +	TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
> +	TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
> +	TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
> +	TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
> +	/* RAW 8 */
> +	TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
> +	TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
> +	TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
> +	TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
> +	/* RAW 10 */
> +	TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
> +	TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
> +	TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
> +	TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
>  };
> 
>  const struct tegra_vi_soc tegra20_vi_soc = {
> @@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
>  static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
>  {
>  	struct tegra_vi_channel *vi_chan =
> v4l2_get_subdev_hostdata(&vip_chan->subdev); +	u32 data_type =
> vi_chan->fmtinfo->img_dt;
>  	int width  = vi_chan->format.width;
>  	int height = vi_chan->format.height;
> -	int output_channel = OUT_1;
> +	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> +			      data_type == TEGRA_IMAGE_DT_RAW10) ?
> +			      OUT_2 : OUT_1;
> 
>  	unsigned int main_input_format;
>  	unsigned int yuv_input_format;





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride
  2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
@ 2025-09-02  1:16   ` Mikko Perttunen
  0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  1:16 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Luma buffer stride is calculated by multiplying height in pixels of image
> by bytes per line. Adjust that value accordingly.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/tegra20.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> b466fe7f4504..a06afe91d2de 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -496,7 +496,7 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) u32 data_type = chan->fmtinfo->img_dt;
>  	int width  = chan->format.width;
>  	int height = chan->format.height;
> -	int stride_l = chan->format.bytesperline;
> +	int stride_l = chan->format.bytesperline * height;
>  	int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
>  			output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
>  	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||

Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>




^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
@ 2025-09-02  2:38   ` Mikko Perttunen
  2025-09-02  5:51     ` Svyatoslav Ryhel
  2025-09-02  7:11     ` Dan Carpenter
  0 siblings, 2 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  2:38 UTC (permalink / raw)
  To: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
  Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
	linux-clk, linux-staging

On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> 
> Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/csi.c     |  12 +
>  drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
>  drivers/staging/media/tegra-video/vi.h      |   2 +
>  drivers/staging/media/tegra-video/video.c   |   2 +
>  4 files changed, 553 insertions(+), 38 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index 2f9907a20db1..714ce52a793c 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
>  	pm_runtime_disable(&pdev->dev);
>  }
>  
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +extern const struct tegra_csi_soc tegra20_csi_soc;
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +extern const struct tegra_csi_soc tegra30_csi_soc;
> +#endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>  extern const struct tegra_csi_soc tegra210_csi_soc;
>  #endif
>  
>  static const struct of_device_id tegra_csi_of_id_table[] = {
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +	{ .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> +#endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>  	{ .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
>  #endif
> diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> index a06afe91d2de..e528ba280ae4 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -4,6 +4,9 @@
>   *
>   * Copyright (C) 2023 SKIDATA GmbH
>   * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> + *
> + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
>   */
>  
>  /*
> @@ -12,12 +15,16 @@
>   */
>  
>  #include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk/tegra.h>
>  #include <linux/delay.h>
>  #include <linux/host1x.h>
> +#include <linux/iopoll.h>
>  #include <linux/kernel.h>
>  #include <linux/kthread.h>
>  #include <linux/v4l2-mediabus.h>
>  
> +#include "csi.h"
>  #include "vip.h"
>  #include "vi.h"
>  
> @@ -42,6 +49,9 @@ enum {
>  #define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT	BIT(8)
>  #define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT		0
>  
> +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n)	(0x0070 + (n) * 8)
> +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n)	(0x0074 + (n) * 8)
> +
>  #define TEGRA_VI_VI_INPUT_CONTROL			0x0088
>  #define       VI_INPUT_FIELD_DETECT			BIT(27)
>  #define       VI_INPUT_BT656				BIT(25)
> @@ -87,6 +97,8 @@ enum {
>  #define       VI_OUTPUT_OUTPUT_FORMAT_SFT		0
>  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST	(3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
>  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR	(6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER	(7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER	(8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
>  #define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT	(9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
>  
>  #define TEGRA_VI_VIP_H_ACTIVE				0x00a4
> @@ -151,8 +163,106 @@ enum {
>  #define TEGRA_VI_VI_RAISE				0x01ac
>  #define       VI_VI_RAISE_ON_EDGE			BIT(0)
>  
> +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n)		(0x01d8 + (n) * 8)
> +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n)		(0x01dc + (n) * 8)
> +#define TEGRA_VI_CSI_PP_H_ACTIVE(n)			(0x01e8 + (n) * 8)
> +#define TEGRA_VI_CSI_PP_V_ACTIVE(n)			(0x01ec + (n) * 8)
> +
> +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL		0x0000
> +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL		0x0008
> +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n)		(0x0010 + (n) * 0x2c)
> +#define       CSI_SKIP_PACKET_THRESHOLD(n)		(((n) & 0xff) << 16)
> +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n)		(0x0018 + (n) * 0x2c)
> +#define       CSI_PP_PAD_FRAME_PAD0S			(0 << 28)
> +#define       CSI_PP_PAD_FRAME_PAD1S			(1 << 28)
> +#define       CSI_PP_PAD_FRAME_NOPAD			(2 << 28)
> +#define       CSI_PP_HEADER_EC_ENABLE			BIT(27)
> +#define       CSI_PP_PAD_SHORT_LINE_PAD0S		(0 << 24)
> +#define       CSI_PP_PAD_SHORT_LINE_PAD1S		(1 << 24)
> +#define       CSI_PP_PAD_SHORT_LINE_NOPAD		(2 << 24)
> +#define       CSI_PP_EMBEDDED_DATA_EMBEDDED		BIT(20)
> +#define       CSI_PP_OUTPUT_FORMAT_ARBITRARY		(0 << 16)
> +#define       CSI_PP_OUTPUT_FORMAT_PIXEL		(1 << 16)
> +#define       CSI_PP_OUTPUT_FORMAT_PIXEL_REP		(2 << 16)
> +#define       CSI_PP_OUTPUT_FORMAT_STORE		(3 << 16)
> +#define       CSI_PP_VIRTUAL_CHANNEL_ID(n)		(((n) - 1) << 14)
> +#define       CSI_PP_DATA_TYPE(n)			((n) << 8)
> +#define       CSI_PP_CRC_CHECK_ENABLE			BIT(7)
> +#define       CSI_PP_WORD_COUNT_HEADER			BIT(6)
> +#define       CSI_PP_DATA_IDENTIFIER_ENABLE		BIT(5)
> +#define       CSI_PP_PACKET_HEADER_SENT			BIT(4)
> +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n)		(0x001c + (n) * 0x2c)
> +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n)		(0x0020 + (n) * 0x2c)
> +#define TEGRA_CSI_PIXEL_STREAM_GAP(n)			(0x0024 + (n) * 0x2c)
> +#define       CSI_PP_FRAME_MIN_GAP(n)			(((n) & 0xffff) << 16)
> +#define       CSI_PP_LINE_MIN_GAP(n)			(((n) & 0xffff))
> +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n)		(0x0028 + (n) * 0x2c)
> +#define       CSI_PP_START_MARKER_FRAME_MAX(n)		(((n) & 0xf) << 12)
> +#define       CSI_PP_START_MARKER_FRAME_MIN(n)		(((n) & 0xf) << 8)
> +#define       CSI_PP_VSYNC_START_MARKER			BIT(4)
> +#define       CSI_PP_SINGLE_SHOT			BIT(2)
> +#define       CSI_PP_NOP				0
> +#define       CSI_PP_ENABLE				1
> +#define       CSI_PP_DISABLE				2
> +#define       CSI_PP_RST				3
> +#define TEGRA_CSI_PHY_CIL_COMMAND			0x0068
> +#define       CSI_A_PHY_CIL_NOP				0x0
> +#define       CSI_A_PHY_CIL_ENABLE			0x1
> +#define       CSI_A_PHY_CIL_DISABLE			0x2
> +#define       CSI_A_PHY_CIL_ENABLE_MASK			0x3
> +#define       CSI_B_PHY_CIL_NOP				(0x0 << 16)
> +#define       CSI_B_PHY_CIL_ENABLE			(0x1 << 16)
> +#define       CSI_B_PHY_CIL_DISABLE			(0x2 << 16)
> +#define       CSI_B_PHY_CIL_ENABLE_MASK			(0x3 << 16)
> +#define TEGRA_CSI_PHY_CIL_CONTROL0(n)			(0x006c + (n) * 4)
> +#define       CSI_CONTINUOUS_CLOCK_MODE_ENABLE		BIT(5)
> +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS		0x0078
> +#define TEGRA_CSI_CSI_CIL_STATUS			0x007c
> +#define       CSI_MIPI_AUTO_CAL_DONE			BIT(15)
> +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK	0x0080
> +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK		0x0084
> +#define TEGRA_CSI_CSI_READONLY_STATUS			0x0088
> +#define TEGRA_CSI_ESCAPE_MODE_COMMAND			0x008c
> +#define TEGRA_CSI_ESCAPE_MODE_DATA			0x0090
> +#define TEGRA_CSI_CIL_PAD_CONFIG0(n)			(0x0094 + (n) * 8)
> +#define TEGRA_CSI_CIL_PAD_CONFIG1(n)			(0x0098 + (n) * 8)
> +#define TEGRA_CSI_CIL_PAD_CONFIG			0x00a4
> +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG			0x00a8
> +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG			0x00ac
> +#define       CSI_CIL_MIPI_CAL_STARTCAL			BIT(31)
> +#define       CSI_CIL_MIPI_CAL_OVERIDE_A		BIT(30)
> +#define       CSI_CIL_MIPI_CAL_OVERIDE_B		BIT(30)
> +#define       CSI_CIL_MIPI_CAL_NOISE_FLT(n)		(((n) & 0xf) << 26)
> +#define       CSI_CIL_MIPI_CAL_PRESCALE(n)		(((n) & 0x3) << 24)
> +#define       CSI_CIL_MIPI_CAL_SEL_A			BIT(21)
> +#define       CSI_CIL_MIPI_CAL_SEL_B			BIT(21)
> +#define       CSI_CIL_MIPI_CAL_HSPDOS(n)		(((n) & 0x1f) << 16)
> +#define       CSI_CIL_MIPI_CAL_HSPUOS(n)		(((n) & 0x1f) << 8)
> +#define       CSI_CIL_MIPI_CAL_TERMOS(n)		(((n) & 0x1f))
> +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS			0x00b0
> +#define TEGRA_CSI_CLKEN_OVERRIDE			0x00b4
> +#define TEGRA_CSI_DEBUG_CONTROL				0x00b8
> +#define       CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED	BIT(0)
> +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0		BIT(4)
> +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1		BIT(5)
> +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2		BIT(6)
> +#define       CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v)	((v) << (8 + 8 * (n)))
> +#define TEGRA_CSI_DEBUG_COUNTER(n)			(0x00bc + (n) * 4)
> +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n)	(0x00c8 + (n) * 4)
> +#define       CSI_PP_EXP_FRAME_HEIGHT(n)		(((n) & 0x1fff) << 16)
> +#define       CSI_PP_MAX_CLOCKS(n)			(((n) & 0xfff) << 4)
> +#define       CSI_PP_LINE_TIMEOUT_ENABLE		BIT(0)
> +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG			0x00d0
> +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0			0x00d4
> +#define       CSI_PAD_DRIV_DN_REF(n)			(((n) & 0x7) << 16)
> +#define       CSI_PAD_DRIV_UP_REF(n)			(((n) & 0x7) << 8)
> +#define       CSI_PAD_TERM_REF(n)			(((n) & 0x7) << 0)
> +#define TEGRA_CSI_CSI_CILA_STATUS			0x00d8
> +#define TEGRA_CSI_CSI_CILB_STATUS			0x00dc
> +
>  /* --------------------------------------------------------------------------
> - * VI
> + * Read and Write helpers
>   */
>  
>  static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
>  	writel(val, chan->vi->iomem + addr);
>  }
>  
> +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> +{
> +	return readl(chan->vi->iomem + addr);
> +}
> +
> +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> +{
> +	writel(val, csi_chan->csi->iomem + addr);
> +}
> +
> +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> +{
> +	return readl(csi_chan->csi->iomem + addr);
> +}
> +
> +/* --------------------------------------------------------------------------
> + * VI
> + */
> +
>  /*
>   * Get the main input format (YUV/RGB...) and the YUV variant as values to
>   * be written into registers for the current VI input mbus code.
> @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
>  static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
>  {
>  	struct tegra_vi *vi = chan->vi;
> -	struct host1x_syncpt *out_sp;
> +	struct host1x_syncpt *out_sp, *fs_sp;
>  
>  	out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
>  	if (!out_sp)
> -		return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> +		return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");

Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?

>  
>  	chan->mw_ack_sp[0] = out_sp;
>  
> +	fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> +	if (!fs_sp)
> +		return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> +
> +	chan->frame_start_sp[0] = fs_sp;
> +
>  	return 0;
>  }
>  
>  static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
>  {
>  	host1x_syncpt_put(chan->mw_ack_sp[0]);
> +	host1x_syncpt_put(chan->frame_start_sp[0]);
>  }
>  
>  static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
>  static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
>  					 struct tegra_channel_buffer *buf)
>  {
> +	struct v4l2_subdev *csi_subdev = NULL;
> +	struct tegra_csi_channel *csi_chan = NULL;
> +	u32 port;
>  	int err;
>  
> -	chan->next_out_sp_idx++;
> +	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> +	if (csi_subdev) {
> +		/* CSI subdevs are named after nodes, channel@0 or channel@1 */
> +		if (!strncmp(csi_subdev->name, "channel", 7)) {
> +			csi_chan = to_csi_chan(csi_subdev);
> +			port = csi_chan->csi_port_nums[0] & 1;
> +		}
> +	}

tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.

Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?

Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?

>  
>  	tegra20_channel_vi_buffer_setup(chan, buf);
>  
> -	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> +	if (csi_chan) {
> +		tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> +				  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> +				  CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> +
> +		chan->next_fs_sp_idx++;
> +		err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> +					 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> +		if (err) {
> +			host1x_syncpt_incr(chan->frame_start_sp[0]);

This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.

Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.

(I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)

> +			if (err != -ERESTARTSYS)
> +				dev_err_ratelimited(&chan->video.dev,
> +						    "frame start syncpt timeout: %d\n", err);
> +		}
> +
> +		tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> +				  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> +				  CSI_PP_DISABLE);
> +	} else {
> +		tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> +	}
>  
> -	/* Wait for syncpt counter to reach frame start event threshold */
> +	chan->next_out_sp_idx++;
>  	err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
>  				 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
>  	if (err) {
>  		host1x_syncpt_incr(chan->mw_ack_sp[0]);
> -		dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> -		release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> -		return err;
> +		if (err != -ERESTARTSYS)
> +			dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
>  	}
>  
> -	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> -			 VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> +	if (!csi_chan)
> +		tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> +				 VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
>  
>  	release_buffer(chan, buf, VB2_BUF_STATE_DONE);
>  
> -	return 0;
> +	return err;
>  }
>  
>  static int tegra20_chan_capture_kthread_start(void *data)
> @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
>  	int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
>  			      data_type == TEGRA_IMAGE_DT_RAW10) ?
>  			      OUT_2 : OUT_1;
> -	int main_output_format;
> -	int yuv_output_format;
> -
> -	tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> -
> -	/*
> -	 * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> -	 * for luminance, which is the default and means not to touch
> -	 * anything.
> -	 */
> -	tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> -			 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> -			 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> -
> -	/* Set up raise-on-edge, so we get an interrupt on end of frame. */
> -	tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> -
> -	tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> -			 (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> -			 (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> -			 yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> -			 main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
>  
>  	/* Set up frame size */
>  	tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
>  	tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
>  }
>  
> +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> +{
> +	struct tegra_csi *csi = csi_chan->csi;
> +	void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> +	unsigned int port = csi_chan->csi_port_nums[0] & 1;
> +	u32 value, pp, cil;
> +	int ret;
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> +			  CSI_CIL_MIPI_CAL_HSPDOS(4) |
> +			  CSI_CIL_MIPI_CAL_HSPUOS(3) |
> +			  CSI_CIL_MIPI_CAL_TERMOS(0));
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> +			  CSI_PAD_DRIV_DN_REF(5) |
> +			  CSI_PAD_DRIV_UP_REF(7) |
> +			  CSI_PAD_TERM_REF(0));
> +
> +	/* CSI B */
> +	value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> +		CSI_CIL_MIPI_CAL_HSPUOS(0) |
> +		CSI_CIL_MIPI_CAL_TERMOS(4);
> +
> +	if (port == PORT_B || csi_chan->numlanes == 4)
> +		value |= CSI_CIL_MIPI_CAL_SEL_B;
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> +
> +	/* CSI A */
> +	value = CSI_CIL_MIPI_CAL_STARTCAL |
> +		CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> +		CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> +		CSI_CIL_MIPI_CAL_HSPDOS(0) |
> +		CSI_CIL_MIPI_CAL_HSPUOS(0) |
> +		CSI_CIL_MIPI_CAL_TERMOS(4);
> +
> +	if (port == PORT_A)
> +		value |= CSI_CIL_MIPI_CAL_SEL_A;
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> +
> +	ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> +					 value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> +	if (ret < 0) {
> +		dev_warn(csi->dev, "MIPI calibration timeout!\n");
> +		goto exit;
> +	}
> +
> +	/* clear status */
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> +	ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> +					 !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> +	if (ret < 0) {
> +		dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> +		goto exit;
> +	}
> +
> +	pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> +	cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> +	if (pp | cil) {
> +		dev_warn(csi->dev, "Calibration status not been cleared!\n");
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +exit:
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> +
> +	/* un-select to avoid interference with DSI */
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> +			  CSI_CIL_MIPI_CAL_HSPDOS(0) |
> +			  CSI_CIL_MIPI_CAL_HSPUOS(0) |
> +			  CSI_CIL_MIPI_CAL_TERMOS(4));
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> +			  CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> +			  CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> +			  CSI_CIL_MIPI_CAL_HSPDOS(0) |
> +			  CSI_CIL_MIPI_CAL_HSPUOS(0) |
> +			  CSI_CIL_MIPI_CAL_TERMOS(4));
> +
> +	return ret;
> +}
> +
>  static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
>  {
>  	struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
>  	struct media_pipeline *pipe = &chan->video.pipe;
> +	struct v4l2_subdev *csi_subdev, *src_subdev;
> +	struct tegra_csi_channel *csi_chan = NULL;
>  	int err;
>  
> +	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> +	if (csi_subdev) {
> +		if (!strncmp(csi_subdev->name, "channel", 7))
> +			csi_chan = to_csi_chan(csi_subdev);
> +	}
> +
> +	chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
>  	chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
>  
>  	err = video_device_pipeline_start(&chan->video, pipe);
>  	if (err)
>  		goto error_pipeline_start;
>  
> -	tegra20_camera_capture_setup(chan);
> +	/*
> +	 * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> +	 * for luminance, which is the default and means not to touch
> +	 * anything.
> +	 */
> +	tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> +			 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> +			 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> +
> +	/* Set up raise-on-edge, so we get an interrupt on end of frame. */
> +	tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
>  
>  	err = tegra_channel_set_stream(chan, true);
>  	if (err)
>  		goto error_set_stream;
>  
> +	tegra20_camera_capture_setup(chan);
> +
> +	if (csi_chan) {
> +		/*
> +		 * TRM has incorrectly documented to wait for done status from
> +		 * calibration logic after CSI interface power on.
> +		 * As per the design, calibration results are latched and applied
> +		 * to the pads only when the link is in LP11 state which will happen
> +		 * during the sensor stream-on.
> +		 * CSI subdev stream-on triggers start of MIPI pads calibration.
> +		 * Wait for calibration to finish here after sensor subdev stream-on.
> +		 */
> +		src_subdev = tegra_channel_get_remote_source_subdev(chan);
> +		if (!src_subdev->s_stream_enabled) {
> +			err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> +			if (err < 0 && err != -ENOIOCTLCMD)
> +				goto error_set_stream;
> +		}
> +
> +		tegra20_csi_pad_calibration(csi_chan);
> +	}
> +
>  	chan->sequence = 0;
>  
>  	chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
>  static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
>  {
>  	struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> +	struct v4l2_subdev *src_subdev;
>  
>  	if (chan->kthread_start_capture) {
>  		kthread_stop(chan->kthread_start_capture);
>  		chan->kthread_start_capture = NULL;
>  	}
>  
> +	src_subdev = tegra_channel_get_remote_source_subdev(chan);
> +	if (src_subdev->s_stream_enabled)
> +		v4l2_subdev_call(src_subdev, video, s_stream, false);
> +
>  	tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
>  	tegra_channel_set_stream(chan, false);
>  	video_device_pipeline_stop(&chan->video);
> @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
>  	.default_video_format = &tegra20_video_formats[0],
>  	.ops = &tegra20_vi_ops,
>  	.hw_revision = 1,
> -	.vi_max_channels = 1, /* parallel input (VIP) */
> +	.vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
>  	.vi_max_clk_hz = 450000000,
>  	.has_h_v_flip = true,
>  };
>  
> +/* --------------------------------------------------------------------------
> + * CSI
> + */
> +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> +{
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> +			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> +			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> +			  CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> +}
> +
> +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> +					    u8 portno)
> +{
> +	struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> +	int width  = vi_chan->format.width;
> +	int height = vi_chan->format.height;
> +	u32 data_type = vi_chan->fmtinfo->img_dt;
> +	u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> +	int output_channel = OUT_1;
> +
> +	unsigned int main_output_format, yuv_output_format;
> +	unsigned int port = portno & 1;
> +	u32 value;
> +
> +	tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> +
> +	switch (data_type) {
> +	case TEGRA_IMAGE_DT_RAW8:
> +	case TEGRA_IMAGE_DT_RAW10:
> +		output_channel = OUT_2;
> +		if (port == PORT_A)
> +			main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> +		else
> +			main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> +		break;
> +	}
> +
> +	tegra20_csi_capture_clean(csi_chan);
> +
> +	/* CSI port cleanup */
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> +	tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> +	tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> +			  CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> +			  CSI_PP_EXP_FRAME_HEIGHT(height) |
> +			  CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> +			  CSI_PP_LINE_TIMEOUT_ENABLE);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> +			  CSI_PP_OUTPUT_FORMAT_PIXEL |
> +			  CSI_PP_DATA_TYPE(data_type) |
> +			  CSI_PP_CRC_CHECK_ENABLE |
> +			  CSI_PP_WORD_COUNT_HEADER |
> +			  CSI_PP_DATA_IDENTIFIER_ENABLE |
> +			  CSI_PP_PACKET_HEADER_SENT |
> +			  port);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> +			  CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> +			  (csi_chan->numlanes - 1));
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> +			  CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> +			  0x5); /* Clock settle time */
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> +			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> +			 host1x_syncpt_id(vi_chan->frame_start_sp[0])
> +			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> +			 VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> +			 host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> +			 << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> +
> +	value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> +		CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> +			  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> +			  CSI_PP_DISABLE);
> +
> +	tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> +			 (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> +			 (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> +			 yuv_output_format | main_output_format);
> +
> +	return 0;
> +};
> +
> +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> +{
> +	struct tegra_csi *csi = csi_chan->csi;
> +	unsigned int port = portno & 1;
> +	u32 value;
> +
> +	value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> +	dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> +
> +	value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> +	dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> +
> +	tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> +			  CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> +			  CSI_PP_DISABLE);
> +
> +	if (csi_chan->numlanes == 4) {
> +		tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> +				  CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> +	} else {
> +		value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> +			CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> +		tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> +	}
> +}
> +
> +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> +{
> +	u8 *portnos = csi_chan->csi_port_nums;
> +	int ret, i;
> +
> +	for (i = 0; i < csi_chan->numgangports; i++) {
> +		ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> +		if (ret)
> +			goto stream_start_fail;
> +	}
> +
> +	return 0;
> +
> +stream_start_fail:
> +	for (i = i - 1; i >= 0; i--)
> +		tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> +
> +	return ret;
> +}
> +
> +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> +{
> +	u8 *portnos = csi_chan->csi_port_nums;
> +	int i;
> +
> +	for (i = 0; i < csi_chan->numgangports; i++)
> +		tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> +}
> +
> +/* Tegra20 CSI operations */
> +static const struct tegra_csi_ops tegra20_csi_ops = {
> +	.csi_start_streaming = tegra20_csi_start_streaming,
> +	.csi_stop_streaming = tegra20_csi_stop_streaming,
> +};
> +
> +static const char * const tegra20_csi_clks[] = {
> +	"csi",
> +};
> +
> +/* Tegra20 CSI SoC data */
> +const struct tegra_csi_soc tegra20_csi_soc = {
> +	.ops = &tegra20_csi_ops,
> +	.csi_max_channels = 2, /* CSI-A and CSI-B */
> +	.clk_names = tegra20_csi_clks,
> +	.num_clks = ARRAY_SIZE(tegra20_csi_clks),
> +	.has_mipi_calibration = false,
> +};
> +
> +static const char * const tegra30_csi_clks[] = {
> +	"csi",
> +	"csia_pad",
> +	"csib_pad",
> +};
> +
> +/* Tegra30 CSI SoC data */
> +const struct tegra_csi_soc tegra30_csi_soc = {
> +	.ops = &tegra20_csi_ops,
> +	.csi_max_channels = 2, /* CSI-A and CSI-B */
> +	.clk_names = tegra30_csi_clks,
> +	.num_clks = ARRAY_SIZE(tegra30_csi_clks),
> +	.has_mipi_calibration = false,
> +};
> +
>  /* --------------------------------------------------------------------------
>   * VIP
>   */
> @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
>  			      data_type == TEGRA_IMAGE_DT_RAW10) ?
>  			      OUT_2 : OUT_1;
>  
> -	unsigned int main_input_format;
> -	unsigned int yuv_input_format;
> +	unsigned int main_input_format, yuv_input_format;
> +	unsigned int main_output_format, yuv_output_format;
>  
>  	tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> +	tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
>  
>  	tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
>  
> @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
>  
>  	tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
>  
> +	tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> +			 (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> +			 (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> +			  yuv_output_format | main_output_format);
> +
>  	return 0;
>  }
>  
> diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> index cac0c0d0e225..c02517c9e09b 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -127,6 +127,7 @@ struct tegra_vi {
>   *		frame through host1x syncpoint counters (On Tegra20 used for the
>   *              OUT_1 syncpt)
>   * @sp_incr_lock: protects cpu syncpoint increment.
> + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
>   * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
>   *
>   * @kthread_start_capture: kthread to start capture of single frame when
> @@ -191,6 +192,7 @@ struct tegra_vi_channel {
>  	/* protects the cpu syncpoint increment */
>  	spinlock_t sp_incr_lock[GANG_PORTS_MAX];
>  	u32 next_out_sp_idx;
> +	u32 next_fs_sp_idx;
>  
>  	struct task_struct *kthread_start_capture;
>  	wait_queue_head_t start_wait;
> diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> index a25885f93cd7..8fa660431eb0 100644
> --- a/drivers/staging/media/tegra-video/video.c
> +++ b/drivers/staging/media/tegra-video/video.c
> @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
>  
>  static const struct of_device_id host1x_video_subdevs[] = {
>  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +	{ .compatible = "nvidia,tegra20-csi", },
>  	{ .compatible = "nvidia,tegra20-vip", },
>  	{ .compatible = "nvidia,tegra20-vi", },
>  #endif
>  #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-csi", },
>  	{ .compatible = "nvidia,tegra30-vip", },
>  	{ .compatible = "nvidia,tegra30-vi", },
>  #endif
> 





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
  2025-09-02  0:46   ` Mikko Perttunen
@ 2025-09-02  5:05     ` Svyatoslav Ryhel
  2025-09-02  6:35       ` Mikko Perttunen
  0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02  5:05 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 2 вер. 2025 р. о 03:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> > all MIPI calibration pads were part of VI block.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/staging/media/tegra-video/csi.c      | 12 +++++++-----
> >  drivers/staging/media/tegra-video/csi.h      |  1 +
> >  drivers/staging/media/tegra-video/tegra210.c |  1 +
> >  3 files changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c
> > b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> > 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> > *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
> >               return 0;
> >
> > -     chan->mipi = tegra_mipi_request(csi->dev, node);
> > -     if (IS_ERR(chan->mipi)) {
> > -             ret = PTR_ERR(chan->mipi);
> > -             chan->mipi = NULL;
> > -             dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> > +     if (csi->soc->has_mipi_calibration) {
> > +             chan->mipi = tegra_mipi_request(csi->dev, node);
>
> The way I would read 'soc->has_mipi_calibration' is that this device (CSI)
> contains the MIPI calibration hardware. I.e. the opposite of here. I would
> invert the logic and optionally call it e.g. 'internal_mipi_calib'.
>
> A cleaner way to do this might be to always call tegra_mipi_request et al. --
> on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the
> callbacks registered in the MIPI driver as we discussed before. That way the
> CSI driver won't need separate code paths for SoCs with internal MIPI
> calibration and SoCs with the external MIPI calibration device.
>

So basically MIPI calibration device for Tegra20/Tegra30 has to be
created within CSI and when MIPI calibration is requested, CSI phandle
is used. Question: may I use a dedicated node for MIPI calibration
within CSI or it has to use CSI node itself? With dedicated node
configuration should be much simpler and can help avoiding probe of
entire.

> Cheers,
> Mikko
>
> > +             if (IS_ERR(chan->mipi)) {
> > +                     ret = PTR_ERR(chan->mipi);
> > +                     chan->mipi = NULL;
> > +                     dev_err(csi->dev, "failed to get mipi device:
> %d\n", ret);
> > +             }
> >       }
> >
> >       return ret;
> > diff --git a/drivers/staging/media/tegra-video/csi.h
> > b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> > 100644
> > --- a/drivers/staging/media/tegra-video/csi.h
> > +++ b/drivers/staging/media/tegra-video/csi.h
> > @@ -128,6 +128,7 @@ struct tegra_csi_soc {
> >       unsigned int num_clks;
> >       const struct tpg_framerate *tpg_frmrate_table;
> >       unsigned int tpg_frmrate_table_size;
> > +     bool has_mipi_calibration;
> >  };
> >
> >  /**
> > diff --git a/drivers/staging/media/tegra-video/tegra210.c
> > b/drivers/staging/media/tegra-video/tegra210.c index
> > da99f19a39e7..305472e94af4 100644
> > --- a/drivers/staging/media/tegra-video/tegra210.c
> > +++ b/drivers/staging/media/tegra-video/tegra210.c
> > @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
> >       .num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
> >       .tpg_frmrate_table = tegra210_tpg_frmrate_table,
> >       .tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> > +     .has_mipi_calibration = true,
> >  };
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
  2025-09-02  1:09   ` Mikko Perttunen
@ 2025-09-02  5:11     ` Svyatoslav Ryhel
  0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02  5:11 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 2 вер. 2025 р. о 04:10 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
> > of existing YUV422_8 2X8.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
> >  1 file changed, 69 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/tegra20.c
> > b/drivers/staging/media/tegra-video/tegra20.c index
> > 67631e0c9ffc..b466fe7f4504 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct
> > tegra_vi_channel *chan, case MEDIA_BUS_FMT_YVYU8_2X8:
> >               (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
> >               break;
> > +     /* RAW8 */
> > +     case MEDIA_BUS_FMT_SBGGR8_1X8:
> > +     case MEDIA_BUS_FMT_SGBRG8_1X8:
> > +     case MEDIA_BUS_FMT_SGRBG8_1X8:
> > +     case MEDIA_BUS_FMT_SRGGB8_1X8:
> > +     /* RAW10 */
> > +     case MEDIA_BUS_FMT_SBGGR10_1X10:
> > +     case MEDIA_BUS_FMT_SGBRG10_1X10:
> > +     case MEDIA_BUS_FMT_SGRBG10_1X10:
> > +     case MEDIA_BUS_FMT_SRGGB10_1X10:
> > +             (*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
>
> Should this be main_input_format instead of yuv_input_format?
>

Yes, it should be main_input_format, you are correct. Thank you.

> > +             break;
> >       }
> >  }
> >
> > @@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct
> > tegra_vi_channel *chan, case V4L2_PIX_FMT_YVU420:
> >               (*main_output_format) =
> VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
> >               break;
> > +     /* RAW8 */
> > +     case V4L2_PIX_FMT_SBGGR8:
> > +     case V4L2_PIX_FMT_SGBRG8:
> > +     case V4L2_PIX_FMT_SGRBG8:
> > +     case V4L2_PIX_FMT_SRGGB8:
> > +     /* RAW10 */
> > +     case V4L2_PIX_FMT_SBGGR10:
> > +     case V4L2_PIX_FMT_SGBRG10:
> > +     case V4L2_PIX_FMT_SGRBG10:
> > +     case V4L2_PIX_FMT_SRGGB10:
> > +             (*main_output_format) =
> VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
> > +             break;
> >       }
> >  }
> >
> > @@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct
> > tegra_vi_channel *chan) case V4L2_PIX_FMT_VYUY:
> >       case V4L2_PIX_FMT_YUYV:
> >       case V4L2_PIX_FMT_YVYU:
> > +     /* RAW8 */
> > +     case V4L2_PIX_FMT_SRGGB8:
> > +     case V4L2_PIX_FMT_SGRBG8:
> > +     case V4L2_PIX_FMT_SGBRG8:
> > +     case V4L2_PIX_FMT_SBGGR8:
> > +     /* RAW10 */
> > +     case V4L2_PIX_FMT_SRGGB10:
> > +     case V4L2_PIX_FMT_SGRBG10:
> > +     case V4L2_PIX_FMT_SGBRG10:
> > +     case V4L2_PIX_FMT_SBGGR10:
> >               if (chan->vflip)
> >                       chan->start_offset += stride * (height - 1);
> >               if (chan->hflip)
> > @@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct
> > tegra_vi_channel *chan, tegra20_vi_write(chan,
> > TEGRA_VI_VB0_BASE_ADDRESS(OUT_1),  base); tegra20_vi_write(chan,
> > TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
> > +     /* RAW8 */
> > +     case V4L2_PIX_FMT_SRGGB8:
> > +     case V4L2_PIX_FMT_SGRBG8:
> > +     case V4L2_PIX_FMT_SGBRG8:
> > +     case V4L2_PIX_FMT_SBGGR8:
> > +     /* RAW10 */
> > +     case V4L2_PIX_FMT_SRGGB10:
> > +     case V4L2_PIX_FMT_SGRBG10:
> > +     case V4L2_PIX_FMT_SGBRG10:
> > +     case V4L2_PIX_FMT_SBGGR10:
> > +             tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2),
> base);
> > +             tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2),
> base +
> > chan->start_offset); +                break;
> >       }
> >  }
> >
> > @@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void
> > *data) static void tegra20_camera_capture_setup(struct tegra_vi_channel
> > *chan) {
> >       u32 output_fourcc = chan->format.pixelformat;
> > +     u32 data_type = chan->fmtinfo->img_dt;
> >       int width  = chan->format.width;
> >       int height = chan->format.height;
> >       int stride_l = chan->format.bytesperline;
> >       int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
> >                       output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> > -     int output_channel = OUT_1;
> > +     int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > +                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > +                           OUT_2 : OUT_1;
> >       int main_output_format;
> >       int yuv_output_format;
> >
> > @@ -580,6 +630,20 @@ static const struct tegra_video_format
> > tegra20_video_formats[] = { TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16,
> > YVYU),
> >       TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
> >       TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
> > +     TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
> > +     TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
> > +     TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
> > +     TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
> > +     /* RAW 8 */
> > +     TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
> > +     TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
> > +     TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
> > +     TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
> > +     /* RAW 10 */
> > +     TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
> > +     TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
> > +     TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
> > +     TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
> >  };
> >
> >  const struct tegra_vi_soc tegra20_vi_soc = {
> > @@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> >  static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >  {
> >       struct tegra_vi_channel *vi_chan =
> > v4l2_get_subdev_hostdata(&vip_chan->subdev); +        u32 data_type =
> > vi_chan->fmtinfo->img_dt;
> >       int width  = vi_chan->format.width;
> >       int height = vi_chan->format.height;
> > -     int output_channel = OUT_1;
> > +     int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > +                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > +                           OUT_2 : OUT_1;
> >
> >       unsigned int main_input_format;
> >       unsigned int yuv_input_format;
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-02  2:38   ` Mikko Perttunen
@ 2025-09-02  5:51     ` Svyatoslav Ryhel
  2025-09-02  6:17       ` Mikko Perttunen
  2025-09-02  7:11     ` Dan Carpenter
  1 sibling, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02  5:51 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> >
> > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/staging/media/tegra-video/csi.c     |  12 +
> >  drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> >  drivers/staging/media/tegra-video/vi.h      |   2 +
> >  drivers/staging/media/tegra-video/video.c   |   2 +
> >  4 files changed, 553 insertions(+), 38 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > index 2f9907a20db1..714ce52a793c 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> >       pm_runtime_disable(&pdev->dev);
> >  }
> >
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > +#endif
> >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >  extern const struct tegra_csi_soc tegra210_csi_soc;
> >  #endif
> >
> >  static const struct of_device_id tegra_csi_of_id_table[] = {
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +     { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +     { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > +#endif
> >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >       { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> >  #endif
> > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > index a06afe91d2de..e528ba280ae4 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -4,6 +4,9 @@
> >   *
> >   * Copyright (C) 2023 SKIDATA GmbH
> >   * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > + *
> > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> >   */
> >
> >  /*
> > @@ -12,12 +15,16 @@
> >   */
> >
> >  #include <linux/bitfield.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk/tegra.h>
> >  #include <linux/delay.h>
> >  #include <linux/host1x.h>
> > +#include <linux/iopoll.h>
> >  #include <linux/kernel.h>
> >  #include <linux/kthread.h>
> >  #include <linux/v4l2-mediabus.h>
> >
> > +#include "csi.h"
> >  #include "vip.h"
> >  #include "vi.h"
> >
> > @@ -42,6 +49,9 @@ enum {
> >  #define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT   BIT(8)
> >  #define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT              0
> >
> > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n)   (0x0070 + (n) * 8)
> > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n)     (0x0074 + (n) * 8)
> > +
> >  #define TEGRA_VI_VI_INPUT_CONTROL                    0x0088
> >  #define       VI_INPUT_FIELD_DETECT                  BIT(27)
> >  #define       VI_INPUT_BT656                         BIT(25)
> > @@ -87,6 +97,8 @@ enum {
> >  #define       VI_OUTPUT_OUTPUT_FORMAT_SFT            0
> >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST     (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR   (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER  (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER  (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> >  #define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT       (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> >
> >  #define TEGRA_VI_VIP_H_ACTIVE                                0x00a4
> > @@ -151,8 +163,106 @@ enum {
> >  #define TEGRA_VI_VI_RAISE                            0x01ac
> >  #define       VI_VI_RAISE_ON_EDGE                    BIT(0)
> >
> > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n)         (0x01d8 + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n)           (0x01dc + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n)                  (0x01e8 + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n)                  (0x01ec + (n) * 8)
> > +
> > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL            0x0000
> > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL          0x0008
> > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n)            (0x0010 + (n) * 0x2c)
> > +#define       CSI_SKIP_PACKET_THRESHOLD(n)           (((n) & 0xff) << 16)
> > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n)           (0x0018 + (n) * 0x2c)
> > +#define       CSI_PP_PAD_FRAME_PAD0S                 (0 << 28)
> > +#define       CSI_PP_PAD_FRAME_PAD1S                 (1 << 28)
> > +#define       CSI_PP_PAD_FRAME_NOPAD                 (2 << 28)
> > +#define       CSI_PP_HEADER_EC_ENABLE                        BIT(27)
> > +#define       CSI_PP_PAD_SHORT_LINE_PAD0S            (0 << 24)
> > +#define       CSI_PP_PAD_SHORT_LINE_PAD1S            (1 << 24)
> > +#define       CSI_PP_PAD_SHORT_LINE_NOPAD            (2 << 24)
> > +#define       CSI_PP_EMBEDDED_DATA_EMBEDDED          BIT(20)
> > +#define       CSI_PP_OUTPUT_FORMAT_ARBITRARY         (0 << 16)
> > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL             (1 << 16)
> > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL_REP         (2 << 16)
> > +#define       CSI_PP_OUTPUT_FORMAT_STORE             (3 << 16)
> > +#define       CSI_PP_VIRTUAL_CHANNEL_ID(n)           (((n) - 1) << 14)
> > +#define       CSI_PP_DATA_TYPE(n)                    ((n) << 8)
> > +#define       CSI_PP_CRC_CHECK_ENABLE                        BIT(7)
> > +#define       CSI_PP_WORD_COUNT_HEADER                       BIT(6)
> > +#define       CSI_PP_DATA_IDENTIFIER_ENABLE          BIT(5)
> > +#define       CSI_PP_PACKET_HEADER_SENT                      BIT(4)
> > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n)           (0x001c + (n) * 0x2c)
> > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n)         (0x0020 + (n) * 0x2c)
> > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n)                        (0x0024 + (n) * 0x2c)
> > +#define       CSI_PP_FRAME_MIN_GAP(n)                        (((n) & 0xffff) << 16)
> > +#define       CSI_PP_LINE_MIN_GAP(n)                 (((n) & 0xffff))
> > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n)         (0x0028 + (n) * 0x2c)
> > +#define       CSI_PP_START_MARKER_FRAME_MAX(n)               (((n) & 0xf) << 12)
> > +#define       CSI_PP_START_MARKER_FRAME_MIN(n)               (((n) & 0xf) << 8)
> > +#define       CSI_PP_VSYNC_START_MARKER                      BIT(4)
> > +#define       CSI_PP_SINGLE_SHOT                     BIT(2)
> > +#define       CSI_PP_NOP                             0
> > +#define       CSI_PP_ENABLE                          1
> > +#define       CSI_PP_DISABLE                         2
> > +#define       CSI_PP_RST                             3
> > +#define TEGRA_CSI_PHY_CIL_COMMAND                    0x0068
> > +#define       CSI_A_PHY_CIL_NOP                              0x0
> > +#define       CSI_A_PHY_CIL_ENABLE                   0x1
> > +#define       CSI_A_PHY_CIL_DISABLE                  0x2
> > +#define       CSI_A_PHY_CIL_ENABLE_MASK                      0x3
> > +#define       CSI_B_PHY_CIL_NOP                              (0x0 << 16)
> > +#define       CSI_B_PHY_CIL_ENABLE                   (0x1 << 16)
> > +#define       CSI_B_PHY_CIL_DISABLE                  (0x2 << 16)
> > +#define       CSI_B_PHY_CIL_ENABLE_MASK                      (0x3 << 16)
> > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n)                        (0x006c + (n) * 4)
> > +#define       CSI_CONTINUOUS_CLOCK_MODE_ENABLE               BIT(5)
> > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS            0x0078
> > +#define TEGRA_CSI_CSI_CIL_STATUS                     0x007c
> > +#define       CSI_MIPI_AUTO_CAL_DONE                 BIT(15)
> > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK    0x0080
> > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK             0x0084
> > +#define TEGRA_CSI_CSI_READONLY_STATUS                        0x0088
> > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND                        0x008c
> > +#define TEGRA_CSI_ESCAPE_MODE_DATA                   0x0090
> > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n)                 (0x0094 + (n) * 8)
> > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n)                 (0x0098 + (n) * 8)
> > +#define TEGRA_CSI_CIL_PAD_CONFIG                     0x00a4
> > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG                       0x00a8
> > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG                       0x00ac
> > +#define       CSI_CIL_MIPI_CAL_STARTCAL                      BIT(31)
> > +#define       CSI_CIL_MIPI_CAL_OVERIDE_A             BIT(30)
> > +#define       CSI_CIL_MIPI_CAL_OVERIDE_B             BIT(30)
> > +#define       CSI_CIL_MIPI_CAL_NOISE_FLT(n)          (((n) & 0xf) << 26)
> > +#define       CSI_CIL_MIPI_CAL_PRESCALE(n)           (((n) & 0x3) << 24)
> > +#define       CSI_CIL_MIPI_CAL_SEL_A                 BIT(21)
> > +#define       CSI_CIL_MIPI_CAL_SEL_B                 BIT(21)
> > +#define       CSI_CIL_MIPI_CAL_HSPDOS(n)             (((n) & 0x1f) << 16)
> > +#define       CSI_CIL_MIPI_CAL_HSPUOS(n)             (((n) & 0x1f) << 8)
> > +#define       CSI_CIL_MIPI_CAL_TERMOS(n)             (((n) & 0x1f))
> > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS                        0x00b0
> > +#define TEGRA_CSI_CLKEN_OVERRIDE                     0x00b4
> > +#define TEGRA_CSI_DEBUG_CONTROL                              0x00b8
> > +#define       CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED     BIT(0)
> > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0                BIT(4)
> > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1                BIT(5)
> > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2                BIT(6)
> > +#define       CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v)    ((v) << (8 + 8 * (n)))
> > +#define TEGRA_CSI_DEBUG_COUNTER(n)                   (0x00bc + (n) * 4)
> > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n)     (0x00c8 + (n) * 4)
> > +#define       CSI_PP_EXP_FRAME_HEIGHT(n)             (((n) & 0x1fff) << 16)
> > +#define       CSI_PP_MAX_CLOCKS(n)                   (((n) & 0xfff) << 4)
> > +#define       CSI_PP_LINE_TIMEOUT_ENABLE             BIT(0)
> > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG                        0x00d0
> > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0                       0x00d4
> > +#define       CSI_PAD_DRIV_DN_REF(n)                 (((n) & 0x7) << 16)
> > +#define       CSI_PAD_DRIV_UP_REF(n)                 (((n) & 0x7) << 8)
> > +#define       CSI_PAD_TERM_REF(n)                    (((n) & 0x7) << 0)
> > +#define TEGRA_CSI_CSI_CILA_STATUS                    0x00d8
> > +#define TEGRA_CSI_CSI_CILB_STATUS                    0x00dc
> > +
> >  /* --------------------------------------------------------------------------
> > - * VI
> > + * Read and Write helpers
> >   */
> >
> >  static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> >       writel(val, chan->vi->iomem + addr);
> >  }
> >
> > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > +{
> > +     return readl(chan->vi->iomem + addr);
> > +}
> > +
> > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > +{
> > +     writel(val, csi_chan->csi->iomem + addr);
> > +}
> > +
> > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > +{
> > +     return readl(csi_chan->csi->iomem + addr);
> > +}
> > +
> > +/* --------------------------------------------------------------------------
> > + * VI
> > + */
> > +
> >  /*
> >   * Get the main input format (YUV/RGB...) and the YUV variant as values to
> >   * be written into registers for the current VI input mbus code.
> > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> >  static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> >  {
> >       struct tegra_vi *vi = chan->vi;
> > -     struct host1x_syncpt *out_sp;
> > +     struct host1x_syncpt *out_sp, *fs_sp;
> >
> >       out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> >       if (!out_sp)
> > -             return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
>
> Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
>

That is interesting. I am fine to switching to any error code as long
as it fits here, EBUSY fits fine.

> >
> >       chan->mw_ack_sp[0] = out_sp;
> >
> > +     fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > +     if (!fs_sp)
> > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > +
> > +     chan->frame_start_sp[0] = fs_sp;
> > +
> >       return 0;
> >  }
> >
> >  static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> >  {
> >       host1x_syncpt_put(chan->mw_ack_sp[0]);
> > +     host1x_syncpt_put(chan->frame_start_sp[0]);
> >  }
> >
> >  static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> >  static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> >                                        struct tegra_channel_buffer *buf)
> >  {
> > +     struct v4l2_subdev *csi_subdev = NULL;
> > +     struct tegra_csi_channel *csi_chan = NULL;
> > +     u32 port;
> >       int err;
> >
> > -     chan->next_out_sp_idx++;
> > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > +     if (csi_subdev) {
> > +             /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > +             if (!strncmp(csi_subdev->name, "channel", 7)) {
> > +                     csi_chan = to_csi_chan(csi_subdev);
> > +                     port = csi_chan->csi_port_nums[0] & 1;
> > +             }
> > +     }
>
> tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
>

That is possible.

> Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
>

I may try that. My main concern was VIP. Unlike Tegra210,
Tegra20/Tegra30 have VIP which can cause issues if no additional
checks are done.

> Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
>

Yes, I hope so. We did not implement this logic, it existed before, we
just expanded it to support CSI.

> >
> >       tegra20_channel_vi_buffer_setup(chan, buf);
> >
> > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > +     if (csi_chan) {
> > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > +                               CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > +
> > +             chan->next_fs_sp_idx++;
> > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > +             if (err) {
> > +                     host1x_syncpt_incr(chan->frame_start_sp[0]);
>
> This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
>

The race condition should be avoidable by resetting pixel parser and
checking syncpt value again.
Incrementing the software reference counter only if hardware completed
successfully sounds like a good idea.

> Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
>
> (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
>
> > +                     if (err != -ERESTARTSYS)
> > +                             dev_err_ratelimited(&chan->video.dev,
> > +                                                 "frame start syncpt timeout: %d\n", err);
> > +             }
> > +
> > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > +                               CSI_PP_DISABLE);
> > +     } else {
> > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > +     }
> >
> > -     /* Wait for syncpt counter to reach frame start event threshold */
> > +     chan->next_out_sp_idx++;
> >       err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> >                                TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> >       if (err) {
> >               host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > -             dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > -             release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > -             return err;
> > +             if (err != -ERESTARTSYS)
> > +                     dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> >       }
> >
> > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > -                      VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > +     if (!csi_chan)
> > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > +                              VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> >
> >       release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> >
> > -     return 0;
> > +     return err;
> >  }
> >
> >  static int tegra20_chan_capture_kthread_start(void *data)
> > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> >       int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                             OUT_2 : OUT_1;
> > -     int main_output_format;
> > -     int yuv_output_format;
> > -
> > -     tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > -
> > -     /*
> > -      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > -      * for luminance, which is the default and means not to touch
> > -      * anything.
> > -      */
> > -     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > -                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > -                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > -
> > -     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > -     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > -
> > -     tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > -                      (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > -                      (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > -                      yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > -                      main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> >
> >       /* Set up frame size */
> >       tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> >       tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> >  }
> >
> > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > +{
> > +     struct tegra_csi *csi = csi_chan->csi;
> > +     void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > +     unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > +     u32 value, pp, cil;
> > +     int ret;
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > +                       CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > +                       CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > +                       CSI_CIL_MIPI_CAL_TERMOS(0));
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > +                       CSI_PAD_DRIV_DN_REF(5) |
> > +                       CSI_PAD_DRIV_UP_REF(7) |
> > +                       CSI_PAD_TERM_REF(0));
> > +
> > +     /* CSI B */
> > +     value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > +
> > +     if (port == PORT_B || csi_chan->numlanes == 4)
> > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > +
> > +     /* CSI A */
> > +     value = CSI_CIL_MIPI_CAL_STARTCAL |
> > +             CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > +             CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > +             CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > +
> > +     if (port == PORT_A)
> > +             value |= CSI_CIL_MIPI_CAL_SEL_A;
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > +
> > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > +                                      value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > +     if (ret < 0) {
> > +             dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > +             goto exit;
> > +     }
> > +
> > +     /* clear status */
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > +                                      !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > +     if (ret < 0) {
> > +             dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > +             goto exit;
> > +     }
> > +
> > +     pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > +     cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > +     if (pp | cil) {
> > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > +             ret = -EINVAL;
> > +             goto exit;
> > +     }
> > +
> > +exit:
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > +
> > +     /* un-select to avoid interference with DSI */
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > +                       CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > +                       CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > +
> > +     return ret;
> > +}
> > +
> >  static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> >  {
> >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> >       struct media_pipeline *pipe = &chan->video.pipe;
> > +     struct v4l2_subdev *csi_subdev, *src_subdev;
> > +     struct tegra_csi_channel *csi_chan = NULL;
> >       int err;
> >
> > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > +     if (csi_subdev) {
> > +             if (!strncmp(csi_subdev->name, "channel", 7))
> > +                     csi_chan = to_csi_chan(csi_subdev);
> > +     }
> > +
> > +     chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> >       chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> >
> >       err = video_device_pipeline_start(&chan->video, pipe);
> >       if (err)
> >               goto error_pipeline_start;
> >
> > -     tegra20_camera_capture_setup(chan);
> > +     /*
> > +      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > +      * for luminance, which is the default and means not to touch
> > +      * anything.
> > +      */
> > +     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > +                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > +                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > +
> > +     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > +     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> >
> >       err = tegra_channel_set_stream(chan, true);
> >       if (err)
> >               goto error_set_stream;
> >
> > +     tegra20_camera_capture_setup(chan);
> > +
> > +     if (csi_chan) {
> > +             /*
> > +              * TRM has incorrectly documented to wait for done status from
> > +              * calibration logic after CSI interface power on.
> > +              * As per the design, calibration results are latched and applied
> > +              * to the pads only when the link is in LP11 state which will happen
> > +              * during the sensor stream-on.
> > +              * CSI subdev stream-on triggers start of MIPI pads calibration.
> > +              * Wait for calibration to finish here after sensor subdev stream-on.
> > +              */
> > +             src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > +             if (!src_subdev->s_stream_enabled) {
> > +                     err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > +                     if (err < 0 && err != -ENOIOCTLCMD)
> > +                             goto error_set_stream;
> > +             }
> > +
> > +             tegra20_csi_pad_calibration(csi_chan);
> > +     }
> > +
> >       chan->sequence = 0;
> >
> >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> >  static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> >  {
> >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > +     struct v4l2_subdev *src_subdev;
> >
> >       if (chan->kthread_start_capture) {
> >               kthread_stop(chan->kthread_start_capture);
> >               chan->kthread_start_capture = NULL;
> >       }
> >
> > +     src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > +     if (src_subdev->s_stream_enabled)
> > +             v4l2_subdev_call(src_subdev, video, s_stream, false);
> > +
> >       tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> >       tegra_channel_set_stream(chan, false);
> >       video_device_pipeline_stop(&chan->video);
> > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> >       .default_video_format = &tegra20_video_formats[0],
> >       .ops = &tegra20_vi_ops,
> >       .hw_revision = 1,
> > -     .vi_max_channels = 1, /* parallel input (VIP) */
> > +     .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> >       .vi_max_clk_hz = 450000000,
> >       .has_h_v_flip = true,
> >  };
> >
> > +/* --------------------------------------------------------------------------
> > + * CSI
> > + */
> > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > +{
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > +}
> > +
> > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > +                                         u8 portno)
> > +{
> > +     struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > +     int width  = vi_chan->format.width;
> > +     int height = vi_chan->format.height;
> > +     u32 data_type = vi_chan->fmtinfo->img_dt;
> > +     u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > +     int output_channel = OUT_1;
> > +
> > +     unsigned int main_output_format, yuv_output_format;
> > +     unsigned int port = portno & 1;
> > +     u32 value;
> > +
> > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > +
> > +     switch (data_type) {
> > +     case TEGRA_IMAGE_DT_RAW8:
> > +     case TEGRA_IMAGE_DT_RAW10:
> > +             output_channel = OUT_2;
> > +             if (port == PORT_A)
> > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > +             else
> > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > +             break;
> > +     }
> > +
> > +     tegra20_csi_capture_clean(csi_chan);
> > +
> > +     /* CSI port cleanup */
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > +                       CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > +                       CSI_PP_EXP_FRAME_HEIGHT(height) |
> > +                       CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > +                       CSI_PP_LINE_TIMEOUT_ENABLE);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > +                       CSI_PP_OUTPUT_FORMAT_PIXEL |
> > +                       CSI_PP_DATA_TYPE(data_type) |
> > +                       CSI_PP_CRC_CHECK_ENABLE |
> > +                       CSI_PP_WORD_COUNT_HEADER |
> > +                       CSI_PP_DATA_IDENTIFIER_ENABLE |
> > +                       CSI_PP_PACKET_HEADER_SENT |
> > +                       port);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > +                       CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > +                       (csi_chan->numlanes - 1));
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > +                       CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > +                       0x5); /* Clock settle time */
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > +                      host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > +                      host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > +
> > +     value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > +             CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > +                       CSI_PP_DISABLE);
> > +
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > +                      yuv_output_format | main_output_format);
> > +
> > +     return 0;
> > +};
> > +
> > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > +{
> > +     struct tegra_csi *csi = csi_chan->csi;
> > +     unsigned int port = portno & 1;
> > +     u32 value;
> > +
> > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > +
> > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > +
> > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > +                       CSI_PP_DISABLE);
> > +
> > +     if (csi_chan->numlanes == 4) {
> > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > +                               CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > +     } else {
> > +             value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > +                     CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > +     }
> > +}
> > +
> > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > +{
> > +     u8 *portnos = csi_chan->csi_port_nums;
> > +     int ret, i;
> > +
> > +     for (i = 0; i < csi_chan->numgangports; i++) {
> > +             ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > +             if (ret)
> > +                     goto stream_start_fail;
> > +     }
> > +
> > +     return 0;
> > +
> > +stream_start_fail:
> > +     for (i = i - 1; i >= 0; i--)
> > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > +
> > +     return ret;
> > +}
> > +
> > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > +{
> > +     u8 *portnos = csi_chan->csi_port_nums;
> > +     int i;
> > +
> > +     for (i = 0; i < csi_chan->numgangports; i++)
> > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > +}
> > +
> > +/* Tegra20 CSI operations */
> > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > +     .csi_start_streaming = tegra20_csi_start_streaming,
> > +     .csi_stop_streaming = tegra20_csi_stop_streaming,
> > +};
> > +
> > +static const char * const tegra20_csi_clks[] = {
> > +     "csi",
> > +};
> > +
> > +/* Tegra20 CSI SoC data */
> > +const struct tegra_csi_soc tegra20_csi_soc = {
> > +     .ops = &tegra20_csi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra20_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > +     .has_mipi_calibration = false,
> > +};
> > +
> > +static const char * const tegra30_csi_clks[] = {
> > +     "csi",
> > +     "csia_pad",
> > +     "csib_pad",
> > +};
> > +
> > +/* Tegra30 CSI SoC data */
> > +const struct tegra_csi_soc tegra30_csi_soc = {
> > +     .ops = &tegra20_csi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra30_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > +     .has_mipi_calibration = false,
> > +};
> > +
> >  /* --------------------------------------------------------------------------
> >   * VIP
> >   */
> > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                             OUT_2 : OUT_1;
> >
> > -     unsigned int main_input_format;
> > -     unsigned int yuv_input_format;
> > +     unsigned int main_input_format, yuv_input_format;
> > +     unsigned int main_output_format, yuv_output_format;
> >
> >       tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> >
> >       tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> >
> > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >
> >       tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> >
> > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > +                       yuv_output_format | main_output_format);
> > +
> >       return 0;
> >  }
> >
> > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > index cac0c0d0e225..c02517c9e09b 100644
> > --- a/drivers/staging/media/tegra-video/vi.h
> > +++ b/drivers/staging/media/tegra-video/vi.h
> > @@ -127,6 +127,7 @@ struct tegra_vi {
> >   *           frame through host1x syncpoint counters (On Tegra20 used for the
> >   *              OUT_1 syncpt)
> >   * @sp_incr_lock: protects cpu syncpoint increment.
> > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> >   * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> >   *
> >   * @kthread_start_capture: kthread to start capture of single frame when
> > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> >       /* protects the cpu syncpoint increment */
> >       spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> >       u32 next_out_sp_idx;
> > +     u32 next_fs_sp_idx;
> >
> >       struct task_struct *kthread_start_capture;
> >       wait_queue_head_t start_wait;
> > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > index a25885f93cd7..8fa660431eb0 100644
> > --- a/drivers/staging/media/tegra-video/video.c
> > +++ b/drivers/staging/media/tegra-video/video.c
> > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> >
> >  static const struct of_device_id host1x_video_subdevs[] = {
> >  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +     { .compatible = "nvidia,tegra20-csi", },
> >       { .compatible = "nvidia,tegra20-vip", },
> >       { .compatible = "nvidia,tegra20-vi", },
> >  #endif
> >  #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +     { .compatible = "nvidia,tegra30-csi", },
> >       { .compatible = "nvidia,tegra30-vip", },
> >       { .compatible = "nvidia,tegra30-vi", },
> >  #endif
> >
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-02  5:51     ` Svyatoslav Ryhel
@ 2025-09-02  6:17       ` Mikko Perttunen
  2025-09-02  6:21         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  6:17 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Tuesday, September 2, 2025 2:51 PM Svyatoslav Ryhel wrote:
> вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> > >
> > > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > >  drivers/staging/media/tegra-video/csi.c     |  12 +
> > >  drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> > >  drivers/staging/media/tegra-video/vi.h      |   2 +
> > >  drivers/staging/media/tegra-video/video.c   |   2 +
> > >  4 files changed, 553 insertions(+), 38 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > index 2f9907a20db1..714ce52a793c 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> > >       pm_runtime_disable(&pdev->dev);
> > >  }
> > >
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > > +#endif
> > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > >  extern const struct tegra_csi_soc tegra210_csi_soc;
> > >  #endif
> > >
> > >  static const struct of_device_id tegra_csi_of_id_table[] = {
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +     { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +     { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > > +#endif
> > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > >       { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> > >  #endif
> > > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > > index a06afe91d2de..e528ba280ae4 100644
> > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > @@ -4,6 +4,9 @@
> > >   *
> > >   * Copyright (C) 2023 SKIDATA GmbH
> > >   * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > > + *
> > > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > >   */
> > >
> > >  /*
> > > @@ -12,12 +15,16 @@
> > >   */
> > >
> > >  #include <linux/bitfield.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/clk/tegra.h>
> > >  #include <linux/delay.h>
> > >  #include <linux/host1x.h>
> > > +#include <linux/iopoll.h>
> > >  #include <linux/kernel.h>
> > >  #include <linux/kthread.h>
> > >  #include <linux/v4l2-mediabus.h>
> > >
> > > +#include "csi.h"
> > >  #include "vip.h"
> > >  #include "vi.h"
> > >
> > > @@ -42,6 +49,9 @@ enum {
> > >  #define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT   BIT(8)
> > >  #define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT              0
> > >
> > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n)   (0x0070 + (n) * 8)
> > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n)     (0x0074 + (n) * 8)
> > > +
> > >  #define TEGRA_VI_VI_INPUT_CONTROL                    0x0088
> > >  #define       VI_INPUT_FIELD_DETECT                  BIT(27)
> > >  #define       VI_INPUT_BT656                         BIT(25)
> > > @@ -87,6 +97,8 @@ enum {
> > >  #define       VI_OUTPUT_OUTPUT_FORMAT_SFT            0
> > >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST     (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR   (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER  (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER  (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > >  #define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT       (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > >
> > >  #define TEGRA_VI_VIP_H_ACTIVE                                0x00a4
> > > @@ -151,8 +163,106 @@ enum {
> > >  #define TEGRA_VI_VI_RAISE                            0x01ac
> > >  #define       VI_VI_RAISE_ON_EDGE                    BIT(0)
> > >
> > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n)         (0x01d8 + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n)           (0x01dc + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n)                  (0x01e8 + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n)                  (0x01ec + (n) * 8)
> > > +
> > > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL            0x0000
> > > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL          0x0008
> > > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n)            (0x0010 + (n) * 0x2c)
> > > +#define       CSI_SKIP_PACKET_THRESHOLD(n)           (((n) & 0xff) << 16)
> > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n)           (0x0018 + (n) * 0x2c)
> > > +#define       CSI_PP_PAD_FRAME_PAD0S                 (0 << 28)
> > > +#define       CSI_PP_PAD_FRAME_PAD1S                 (1 << 28)
> > > +#define       CSI_PP_PAD_FRAME_NOPAD                 (2 << 28)
> > > +#define       CSI_PP_HEADER_EC_ENABLE                        BIT(27)
> > > +#define       CSI_PP_PAD_SHORT_LINE_PAD0S            (0 << 24)
> > > +#define       CSI_PP_PAD_SHORT_LINE_PAD1S            (1 << 24)
> > > +#define       CSI_PP_PAD_SHORT_LINE_NOPAD            (2 << 24)
> > > +#define       CSI_PP_EMBEDDED_DATA_EMBEDDED          BIT(20)
> > > +#define       CSI_PP_OUTPUT_FORMAT_ARBITRARY         (0 << 16)
> > > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL             (1 << 16)
> > > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL_REP         (2 << 16)
> > > +#define       CSI_PP_OUTPUT_FORMAT_STORE             (3 << 16)
> > > +#define       CSI_PP_VIRTUAL_CHANNEL_ID(n)           (((n) - 1) << 14)
> > > +#define       CSI_PP_DATA_TYPE(n)                    ((n) << 8)
> > > +#define       CSI_PP_CRC_CHECK_ENABLE                        BIT(7)
> > > +#define       CSI_PP_WORD_COUNT_HEADER                       BIT(6)
> > > +#define       CSI_PP_DATA_IDENTIFIER_ENABLE          BIT(5)
> > > +#define       CSI_PP_PACKET_HEADER_SENT                      BIT(4)
> > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n)           (0x001c + (n) * 0x2c)
> > > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n)         (0x0020 + (n) * 0x2c)
> > > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n)                        (0x0024 + (n) * 0x2c)
> > > +#define       CSI_PP_FRAME_MIN_GAP(n)                        (((n) & 0xffff) << 16)
> > > +#define       CSI_PP_LINE_MIN_GAP(n)                 (((n) & 0xffff))
> > > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n)         (0x0028 + (n) * 0x2c)
> > > +#define       CSI_PP_START_MARKER_FRAME_MAX(n)               (((n) & 0xf) << 12)
> > > +#define       CSI_PP_START_MARKER_FRAME_MIN(n)               (((n) & 0xf) << 8)
> > > +#define       CSI_PP_VSYNC_START_MARKER                      BIT(4)
> > > +#define       CSI_PP_SINGLE_SHOT                     BIT(2)
> > > +#define       CSI_PP_NOP                             0
> > > +#define       CSI_PP_ENABLE                          1
> > > +#define       CSI_PP_DISABLE                         2
> > > +#define       CSI_PP_RST                             3
> > > +#define TEGRA_CSI_PHY_CIL_COMMAND                    0x0068
> > > +#define       CSI_A_PHY_CIL_NOP                              0x0
> > > +#define       CSI_A_PHY_CIL_ENABLE                   0x1
> > > +#define       CSI_A_PHY_CIL_DISABLE                  0x2
> > > +#define       CSI_A_PHY_CIL_ENABLE_MASK                      0x3
> > > +#define       CSI_B_PHY_CIL_NOP                              (0x0 << 16)
> > > +#define       CSI_B_PHY_CIL_ENABLE                   (0x1 << 16)
> > > +#define       CSI_B_PHY_CIL_DISABLE                  (0x2 << 16)
> > > +#define       CSI_B_PHY_CIL_ENABLE_MASK                      (0x3 << 16)
> > > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n)                        (0x006c + (n) * 4)
> > > +#define       CSI_CONTINUOUS_CLOCK_MODE_ENABLE               BIT(5)
> > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS            0x0078
> > > +#define TEGRA_CSI_CSI_CIL_STATUS                     0x007c
> > > +#define       CSI_MIPI_AUTO_CAL_DONE                 BIT(15)
> > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK    0x0080
> > > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK             0x0084
> > > +#define TEGRA_CSI_CSI_READONLY_STATUS                        0x0088
> > > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND                        0x008c
> > > +#define TEGRA_CSI_ESCAPE_MODE_DATA                   0x0090
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n)                 (0x0094 + (n) * 8)
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n)                 (0x0098 + (n) * 8)
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG                     0x00a4
> > > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG                       0x00a8
> > > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG                       0x00ac
> > > +#define       CSI_CIL_MIPI_CAL_STARTCAL                      BIT(31)
> > > +#define       CSI_CIL_MIPI_CAL_OVERIDE_A             BIT(30)
> > > +#define       CSI_CIL_MIPI_CAL_OVERIDE_B             BIT(30)
> > > +#define       CSI_CIL_MIPI_CAL_NOISE_FLT(n)          (((n) & 0xf) << 26)
> > > +#define       CSI_CIL_MIPI_CAL_PRESCALE(n)           (((n) & 0x3) << 24)
> > > +#define       CSI_CIL_MIPI_CAL_SEL_A                 BIT(21)
> > > +#define       CSI_CIL_MIPI_CAL_SEL_B                 BIT(21)
> > > +#define       CSI_CIL_MIPI_CAL_HSPDOS(n)             (((n) & 0x1f) << 16)
> > > +#define       CSI_CIL_MIPI_CAL_HSPUOS(n)             (((n) & 0x1f) << 8)
> > > +#define       CSI_CIL_MIPI_CAL_TERMOS(n)             (((n) & 0x1f))
> > > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS                        0x00b0
> > > +#define TEGRA_CSI_CLKEN_OVERRIDE                     0x00b4
> > > +#define TEGRA_CSI_DEBUG_CONTROL                              0x00b8
> > > +#define       CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED     BIT(0)
> > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0                BIT(4)
> > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1                BIT(5)
> > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2                BIT(6)
> > > +#define       CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v)    ((v) << (8 + 8 * (n)))
> > > +#define TEGRA_CSI_DEBUG_COUNTER(n)                   (0x00bc + (n) * 4)
> > > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n)     (0x00c8 + (n) * 4)
> > > +#define       CSI_PP_EXP_FRAME_HEIGHT(n)             (((n) & 0x1fff) << 16)
> > > +#define       CSI_PP_MAX_CLOCKS(n)                   (((n) & 0xfff) << 4)
> > > +#define       CSI_PP_LINE_TIMEOUT_ENABLE             BIT(0)
> > > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG                        0x00d0
> > > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0                       0x00d4
> > > +#define       CSI_PAD_DRIV_DN_REF(n)                 (((n) & 0x7) << 16)
> > > +#define       CSI_PAD_DRIV_UP_REF(n)                 (((n) & 0x7) << 8)
> > > +#define       CSI_PAD_TERM_REF(n)                    (((n) & 0x7) << 0)
> > > +#define TEGRA_CSI_CSI_CILA_STATUS                    0x00d8
> > > +#define TEGRA_CSI_CSI_CILB_STATUS                    0x00dc
> > > +
> > >  /* --------------------------------------------------------------------------
> > > - * VI
> > > + * Read and Write helpers
> > >   */
> > >
> > >  static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> > >       writel(val, chan->vi->iomem + addr);
> > >  }
> > >
> > > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > > +{
> > > +     return readl(chan->vi->iomem + addr);
> > > +}
> > > +
> > > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > > +{
> > > +     writel(val, csi_chan->csi->iomem + addr);
> > > +}
> > > +
> > > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > > +{
> > > +     return readl(csi_chan->csi->iomem + addr);
> > > +}
> > > +
> > > +/* --------------------------------------------------------------------------
> > > + * VI
> > > + */
> > > +
> > >  /*
> > >   * Get the main input format (YUV/RGB...) and the YUV variant as values to
> > >   * be written into registers for the current VI input mbus code.
> > > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > >  static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > >  {
> > >       struct tegra_vi *vi = chan->vi;
> > > -     struct host1x_syncpt *out_sp;
> > > +     struct host1x_syncpt *out_sp, *fs_sp;
> > >
> > >       out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > >       if (!out_sp)
> > > -             return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
> >
> > Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
> >
> 
> That is interesting. I am fine to switching to any error code as long
> as it fits here, EBUSY fits fine.
> 
> > >
> > >       chan->mw_ack_sp[0] = out_sp;
> > >
> > > +     fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > +     if (!fs_sp)
> > > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > > +
> > > +     chan->frame_start_sp[0] = fs_sp;
> > > +
> > >       return 0;
> > >  }
> > >
> > >  static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> > >  {
> > >       host1x_syncpt_put(chan->mw_ack_sp[0]);
> > > +     host1x_syncpt_put(chan->frame_start_sp[0]);
> > >  }
> > >
> > >  static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> > >  static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> > >                                        struct tegra_channel_buffer *buf)
> > >  {
> > > +     struct v4l2_subdev *csi_subdev = NULL;
> > > +     struct tegra_csi_channel *csi_chan = NULL;
> > > +     u32 port;
> > >       int err;
> > >
> > > -     chan->next_out_sp_idx++;
> > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > +     if (csi_subdev) {
> > > +             /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > > +             if (!strncmp(csi_subdev->name, "channel", 7)) {
> > > +                     csi_chan = to_csi_chan(csi_subdev);
> > > +                     port = csi_chan->csi_port_nums[0] & 1;
> > > +             }
> > > +     }
> >
> > tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
> >
> 
> That is possible.
> 
> > Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
> >
> 
> I may try that. My main concern was VIP. Unlike Tegra210,
> Tegra20/Tegra30 have VIP which can cause issues if no additional
> checks are done.
> 
> > Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
> >
> 
> Yes, I hope so. We did not implement this logic, it existed before, we
> just expanded it to support CSI.

If it's non-trivial it can be left for later.

> 
> > >
> > >       tegra20_channel_vi_buffer_setup(chan, buf);
> > >
> > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > +     if (csi_chan) {
> > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > +                               CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > > +
> > > +             chan->next_fs_sp_idx++;
> > > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > +             if (err) {
> > > +                     host1x_syncpt_incr(chan->frame_start_sp[0]);
> >
> > This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
> >
> 
> The race condition should be avoidable by resetting pixel parser and
> checking syncpt value again.
> Incrementing the software reference counter only if hardware completed
> successfully sounds like a good idea.
> 
> > Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
> >
> > (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
> >
> > > +                     if (err != -ERESTARTSYS)
> > > +                             dev_err_ratelimited(&chan->video.dev,
> > > +                                                 "frame start syncpt timeout: %d\n", err);
> > > +             }
> > > +
> > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > +                               CSI_PP_DISABLE);
> > > +     } else {
> > > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > +     }
> > >
> > > -     /* Wait for syncpt counter to reach frame start event threshold */
> > > +     chan->next_out_sp_idx++;
> > >       err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> > >                                TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > >       if (err) {
> > >               host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > > -             dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > > -             release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > > -             return err;
> > > +             if (err != -ERESTARTSYS)
> > > +                     dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> > >       }
> > >
> > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > -                      VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > +     if (!csi_chan)
> > > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > +                              VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > >
> > >       release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> > >
> > > -     return 0;
> > > +     return err;
> > >  }
> > >
> > >  static int tegra20_chan_capture_kthread_start(void *data)
> > > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > >       int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                             OUT_2 : OUT_1;
> > > -     int main_output_format;
> > > -     int yuv_output_format;
> > > -
> > > -     tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > > -
> > > -     /*
> > > -      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > > -      * for luminance, which is the default and means not to touch
> > > -      * anything.
> > > -      */
> > > -     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > -                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > -                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > -
> > > -     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > -     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > -
> > > -     tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > -                      (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > -                      (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > -                      yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > > -                      main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> > >
> > >       /* Set up frame size */
> > >       tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > >       tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> > >  }
> > >
> > > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > > +{
> > > +     struct tegra_csi *csi = csi_chan->csi;
> > > +     void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > +     unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > > +     u32 value, pp, cil;
> > > +     int ret;
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > > +                       CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > > +                       CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > > +                       CSI_CIL_MIPI_CAL_TERMOS(0));
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > > +                       CSI_PAD_DRIV_DN_REF(5) |
> > > +                       CSI_PAD_DRIV_UP_REF(7) |
> > > +                       CSI_PAD_TERM_REF(0));
> > > +
> > > +     /* CSI B */
> > > +     value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > > +
> > > +     if (port == PORT_B || csi_chan->numlanes == 4)
> > > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > > +
> > > +     /* CSI A */
> > > +     value = CSI_CIL_MIPI_CAL_STARTCAL |
> > > +             CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > +             CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > +             CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > > +
> > > +     if (port == PORT_A)
> > > +             value |= CSI_CIL_MIPI_CAL_SEL_A;
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > +
> > > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > +                                      value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > > +     if (ret < 0) {
> > > +             dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > > +             goto exit;
> > > +     }
> > > +
> > > +     /* clear status */
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > +                                      !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > > +     if (ret < 0) {
> > > +             dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > > +             goto exit;
> > > +     }
> > > +
> > > +     pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > +     cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > +     if (pp | cil) {
> > > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > +             ret = -EINVAL;
> > > +             goto exit;
> > > +     }
> > > +
> > > +exit:
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > +
> > > +     /* un-select to avoid interference with DSI */
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > > +                       CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > +                       CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > > +
> > > +     return ret;
> > > +}
> > > +
> > >  static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > >  {
> > >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > >       struct media_pipeline *pipe = &chan->video.pipe;
> > > +     struct v4l2_subdev *csi_subdev, *src_subdev;
> > > +     struct tegra_csi_channel *csi_chan = NULL;
> > >       int err;
> > >
> > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > +     if (csi_subdev) {
> > > +             if (!strncmp(csi_subdev->name, "channel", 7))
> > > +                     csi_chan = to_csi_chan(csi_subdev);
> > > +     }
> > > +
> > > +     chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> > >       chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> > >
> > >       err = video_device_pipeline_start(&chan->video, pipe);
> > >       if (err)
> > >               goto error_pipeline_start;
> > >
> > > -     tegra20_camera_capture_setup(chan);
> > > +     /*
> > > +      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > > +      * for luminance, which is the default and means not to touch
> > > +      * anything.
> > > +      */
> > > +     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > +                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > +                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > +
> > > +     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > +     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > >
> > >       err = tegra_channel_set_stream(chan, true);
> > >       if (err)
> > >               goto error_set_stream;
> > >
> > > +     tegra20_camera_capture_setup(chan);
> > > +
> > > +     if (csi_chan) {
> > > +             /*
> > > +              * TRM has incorrectly documented to wait for done status from
> > > +              * calibration logic after CSI interface power on.
> > > +              * As per the design, calibration results are latched and applied
> > > +              * to the pads only when the link is in LP11 state which will happen
> > > +              * during the sensor stream-on.
> > > +              * CSI subdev stream-on triggers start of MIPI pads calibration.
> > > +              * Wait for calibration to finish here after sensor subdev stream-on.
> > > +              */
> > > +             src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > +             if (!src_subdev->s_stream_enabled) {
> > > +                     err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > > +                     if (err < 0 && err != -ENOIOCTLCMD)
> > > +                             goto error_set_stream;
> > > +             }
> > > +
> > > +             tegra20_csi_pad_calibration(csi_chan);
> > > +     }
> > > +
> > >       chan->sequence = 0;
> > >
> > >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > >  static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> > >  {
> > >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > +     struct v4l2_subdev *src_subdev;
> > >
> > >       if (chan->kthread_start_capture) {
> > >               kthread_stop(chan->kthread_start_capture);
> > >               chan->kthread_start_capture = NULL;
> > >       }
> > >
> > > +     src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > +     if (src_subdev->s_stream_enabled)
> > > +             v4l2_subdev_call(src_subdev, video, s_stream, false);
> > > +
> > >       tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> > >       tegra_channel_set_stream(chan, false);
> > >       video_device_pipeline_stop(&chan->video);
> > > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > >       .default_video_format = &tegra20_video_formats[0],
> > >       .ops = &tegra20_vi_ops,
> > >       .hw_revision = 1,
> > > -     .vi_max_channels = 1, /* parallel input (VIP) */
> > > +     .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> > >       .vi_max_clk_hz = 450000000,
> > >       .has_h_v_flip = true,
> > >  };
> > >
> > > +/* --------------------------------------------------------------------------
> > > + * CSI
> > > + */
> > > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > > +{
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > > +}
> > > +
> > > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > > +                                         u8 portno)
> > > +{
> > > +     struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > > +     int width  = vi_chan->format.width;
> > > +     int height = vi_chan->format.height;
> > > +     u32 data_type = vi_chan->fmtinfo->img_dt;
> > > +     u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > > +     int output_channel = OUT_1;
> > > +
> > > +     unsigned int main_output_format, yuv_output_format;
> > > +     unsigned int port = portno & 1;
> > > +     u32 value;
> > > +
> > > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > +
> > > +     switch (data_type) {
> > > +     case TEGRA_IMAGE_DT_RAW8:
> > > +     case TEGRA_IMAGE_DT_RAW10:
> > > +             output_channel = OUT_2;
> > > +             if (port == PORT_A)
> > > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > > +             else
> > > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > > +             break;
> > > +     }
> > > +
> > > +     tegra20_csi_capture_clean(csi_chan);
> > > +
> > > +     /* CSI port cleanup */
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > > +                       CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > > +                       CSI_PP_EXP_FRAME_HEIGHT(height) |
> > > +                       CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > > +                       CSI_PP_LINE_TIMEOUT_ENABLE);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > > +                       CSI_PP_OUTPUT_FORMAT_PIXEL |
> > > +                       CSI_PP_DATA_TYPE(data_type) |
> > > +                       CSI_PP_CRC_CHECK_ENABLE |
> > > +                       CSI_PP_WORD_COUNT_HEADER |
> > > +                       CSI_PP_DATA_IDENTIFIER_ENABLE |
> > > +                       CSI_PP_PACKET_HEADER_SENT |
> > > +                       port);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > > +                       CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > > +                       (csi_chan->numlanes - 1));
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > > +                       CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > > +                       0x5); /* Clock settle time */
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > +                      host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > +                      host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > +
> > > +     value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > > +             CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > +                       CSI_PP_DISABLE);
> > > +
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > +                      yuv_output_format | main_output_format);
> > > +
> > > +     return 0;
> > > +};
> > > +
> > > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > > +{
> > > +     struct tegra_csi *csi = csi_chan->csi;
> > > +     unsigned int port = portno & 1;
> > > +     u32 value;
> > > +
> > > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > > +
> > > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > +
> > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > +                       CSI_PP_DISABLE);
> > > +
> > > +     if (csi_chan->numlanes == 4) {
> > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > > +                               CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > > +     } else {
> > > +             value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > > +                     CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > +     }
> > > +}
> > > +
> > > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > > +{
> > > +     u8 *portnos = csi_chan->csi_port_nums;
> > > +     int ret, i;
> > > +
> > > +     for (i = 0; i < csi_chan->numgangports; i++) {
> > > +             ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > > +             if (ret)
> > > +                     goto stream_start_fail;
> > > +     }
> > > +
> > > +     return 0;
> > > +
> > > +stream_start_fail:
> > > +     for (i = i - 1; i >= 0; i--)
> > > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > > +{
> > > +     u8 *portnos = csi_chan->csi_port_nums;
> > > +     int i;
> > > +
> > > +     for (i = 0; i < csi_chan->numgangports; i++)
> > > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > +}
> > > +
> > > +/* Tegra20 CSI operations */
> > > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > > +     .csi_start_streaming = tegra20_csi_start_streaming,
> > > +     .csi_stop_streaming = tegra20_csi_stop_streaming,
> > > +};
> > > +
> > > +static const char * const tegra20_csi_clks[] = {
> > > +     "csi",
> > > +};
> > > +
> > > +/* Tegra20 CSI SoC data */
> > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > +     .ops = &tegra20_csi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra20_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > +     .has_mipi_calibration = false,
> > > +};
> > > +
> > > +static const char * const tegra30_csi_clks[] = {
> > > +     "csi",
> > > +     "csia_pad",
> > > +     "csib_pad",
> > > +};
> > > +
> > > +/* Tegra30 CSI SoC data */
> > > +const struct tegra_csi_soc tegra30_csi_soc = {
> > > +     .ops = &tegra20_csi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra30_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > +     .has_mipi_calibration = false,
> > > +};
> > > +
> > >  /* --------------------------------------------------------------------------
> > >   * VIP
> > >   */
> > > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                             OUT_2 : OUT_1;
> > >
> > > -     unsigned int main_input_format;
> > > -     unsigned int yuv_input_format;
> > > +     unsigned int main_input_format, yuv_input_format;
> > > +     unsigned int main_output_format, yuv_output_format;
> > >
> > >       tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > >
> > >       tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> > >
> > > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > >
> > >       tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> > >
> > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > +                       yuv_output_format | main_output_format);
> > > +
> > >       return 0;
> > >  }
> > >
> > > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > > index cac0c0d0e225..c02517c9e09b 100644
> > > --- a/drivers/staging/media/tegra-video/vi.h
> > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > @@ -127,6 +127,7 @@ struct tegra_vi {
> > >   *           frame through host1x syncpoint counters (On Tegra20 used for the
> > >   *              OUT_1 syncpt)
> > >   * @sp_incr_lock: protects cpu syncpoint increment.
> > > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> > >   * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> > >   *
> > >   * @kthread_start_capture: kthread to start capture of single frame when
> > > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> > >       /* protects the cpu syncpoint increment */
> > >       spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> > >       u32 next_out_sp_idx;
> > > +     u32 next_fs_sp_idx;
> > >
> > >       struct task_struct *kthread_start_capture;
> > >       wait_queue_head_t start_wait;
> > > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > > index a25885f93cd7..8fa660431eb0 100644
> > > --- a/drivers/staging/media/tegra-video/video.c
> > > +++ b/drivers/staging/media/tegra-video/video.c
> > > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> > >
> > >  static const struct of_device_id host1x_video_subdevs[] = {
> > >  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +     { .compatible = "nvidia,tegra20-csi", },
> > >       { .compatible = "nvidia,tegra20-vip", },
> > >       { .compatible = "nvidia,tegra20-vi", },
> > >  #endif
> > >  #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +     { .compatible = "nvidia,tegra30-csi", },
> > >       { .compatible = "nvidia,tegra30-vip", },
> > >       { .compatible = "nvidia,tegra30-vi", },
> > >  #endif
> > >
> >
> >
> >
> >





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-02  6:17       ` Mikko Perttunen
@ 2025-09-02  6:21         ` Svyatoslav Ryhel
  0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02  6:21 UTC (permalink / raw)
  To: Mikko Perttunen
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

вт, 2 вер. 2025 р. о 09:18 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, September 2, 2025 2:51 PM Svyatoslav Ryhel wrote:
> > вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> > > >
> > > > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > ---
> > > >  drivers/staging/media/tegra-video/csi.c     |  12 +
> > > >  drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> > > >  drivers/staging/media/tegra-video/vi.h      |   2 +
> > > >  drivers/staging/media/tegra-video/video.c   |   2 +
> > > >  4 files changed, 553 insertions(+), 38 deletions(-)
> > > >
> > > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > > index 2f9907a20db1..714ce52a793c 100644
> > > > --- a/drivers/staging/media/tegra-video/csi.c
> > > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> > > >       pm_runtime_disable(&pdev->dev);
> > > >  }
> > > >
> > > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > > > +#endif
> > > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > > > +#endif
> > > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > >  extern const struct tegra_csi_soc tegra210_csi_soc;
> > > >  #endif
> > > >
> > > >  static const struct of_device_id tegra_csi_of_id_table[] = {
> > > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > +     { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > > > +#endif
> > > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > +     { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > > > +#endif
> > > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > >       { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> > > >  #endif
> > > > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > > > index a06afe91d2de..e528ba280ae4 100644
> > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > @@ -4,6 +4,9 @@
> > > >   *
> > > >   * Copyright (C) 2023 SKIDATA GmbH
> > > >   * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > > > + *
> > > > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > > > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > >   */
> > > >
> > > >  /*
> > > > @@ -12,12 +15,16 @@
> > > >   */
> > > >
> > > >  #include <linux/bitfield.h>
> > > > +#include <linux/clk.h>
> > > > +#include <linux/clk/tegra.h>
> > > >  #include <linux/delay.h>
> > > >  #include <linux/host1x.h>
> > > > +#include <linux/iopoll.h>
> > > >  #include <linux/kernel.h>
> > > >  #include <linux/kthread.h>
> > > >  #include <linux/v4l2-mediabus.h>
> > > >
> > > > +#include "csi.h"
> > > >  #include "vip.h"
> > > >  #include "vi.h"
> > > >
> > > > @@ -42,6 +49,9 @@ enum {
> > > >  #define       VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT   BIT(8)
> > > >  #define       VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT              0
> > > >
> > > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n)   (0x0070 + (n) * 8)
> > > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n)     (0x0074 + (n) * 8)
> > > > +
> > > >  #define TEGRA_VI_VI_INPUT_CONTROL                    0x0088
> > > >  #define       VI_INPUT_FIELD_DETECT                  BIT(27)
> > > >  #define       VI_INPUT_BT656                         BIT(25)
> > > > @@ -87,6 +97,8 @@ enum {
> > > >  #define       VI_OUTPUT_OUTPUT_FORMAT_SFT            0
> > > >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV422POST     (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > >  #define       VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR   (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER  (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > +#define       VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER  (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > >  #define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT       (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > >
> > > >  #define TEGRA_VI_VIP_H_ACTIVE                                0x00a4
> > > > @@ -151,8 +163,106 @@ enum {
> > > >  #define TEGRA_VI_VI_RAISE                            0x01ac
> > > >  #define       VI_VI_RAISE_ON_EDGE                    BIT(0)
> > > >
> > > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n)         (0x01d8 + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n)           (0x01dc + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n)                  (0x01e8 + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n)                  (0x01ec + (n) * 8)
> > > > +
> > > > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > > > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL            0x0000
> > > > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL          0x0008
> > > > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n)            (0x0010 + (n) * 0x2c)
> > > > +#define       CSI_SKIP_PACKET_THRESHOLD(n)           (((n) & 0xff) << 16)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n)           (0x0018 + (n) * 0x2c)
> > > > +#define       CSI_PP_PAD_FRAME_PAD0S                 (0 << 28)
> > > > +#define       CSI_PP_PAD_FRAME_PAD1S                 (1 << 28)
> > > > +#define       CSI_PP_PAD_FRAME_NOPAD                 (2 << 28)
> > > > +#define       CSI_PP_HEADER_EC_ENABLE                        BIT(27)
> > > > +#define       CSI_PP_PAD_SHORT_LINE_PAD0S            (0 << 24)
> > > > +#define       CSI_PP_PAD_SHORT_LINE_PAD1S            (1 << 24)
> > > > +#define       CSI_PP_PAD_SHORT_LINE_NOPAD            (2 << 24)
> > > > +#define       CSI_PP_EMBEDDED_DATA_EMBEDDED          BIT(20)
> > > > +#define       CSI_PP_OUTPUT_FORMAT_ARBITRARY         (0 << 16)
> > > > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL             (1 << 16)
> > > > +#define       CSI_PP_OUTPUT_FORMAT_PIXEL_REP         (2 << 16)
> > > > +#define       CSI_PP_OUTPUT_FORMAT_STORE             (3 << 16)
> > > > +#define       CSI_PP_VIRTUAL_CHANNEL_ID(n)           (((n) - 1) << 14)
> > > > +#define       CSI_PP_DATA_TYPE(n)                    ((n) << 8)
> > > > +#define       CSI_PP_CRC_CHECK_ENABLE                        BIT(7)
> > > > +#define       CSI_PP_WORD_COUNT_HEADER                       BIT(6)
> > > > +#define       CSI_PP_DATA_IDENTIFIER_ENABLE          BIT(5)
> > > > +#define       CSI_PP_PACKET_HEADER_SENT                      BIT(4)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n)           (0x001c + (n) * 0x2c)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n)         (0x0020 + (n) * 0x2c)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n)                        (0x0024 + (n) * 0x2c)
> > > > +#define       CSI_PP_FRAME_MIN_GAP(n)                        (((n) & 0xffff) << 16)
> > > > +#define       CSI_PP_LINE_MIN_GAP(n)                 (((n) & 0xffff))
> > > > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n)         (0x0028 + (n) * 0x2c)
> > > > +#define       CSI_PP_START_MARKER_FRAME_MAX(n)               (((n) & 0xf) << 12)
> > > > +#define       CSI_PP_START_MARKER_FRAME_MIN(n)               (((n) & 0xf) << 8)
> > > > +#define       CSI_PP_VSYNC_START_MARKER                      BIT(4)
> > > > +#define       CSI_PP_SINGLE_SHOT                     BIT(2)
> > > > +#define       CSI_PP_NOP                             0
> > > > +#define       CSI_PP_ENABLE                          1
> > > > +#define       CSI_PP_DISABLE                         2
> > > > +#define       CSI_PP_RST                             3
> > > > +#define TEGRA_CSI_PHY_CIL_COMMAND                    0x0068
> > > > +#define       CSI_A_PHY_CIL_NOP                              0x0
> > > > +#define       CSI_A_PHY_CIL_ENABLE                   0x1
> > > > +#define       CSI_A_PHY_CIL_DISABLE                  0x2
> > > > +#define       CSI_A_PHY_CIL_ENABLE_MASK                      0x3
> > > > +#define       CSI_B_PHY_CIL_NOP                              (0x0 << 16)
> > > > +#define       CSI_B_PHY_CIL_ENABLE                   (0x1 << 16)
> > > > +#define       CSI_B_PHY_CIL_DISABLE                  (0x2 << 16)
> > > > +#define       CSI_B_PHY_CIL_ENABLE_MASK                      (0x3 << 16)
> > > > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n)                        (0x006c + (n) * 4)
> > > > +#define       CSI_CONTINUOUS_CLOCK_MODE_ENABLE               BIT(5)
> > > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS            0x0078
> > > > +#define TEGRA_CSI_CSI_CIL_STATUS                     0x007c
> > > > +#define       CSI_MIPI_AUTO_CAL_DONE                 BIT(15)
> > > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK    0x0080
> > > > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK             0x0084
> > > > +#define TEGRA_CSI_CSI_READONLY_STATUS                        0x0088
> > > > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND                        0x008c
> > > > +#define TEGRA_CSI_ESCAPE_MODE_DATA                   0x0090
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n)                 (0x0094 + (n) * 8)
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n)                 (0x0098 + (n) * 8)
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG                     0x00a4
> > > > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG                       0x00a8
> > > > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG                       0x00ac
> > > > +#define       CSI_CIL_MIPI_CAL_STARTCAL                      BIT(31)
> > > > +#define       CSI_CIL_MIPI_CAL_OVERIDE_A             BIT(30)
> > > > +#define       CSI_CIL_MIPI_CAL_OVERIDE_B             BIT(30)
> > > > +#define       CSI_CIL_MIPI_CAL_NOISE_FLT(n)          (((n) & 0xf) << 26)
> > > > +#define       CSI_CIL_MIPI_CAL_PRESCALE(n)           (((n) & 0x3) << 24)
> > > > +#define       CSI_CIL_MIPI_CAL_SEL_A                 BIT(21)
> > > > +#define       CSI_CIL_MIPI_CAL_SEL_B                 BIT(21)
> > > > +#define       CSI_CIL_MIPI_CAL_HSPDOS(n)             (((n) & 0x1f) << 16)
> > > > +#define       CSI_CIL_MIPI_CAL_HSPUOS(n)             (((n) & 0x1f) << 8)
> > > > +#define       CSI_CIL_MIPI_CAL_TERMOS(n)             (((n) & 0x1f))
> > > > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS                        0x00b0
> > > > +#define TEGRA_CSI_CLKEN_OVERRIDE                     0x00b4
> > > > +#define TEGRA_CSI_DEBUG_CONTROL                              0x00b8
> > > > +#define       CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED     BIT(0)
> > > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0                BIT(4)
> > > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1                BIT(5)
> > > > +#define       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2                BIT(6)
> > > > +#define       CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v)    ((v) << (8 + 8 * (n)))
> > > > +#define TEGRA_CSI_DEBUG_COUNTER(n)                   (0x00bc + (n) * 4)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n)     (0x00c8 + (n) * 4)
> > > > +#define       CSI_PP_EXP_FRAME_HEIGHT(n)             (((n) & 0x1fff) << 16)
> > > > +#define       CSI_PP_MAX_CLOCKS(n)                   (((n) & 0xfff) << 4)
> > > > +#define       CSI_PP_LINE_TIMEOUT_ENABLE             BIT(0)
> > > > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG                        0x00d0
> > > > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0                       0x00d4
> > > > +#define       CSI_PAD_DRIV_DN_REF(n)                 (((n) & 0x7) << 16)
> > > > +#define       CSI_PAD_DRIV_UP_REF(n)                 (((n) & 0x7) << 8)
> > > > +#define       CSI_PAD_TERM_REF(n)                    (((n) & 0x7) << 0)
> > > > +#define TEGRA_CSI_CSI_CILA_STATUS                    0x00d8
> > > > +#define TEGRA_CSI_CSI_CILB_STATUS                    0x00dc
> > > > +
> > > >  /* --------------------------------------------------------------------------
> > > > - * VI
> > > > + * Read and Write helpers
> > > >   */
> > > >
> > > >  static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > > > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> > > >       writel(val, chan->vi->iomem + addr);
> > > >  }
> > > >
> > > > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > > > +{
> > > > +     return readl(chan->vi->iomem + addr);
> > > > +}
> > > > +
> > > > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > > > +{
> > > > +     writel(val, csi_chan->csi->iomem + addr);
> > > > +}
> > > > +
> > > > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > > > +{
> > > > +     return readl(csi_chan->csi->iomem + addr);
> > > > +}
> > > > +
> > > > +/* --------------------------------------------------------------------------
> > > > + * VI
> > > > + */
> > > > +
> > > >  /*
> > > >   * Get the main input format (YUV/RGB...) and the YUV variant as values to
> > > >   * be written into registers for the current VI input mbus code.
> > > > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > > >  static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > > >  {
> > > >       struct tegra_vi *vi = chan->vi;
> > > > -     struct host1x_syncpt *out_sp;
> > > > +     struct host1x_syncpt *out_sp, *fs_sp;
> > > >
> > > >       out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > >       if (!out_sp)
> > > > -             return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > > > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
> > >
> > > Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
> > >
> >
> > That is interesting. I am fine to switching to any error code as long
> > as it fits here, EBUSY fits fine.
> >
> > > >
> > > >       chan->mw_ack_sp[0] = out_sp;
> > > >
> > > > +     fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > > +     if (!fs_sp)
> > > > +             return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > > > +
> > > > +     chan->frame_start_sp[0] = fs_sp;
> > > > +
> > > >       return 0;
> > > >  }
> > > >
> > > >  static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> > > >  {
> > > >       host1x_syncpt_put(chan->mw_ack_sp[0]);
> > > > +     host1x_syncpt_put(chan->frame_start_sp[0]);
> > > >  }
> > > >
> > > >  static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > > > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> > > >  static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> > > >                                        struct tegra_channel_buffer *buf)
> > > >  {
> > > > +     struct v4l2_subdev *csi_subdev = NULL;
> > > > +     struct tegra_csi_channel *csi_chan = NULL;
> > > > +     u32 port;
> > > >       int err;
> > > >
> > > > -     chan->next_out_sp_idx++;
> > > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > > +     if (csi_subdev) {
> > > > +             /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > > > +             if (!strncmp(csi_subdev->name, "channel", 7)) {
> > > > +                     csi_chan = to_csi_chan(csi_subdev);
> > > > +                     port = csi_chan->csi_port_nums[0] & 1;
> > > > +             }
> > > > +     }
> > >
> > > tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
> > >
> >
> > That is possible.
> >
> > > Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
> > >
> >
> > I may try that. My main concern was VIP. Unlike Tegra210,
> > Tegra20/Tegra30 have VIP which can cause issues if no additional
> > checks are done.
> >
> > > Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
> > >
> >
> > Yes, I hope so. We did not implement this logic, it existed before, we
> > just expanded it to support CSI.
>
> If it's non-trivial it can be left for later.
>

No no, I have some ideas that may address this.

> >
> > > >
> > > >       tegra20_channel_vi_buffer_setup(chan, buf);
> > > >
> > > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > +     if (csi_chan) {
> > > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > +                               CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > > > +
> > > > +             chan->next_fs_sp_idx++;
> > > > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > > > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > > +             if (err) {
> > > > +                     host1x_syncpt_incr(chan->frame_start_sp[0]);
> > >
> > > This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
> > >
> >
> > The race condition should be avoidable by resetting pixel parser and
> > checking syncpt value again.
> > Incrementing the software reference counter only if hardware completed
> > successfully sounds like a good idea.
> >
> > > Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
> > >
> > > (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
> > >
> > > > +                     if (err != -ERESTARTSYS)
> > > > +                             dev_err_ratelimited(&chan->video.dev,
> > > > +                                                 "frame start syncpt timeout: %d\n", err);
> > > > +             }
> > > > +
> > > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > +                               CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > +                               CSI_PP_DISABLE);
> > > > +     } else {
> > > > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > +     }
> > > >
> > > > -     /* Wait for syncpt counter to reach frame start event threshold */
> > > > +     chan->next_out_sp_idx++;
> > > >       err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> > > >                                TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > >       if (err) {
> > > >               host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > > > -             dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > > > -             release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > > > -             return err;
> > > > +             if (err != -ERESTARTSYS)
> > > > +                     dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> > > >       }
> > > >
> > > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > > -                      VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > +     if (!csi_chan)
> > > > +             tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > > +                              VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > >
> > > >       release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> > > >
> > > > -     return 0;
> > > > +     return err;
> > > >  }
> > > >
> > > >  static int tegra20_chan_capture_kthread_start(void *data)
> > > > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > >       int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > > >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > >                             OUT_2 : OUT_1;
> > > > -     int main_output_format;
> > > > -     int yuv_output_format;
> > > > -
> > > > -     tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > > > -
> > > > -     /*
> > > > -      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > > > -      * for luminance, which is the default and means not to touch
> > > > -      * anything.
> > > > -      */
> > > > -     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > > -                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > > -                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > > -
> > > > -     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > > -     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > > -
> > > > -     tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > -                      (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > -                      (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > -                      yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > > > -                      main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> > > >
> > > >       /* Set up frame size */
> > > >       tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > > > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > >       tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> > > >  }
> > > >
> > > > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > +     struct tegra_csi *csi = csi_chan->csi;
> > > > +     void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > > +     unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > > > +     u32 value, pp, cil;
> > > > +     int ret;
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > > > +                       CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > > > +                       CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > > > +                       CSI_CIL_MIPI_CAL_TERMOS(0));
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > > > +                       CSI_PAD_DRIV_DN_REF(5) |
> > > > +                       CSI_PAD_DRIV_UP_REF(7) |
> > > > +                       CSI_PAD_TERM_REF(0));
> > > > +
> > > > +     /* CSI B */
> > > > +     value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > > > +
> > > > +     if (port == PORT_B || csi_chan->numlanes == 4)
> > > > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > > > +
> > > > +     /* CSI A */
> > > > +     value = CSI_CIL_MIPI_CAL_STARTCAL |
> > > > +             CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > > +             CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > > +             CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > +             CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > +             CSI_CIL_MIPI_CAL_TERMOS(4);
> > > > +
> > > > +     if (port == PORT_A)
> > > > +             value |= CSI_CIL_MIPI_CAL_SEL_A;
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > > +
> > > > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > > +                                      value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > > > +     if (ret < 0) {
> > > > +             dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > > > +             goto exit;
> > > > +     }
> > > > +
> > > > +     /* clear status */
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > > +     ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > > +                                      !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > > > +     if (ret < 0) {
> > > > +             dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > > > +             goto exit;
> > > > +     }
> > > > +
> > > > +     pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > > +     cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > > +     if (pp | cil) {
> > > > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > > +             ret = -EINVAL;
> > > > +             goto exit;
> > > > +     }
> > > > +
> > > > +exit:
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > > +
> > > > +     /* un-select to avoid interference with DSI */
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > > > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > > > +                       CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > > +                       CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > > +                       CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > +                       CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > +                       CSI_CIL_MIPI_CAL_TERMOS(4));
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > >  static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > >  {
> > > >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > >       struct media_pipeline *pipe = &chan->video.pipe;
> > > > +     struct v4l2_subdev *csi_subdev, *src_subdev;
> > > > +     struct tegra_csi_channel *csi_chan = NULL;
> > > >       int err;
> > > >
> > > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > > +     if (csi_subdev) {
> > > > +             if (!strncmp(csi_subdev->name, "channel", 7))
> > > > +                     csi_chan = to_csi_chan(csi_subdev);
> > > > +     }
> > > > +
> > > > +     chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> > > >       chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> > > >
> > > >       err = video_device_pipeline_start(&chan->video, pipe);
> > > >       if (err)
> > > >               goto error_pipeline_start;
> > > >
> > > > -     tegra20_camera_capture_setup(chan);
> > > > +     /*
> > > > +      * Set up low pass filter.  Use 0x240 for chromaticity and 0x240
> > > > +      * for luminance, which is the default and means not to touch
> > > > +      * anything.
> > > > +      */
> > > > +     tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > > +                      0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > > +                      0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > > +
> > > > +     /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > > +     tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > >
> > > >       err = tegra_channel_set_stream(chan, true);
> > > >       if (err)
> > > >               goto error_set_stream;
> > > >
> > > > +     tegra20_camera_capture_setup(chan);
> > > > +
> > > > +     if (csi_chan) {
> > > > +             /*
> > > > +              * TRM has incorrectly documented to wait for done status from
> > > > +              * calibration logic after CSI interface power on.
> > > > +              * As per the design, calibration results are latched and applied
> > > > +              * to the pads only when the link is in LP11 state which will happen
> > > > +              * during the sensor stream-on.
> > > > +              * CSI subdev stream-on triggers start of MIPI pads calibration.
> > > > +              * Wait for calibration to finish here after sensor subdev stream-on.
> > > > +              */
> > > > +             src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > > +             if (!src_subdev->s_stream_enabled) {
> > > > +                     err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > > > +                     if (err < 0 && err != -ENOIOCTLCMD)
> > > > +                             goto error_set_stream;
> > > > +             }
> > > > +
> > > > +             tegra20_csi_pad_calibration(csi_chan);
> > > > +     }
> > > > +
> > > >       chan->sequence = 0;
> > > >
> > > >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > >  static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> > > >  {
> > > >       struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > > +     struct v4l2_subdev *src_subdev;
> > > >
> > > >       if (chan->kthread_start_capture) {
> > > >               kthread_stop(chan->kthread_start_capture);
> > > >               chan->kthread_start_capture = NULL;
> > > >       }
> > > >
> > > > +     src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > > +     if (src_subdev->s_stream_enabled)
> > > > +             v4l2_subdev_call(src_subdev, video, s_stream, false);
> > > > +
> > > >       tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> > > >       tegra_channel_set_stream(chan, false);
> > > >       video_device_pipeline_stop(&chan->video);
> > > > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > > >       .default_video_format = &tegra20_video_formats[0],
> > > >       .ops = &tegra20_vi_ops,
> > > >       .hw_revision = 1,
> > > > -     .vi_max_channels = 1, /* parallel input (VIP) */
> > > > +     .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> > > >       .vi_max_clk_hz = 450000000,
> > > >       .has_h_v_flip = true,
> > > >  };
> > > >
> > > > +/* --------------------------------------------------------------------------
> > > > + * CSI
> > > > + */
> > > > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > > > +                       CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > > > +}
> > > > +
> > > > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > > > +                                         u8 portno)
> > > > +{
> > > > +     struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > > > +     int width  = vi_chan->format.width;
> > > > +     int height = vi_chan->format.height;
> > > > +     u32 data_type = vi_chan->fmtinfo->img_dt;
> > > > +     u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > > > +     int output_channel = OUT_1;
> > > > +
> > > > +     unsigned int main_output_format, yuv_output_format;
> > > > +     unsigned int port = portno & 1;
> > > > +     u32 value;
> > > > +
> > > > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > > +
> > > > +     switch (data_type) {
> > > > +     case TEGRA_IMAGE_DT_RAW8:
> > > > +     case TEGRA_IMAGE_DT_RAW10:
> > > > +             output_channel = OUT_2;
> > > > +             if (port == PORT_A)
> > > > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > > > +             else
> > > > +                     main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > > > +             break;
> > > > +     }
> > > > +
> > > > +     tegra20_csi_capture_clean(csi_chan);
> > > > +
> > > > +     /* CSI port cleanup */
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > > > +                       CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > > > +                       CSI_PP_EXP_FRAME_HEIGHT(height) |
> > > > +                       CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > > > +                       CSI_PP_LINE_TIMEOUT_ENABLE);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > > > +                       CSI_PP_OUTPUT_FORMAT_PIXEL |
> > > > +                       CSI_PP_DATA_TYPE(data_type) |
> > > > +                       CSI_PP_CRC_CHECK_ENABLE |
> > > > +                       CSI_PP_WORD_COUNT_HEADER |
> > > > +                       CSI_PP_DATA_IDENTIFIER_ENABLE |
> > > > +                       CSI_PP_PACKET_HEADER_SENT |
> > > > +                       port);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > > > +                       CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > > > +                       (csi_chan->numlanes - 1));
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > > > +                       CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > > > +                       0x5); /* Clock settle time */
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > > > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > > +                      host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > > > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > > > +                      VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > > +                      host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > > > +                      << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > > +
> > > > +     value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > > > +             CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > +                       CSI_PP_DISABLE);
> > > > +
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > +                      yuv_output_format | main_output_format);
> > > > +
> > > > +     return 0;
> > > > +};
> > > > +
> > > > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > > > +{
> > > > +     struct tegra_csi *csi = csi_chan->csi;
> > > > +     unsigned int port = portno & 1;
> > > > +     u32 value;
> > > > +
> > > > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > > > +
> > > > +     value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > > +     dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > > +
> > > > +     tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > +                       CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > +                       CSI_PP_DISABLE);
> > > > +
> > > > +     if (csi_chan->numlanes == 4) {
> > > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > > > +                               CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > > > +     } else {
> > > > +             value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > > > +                     CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > > > +             tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > > +     }
> > > > +}
> > > > +
> > > > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > +     u8 *portnos = csi_chan->csi_port_nums;
> > > > +     int ret, i;
> > > > +
> > > > +     for (i = 0; i < csi_chan->numgangports; i++) {
> > > > +             ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > > > +             if (ret)
> > > > +                     goto stream_start_fail;
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +
> > > > +stream_start_fail:
> > > > +     for (i = i - 1; i >= 0; i--)
> > > > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > > +
> > > > +     return ret;
> > > > +}
> > > > +
> > > > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > +     u8 *portnos = csi_chan->csi_port_nums;
> > > > +     int i;
> > > > +
> > > > +     for (i = 0; i < csi_chan->numgangports; i++)
> > > > +             tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > > +}
> > > > +
> > > > +/* Tegra20 CSI operations */
> > > > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > > > +     .csi_start_streaming = tegra20_csi_start_streaming,
> > > > +     .csi_stop_streaming = tegra20_csi_stop_streaming,
> > > > +};
> > > > +
> > > > +static const char * const tegra20_csi_clks[] = {
> > > > +     "csi",
> > > > +};
> > > > +
> > > > +/* Tegra20 CSI SoC data */
> > > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > > +     .ops = &tegra20_csi_ops,
> > > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > > +     .clk_names = tegra20_csi_clks,
> > > > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > > +     .has_mipi_calibration = false,
> > > > +};
> > > > +
> > > > +static const char * const tegra30_csi_clks[] = {
> > > > +     "csi",
> > > > +     "csia_pad",
> > > > +     "csib_pad",
> > > > +};
> > > > +
> > > > +/* Tegra30 CSI SoC data */
> > > > +const struct tegra_csi_soc tegra30_csi_soc = {
> > > > +     .ops = &tegra20_csi_ops,
> > > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > > +     .clk_names = tegra30_csi_clks,
> > > > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > > +     .has_mipi_calibration = false,
> > > > +};
> > > > +
> > > >  /* --------------------------------------------------------------------------
> > > >   * VIP
> > > >   */
> > > > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > > >                             data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > >                             OUT_2 : OUT_1;
> > > >
> > > > -     unsigned int main_input_format;
> > > > -     unsigned int yuv_input_format;
> > > > +     unsigned int main_input_format, yuv_input_format;
> > > > +     unsigned int main_output_format, yuv_output_format;
> > > >
> > > >       tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > > > +     tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > >
> > > >       tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> > > >
> > > > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > > >
> > > >       tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> > > >
> > > > +     tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > +                      (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > +                      (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > +                       yuv_output_format | main_output_format);
> > > > +
> > > >       return 0;
> > > >  }
> > > >
> > > > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > > > index cac0c0d0e225..c02517c9e09b 100644
> > > > --- a/drivers/staging/media/tegra-video/vi.h
> > > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > > @@ -127,6 +127,7 @@ struct tegra_vi {
> > > >   *           frame through host1x syncpoint counters (On Tegra20 used for the
> > > >   *              OUT_1 syncpt)
> > > >   * @sp_incr_lock: protects cpu syncpoint increment.
> > > > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> > > >   * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> > > >   *
> > > >   * @kthread_start_capture: kthread to start capture of single frame when
> > > > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> > > >       /* protects the cpu syncpoint increment */
> > > >       spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> > > >       u32 next_out_sp_idx;
> > > > +     u32 next_fs_sp_idx;
> > > >
> > > >       struct task_struct *kthread_start_capture;
> > > >       wait_queue_head_t start_wait;
> > > > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > > > index a25885f93cd7..8fa660431eb0 100644
> > > > --- a/drivers/staging/media/tegra-video/video.c
> > > > +++ b/drivers/staging/media/tegra-video/video.c
> > > > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> > > >
> > > >  static const struct of_device_id host1x_video_subdevs[] = {
> > > >  #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > +     { .compatible = "nvidia,tegra20-csi", },
> > > >       { .compatible = "nvidia,tegra20-vip", },
> > > >       { .compatible = "nvidia,tegra20-vi", },
> > > >  #endif
> > > >  #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > +     { .compatible = "nvidia,tegra30-csi", },
> > > >       { .compatible = "nvidia,tegra30-vip", },
> > > >       { .compatible = "nvidia,tegra30-vi", },
> > > >  #endif
> > > >
> > >
> > >
> > >
> > >
>
>
>
>

^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
  2025-09-02  5:05     ` Svyatoslav Ryhel
@ 2025-09-02  6:35       ` Mikko Perttunen
  0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02  6:35 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
	linux-kernel, linux-clk, linux-staging

On Tuesday, September 2, 2025 2:05 PM Svyatoslav Ryhel wrote:
> вт, 2 вер. 2025 р. о 03:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> > > all MIPI calibration pads were part of VI block.
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > >  drivers/staging/media/tegra-video/csi.c      | 12 +++++++-----
> > >  drivers/staging/media/tegra-video/csi.h      |  1 +
> > >  drivers/staging/media/tegra-video/tegra210.c |  1 +
> > >  3 files changed, 9 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c
> > > b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> > > 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> > > *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
> > >               return 0;
> > >
> > > -     chan->mipi = tegra_mipi_request(csi->dev, node);
> > > -     if (IS_ERR(chan->mipi)) {
> > > -             ret = PTR_ERR(chan->mipi);
> > > -             chan->mipi = NULL;
> > > -             dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> > > +     if (csi->soc->has_mipi_calibration) {
> > > +             chan->mipi = tegra_mipi_request(csi->dev, node);
> >
> > The way I would read 'soc->has_mipi_calibration' is that this device (CSI)
> > contains the MIPI calibration hardware. I.e. the opposite of here. I would
> > invert the logic and optionally call it e.g. 'internal_mipi_calib'.
> >
> > A cleaner way to do this might be to always call tegra_mipi_request et al. --
> > on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the
> > callbacks registered in the MIPI driver as we discussed before. That way the
> > CSI driver won't need separate code paths for SoCs with internal MIPI
> > calibration and SoCs with the external MIPI calibration device.
> >
> 
> So basically MIPI calibration device for Tegra20/Tegra30 has to be
> created within CSI and when MIPI calibration is requested, CSI phandle
> is used. Question: may I use a dedicated node for MIPI calibration
> within CSI or it has to use CSI node itself? With dedicated node
> configuration should be much simpler and can help avoiding probe of
> entire.

I think it'd better to use the CSI node itself. The calibration registers are somewhat scattered in the address space so it's hard to argue for the MIPI calibration to be a subdevice of CSI.

If it's problematic, we can also just call the calibration logic internally within the driver. But in that case also I'd place both the DSI and CSI calibration logic together in one place since AIUI they can interact with each other.

> 
> > Cheers,
> > Mikko
> >
> > > +             if (IS_ERR(chan->mipi)) {
> > > +                     ret = PTR_ERR(chan->mipi);
> > > +                     chan->mipi = NULL;
> > > +                     dev_err(csi->dev, "failed to get mipi device:
> > %d\n", ret);
> > > +             }
> > >       }
> > >
> > >       return ret;
> > > diff --git a/drivers/staging/media/tegra-video/csi.h
> > > b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> > > 100644
> > > --- a/drivers/staging/media/tegra-video/csi.h
> > > +++ b/drivers/staging/media/tegra-video/csi.h
> > > @@ -128,6 +128,7 @@ struct tegra_csi_soc {
> > >       unsigned int num_clks;
> > >       const struct tpg_framerate *tpg_frmrate_table;
> > >       unsigned int tpg_frmrate_table_size;
> > > +     bool has_mipi_calibration;
> > >  };
> > >
> > >  /**
> > > diff --git a/drivers/staging/media/tegra-video/tegra210.c
> > > b/drivers/staging/media/tegra-video/tegra210.c index
> > > da99f19a39e7..305472e94af4 100644
> > > --- a/drivers/staging/media/tegra-video/tegra210.c
> > > +++ b/drivers/staging/media/tegra-video/tegra210.c
> > > @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
> > >       .num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
> > >       .tpg_frmrate_table = tegra210_tpg_frmrate_table,
> > >       .tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> > > +     .has_mipi_calibration = true,
> > >  };
> >
> >
> >
> >





^ permalink raw reply	[flat|nested] 59+ messages in thread

* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-02  2:38   ` Mikko Perttunen
  2025-09-02  5:51     ` Svyatoslav Ryhel
@ 2025-09-02  7:11     ` Dan Carpenter
  1 sibling, 0 replies; 59+ messages in thread
From: Dan Carpenter @ 2025-09-02  7:11 UTC (permalink / raw)
  To: Mikko Perttunen, Uwe Kleine-König
  Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
	Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
	Dmitry Osipenko, Charan Pedumuru, linux-media, linux-tegra,
	dri-devel, devicetree, linux-kernel, linux-clk, linux-staging

On Tue, Sep 02, 2025 at 11:38:18AM +0900, Mikko Perttunen wrote:
> > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> >  static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> >  {
> >  	struct tegra_vi *vi = chan->vi;
> > -	struct host1x_syncpt *out_sp;
> > +	struct host1x_syncpt *out_sp, *fs_sp;
> >  
> >  	out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> >  	if (!out_sp)
> > -		return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > +		return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
> 
> Existing issue, but dev_err_probe doesn't print anything when the error is
> -ENOMEM, since "there is already enough output". But that's not necessarily
> the case with failing syncpoint allocation. Maybe we should be using a
> different error code like EBUSY?
> 

I'm not sure I love the rule that -ENOMEM doesn't print a message.
Deleting error messages is fine because it makes the code simpler and
saves a little memory.  But with dev_err_probe() the message is still
there in the memory, we just don't print it.  Printing the error message
doesn't hurt anything.

But if we go down that road, we should make it make it a checkpatch
warning to pass a hard coded -ENOMEM to dev_err_probe().

regards,
dan carpenter

^ permalink raw reply	[flat|nested] 59+ messages in thread

end of thread, other threads:[~2025-09-02  7:12 UTC | newest]

Thread overview: 59+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
2025-08-27  4:09   ` Mikko Perttunen
2025-08-27  4:32     ` Svyatoslav
2025-08-27 10:36       ` Mikko Perttunen
2025-08-27 10:45         ` Svyatoslav Ryhel
2025-08-28  8:13           ` Mikko Perttunen
2025-08-28  8:28             ` Svyatoslav Ryhel
2025-08-28 10:15               ` Mikko Perttunen
2025-08-28 10:23                 ` Svyatoslav Ryhel
2025-08-29  0:29                   ` Mikko Perttunen
2025-08-29  7:05                     ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
2025-08-22 13:59   ` Rob Herring
2025-08-27  4:19   ` Mikko Perttunen
2025-08-27  4:28     ` Svyatoslav
2025-08-27 10:27       ` Mikko Perttunen
2025-08-29  6:54         ` Krzysztof Kozlowski
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
2025-08-27  4:26   ` Mikko Perttunen
2025-08-29  0:44   ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
2025-08-19 20:27   ` Rob Herring
2025-08-20  5:36     ` Svyatoslav Ryhel
2025-08-29  6:42     ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
2025-08-27  4:29   ` Mikko Perttunen
2025-08-27  4:47     ` Svyatoslav
2025-08-29  0:56       ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
2025-09-02  0:46   ` Mikko Perttunen
2025-09-02  5:05     ` Svyatoslav Ryhel
2025-09-02  6:35       ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
2025-09-02  0:51   ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
2025-09-02  1:00   ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
2025-09-02  1:09   ` Mikko Perttunen
2025-09-02  5:11     ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
2025-09-02  1:16   ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
2025-08-19 20:30   ` Rob Herring
2025-08-20  5:39     ` Svyatoslav Ryhel
2025-08-22 14:06       ` Rob Herring
2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
2025-09-02  2:38   ` Mikko Perttunen
2025-09-02  5:51     ` Svyatoslav Ryhel
2025-09-02  6:17       ` Mikko Perttunen
2025-09-02  6:21         ` Svyatoslav Ryhel
2025-09-02  7:11     ` Dan Carpenter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).