devicetree.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30
@ 2025-09-06 13:53 Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114 Svyatoslav Ryhel
                   ` (23 more replies)
  0 siblings, 24 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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.

---
Changes in v2:
- vi_sensor gated through csus
- TEGRA30_CLK_CLK_MAX moved to clk-tegra30
- adjusted commit titles and messages
- clk_register_clkdev dropped from pad clock registration
- removed tegra30-vi/vip and used tegra20 fallback
- added separate csi schema for tegra20-csi and tegra30-csi
- fixet number of VI channels
- adjusted tegra_vi_out naming
- fixed yuv_input_format to main_input_format
- MIPI calibration refsctored for Tegra114+ and added support for
  pre-Tegra114 to use CSI as a MIPI calibration device
- switched ENOMEM to EBUSY
- added check into tegra_channel_get_remote_csi_subdev
- moved avdd-dsi-csi-supply into CSI
- next_fs_sp_idx > next_fs_sp_value
- removed host1x_syncpt_incr from framecounted syncpoint
- csi subdev request moved before frame cycle
---

Svyatoslav Ryhel (23):
  clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and
    Tegra114
  dt-bindings: clock: tegra30: Add IDs for CSI pad clocks
  clk: tegra30: add CSI pad clock gates
  dt-bindings: display: tegra: document Tegra30 VI and VIP
  staging: media: tegra-video: expand VI and VIP support to Tegra30
  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: csi: move CSI helpers to header
  gpu: host1x: convert MIPI to use operations
  staging: media: tegra-video: csi: add support for SoCs with integrated
    MIPI calibration
  staging: media: tegra-video: csi: add a check to
    tegra_channel_get_remote_csi_subdev
  dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  staging: media: tegra-video: csi: move avdd-dsi-csi-supply from VI to
    CSI
  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 nodes for Tegra20 and Tegra30
  staging: media: tegra-video: add CSI support for Tegra20 and Tegra30

 .../display/tegra/nvidia,tegra20-csi.yaml     | 104 +++
 .../display/tegra/nvidia,tegra20-vi.yaml      |  22 +-
 .../display/tegra/nvidia,tegra20-vip.yaml     |   9 +-
 .../display/tegra/nvidia,tegra210-csi.yaml    |   3 +
 .../display/tegra/nvidia,tegra30-csi.yaml     | 115 +++
 arch/arm/boot/dts/nvidia/tegra20.dtsi         |  19 +-
 arch/arm/boot/dts/nvidia/tegra30.dtsi         |  24 +-
 drivers/clk/tegra/clk-tegra114.c              |   7 +-
 drivers/clk/tegra/clk-tegra20.c               |   7 +-
 drivers/clk/tegra/clk-tegra30.c               |  21 +-
 drivers/gpu/drm/tegra/dsi.c                   |   1 +
 drivers/gpu/host1x/mipi.c                     |  58 +-
 drivers/staging/media/tegra-video/Makefile    |   1 +
 drivers/staging/media/tegra-video/csi.c       |  66 +-
 drivers/staging/media/tegra-video/tegra20.c   | 793 +++++++++++++++---
 drivers/staging/media/tegra-video/tegra210.c  |   2 +-
 drivers/staging/media/tegra-video/vi.c        |  54 +-
 drivers/staging/media/tegra-video/vi.h        |   9 +-
 drivers/staging/media/tegra-video/video.c     |   8 +-
 drivers/staging/media/tegra-video/vip.c       |   4 +-
 include/dt-bindings/clock/tegra30-car.h       |   3 +-
 include/linux/host1x.h                        |  10 -
 .../csi.h => include/linux/tegra-csi.h        |  18 +
 include/linux/tegra-mipi-cal.h                | 143 ++++
 24 files changed, 1269 insertions(+), 232 deletions(-)
 create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
 create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
 rename drivers/staging/media/tegra-video/csi.h => include/linux/tegra-csi.h (88%)
 create mode 100644 include/linux/tegra-mipi-cal.h

-- 
2.48.1


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

* [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-19  6:29   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks Svyatoslav Ryhel
                   ` (22 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

CSUS clock which is camera MCLK, is also a clock gate for vi_sensor so
lets model it by creating CSUS grate with vi_sensor as a parent.

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

diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 186b0b81c1ec..00282b0d3763 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -691,7 +691,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true },
 	[tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true },
 	[tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true },
-	[tegra_clk_csus] = { .dt_id = TEGRA114_CLK_CSUS, .present = true },
 	[tegra_clk_mselect] = { .dt_id = TEGRA114_CLK_MSELECT, .present = true },
 	[tegra_clk_tsensor] = { .dt_id = TEGRA114_CLK_TSENSOR, .present = true },
 	[tegra_clk_i2s3] = { .dt_id = TEGRA114_CLK_I2S3, .present = true },
@@ -1047,6 +1046,12 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
 					     0, 82, periph_clk_enb_refcnt);
 	clks[TEGRA114_CLK_DSIB] = clk;
 
+	/* csus */
+	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
+					     clk_base, 0, TEGRA114_CLK_CSUS,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA114_CLK_CSUS] = clk;
+
 	/* emc mux */
 	clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
 			       ARRAY_SIZE(mux_pllmcp_clkm),
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 2c58ce25af75..bf9a9f8ddf62 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -530,7 +530,6 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_rtc] = { .dt_id = TEGRA20_CLK_RTC, .present = true },
 	[tegra_clk_timer] = { .dt_id = TEGRA20_CLK_TIMER, .present = true },
 	[tegra_clk_kbc] = { .dt_id = TEGRA20_CLK_KBC, .present = true },
-	[tegra_clk_csus] = { .dt_id = TEGRA20_CLK_CSUS, .present = true },
 	[tegra_clk_vcp] = { .dt_id = TEGRA20_CLK_VCP, .present = true },
 	[tegra_clk_bsea] = { .dt_id = TEGRA20_CLK_BSEA, .present = true },
 	[tegra_clk_bsev] = { .dt_id = TEGRA20_CLK_BSEV, .present = true },
@@ -807,6 +806,12 @@ static void __init tegra20_periph_clk_init(void)
 	clk_register_clkdev(clk, NULL, "dsi");
 	clks[TEGRA20_CLK_DSI] = clk;
 
+	/* csus */
+	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
+					     clk_base, 0, TEGRA20_CLK_CSUS,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA20_CLK_CSUS] = clk;
+
 	/* pex */
 	clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70,
 				    periph_clk_enb_refcnt);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 82a8cb9545eb..ca367184e185 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -779,7 +779,6 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
 	[tegra_clk_rtc] = { .dt_id = TEGRA30_CLK_RTC, .present = true },
 	[tegra_clk_timer] = { .dt_id = TEGRA30_CLK_TIMER, .present = true },
 	[tegra_clk_kbc] = { .dt_id = TEGRA30_CLK_KBC, .present = true },
-	[tegra_clk_csus] = { .dt_id = TEGRA30_CLK_CSUS, .present = true },
 	[tegra_clk_vcp] = { .dt_id = TEGRA30_CLK_VCP, .present = true },
 	[tegra_clk_bsea] = { .dt_id = TEGRA30_CLK_BSEA, .present = true },
 	[tegra_clk_bsev] = { .dt_id = TEGRA30_CLK_BSEV, .present = true },
@@ -1008,6 +1007,12 @@ static void __init tegra30_periph_clk_init(void)
 				    0, 48, periph_clk_enb_refcnt);
 	clks[TEGRA30_CLK_DSIA] = clk;
 
+	/* csus */
+	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
+					     clk_base, 0, TEGRA30_CLK_CSUS,
+					     periph_clk_enb_refcnt);
+	clks[TEGRA30_CLK_CSUS] = 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] 71+ messages in thread

* [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114 Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-07  9:34   ` Krzysztof Kozlowski
  2025-09-06 13:53 ` [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates Svyatoslav Ryhel
                   ` (21 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Tegra30 has CSI pad clock enable bits embedded into PLLD/PLLD2 registers.
Add ids for these clocks. Additionally, move TEGRA30_CLK_CLK_MAX into
clk-tegra30 source.

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

diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index ca367184e185..ca738bc64615 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -53,6 +53,7 @@
 #define SYSTEM_CLK_RATE 0x030
 
 #define TEGRA30_CLK_PERIPH_BANKS	5
+#define TEGRA30_CLK_CLK_MAX		311
 
 #define PLLC_BASE 0x80
 #define PLLC_MISC 0x8c
diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
index f193663e6f28..763b81f80908 100644
--- a/include/dt-bindings/clock/tegra30-car.h
+++ b/include/dt-bindings/clock/tegra30-car.h
@@ -271,6 +271,7 @@
 #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
 
 #endif	/* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
-- 
2.48.1


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

* [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114 Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-19  6:33   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP Svyatoslav Ryhel
                   ` (20 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Tegra30 has CSI pad bits in both PLLD and PLLD2 clocks that are required
for the correct work of the CSI block. Add CSI pad A and pad B clock gates
with PLLD/PLLD2 parents, respectively. Add plld2 spinlock, like one plld
has to be used for clock gate registration.

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

diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index ca738bc64615..61fe527ee6c1 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -154,6 +154,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,16 @@ 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);
+	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);
+	clks[TEGRA30_CLK_CSIB_PAD] = clk;
+
 	/* csus */
 	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
 					     clk_base, 0, TEGRA30_CLK_CSUS,
-- 
2.48.1


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

* [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (2 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 19:17   ` Rob Herring (Arm)
  2025-09-06 13:53 ` [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
                   ` (19 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Existing Parallel VI interface schema for Tegra20 is fully compatible with
Tegra30; hence, lets reuse it by setting fallback for Tegra30.

Adjust existing VI schema to reflect that Tegra20 VI is compatible with
Tegra30 by setting a fallback for Tegra30. Additionally, switch to using
an enum instead of list of const.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../display/tegra/nvidia,tegra20-vi.yaml      | 19 ++++++++++++-------
 .../display/tegra/nvidia,tegra20-vip.yaml     |  9 +++++++--
 2 files changed, 19 insertions(+), 9 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
index 2181855a0920..dd67d4162884 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
@@ -16,16 +16,21 @@ properties:
 
   compatible:
     oneOf:
-      - const: nvidia,tegra20-vi
-      - const: nvidia,tegra30-vi
-      - const: nvidia,tegra114-vi
-      - const: nvidia,tegra124-vi
+      - enum:
+          - nvidia,tegra20-vi
+          - nvidia,tegra114-vi
+          - nvidia,tegra124-vi
+          - nvidia,tegra210-vi
+          - nvidia,tegra186-vi
+          - nvidia,tegra194-vi
+
+      - items:
+          - const: nvidia,tegra30-vi
+          - const: nvidia,tegra20-vi
+
       - items:
           - const: nvidia,tegra132-vi
           - const: nvidia,tegra124-vi
-      - const: nvidia,tegra210-vi
-      - const: nvidia,tegra186-vi
-      - const: nvidia,tegra194-vi
 
   reg:
     maxItems: 1
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
index 14294edb8d8c..c135f1bd98a9 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
@@ -11,8 +11,13 @@ maintainers:
 
 properties:
   compatible:
-    enum:
-      - nvidia,tegra20-vip
+    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 related	[flat|nested] 71+ messages in thread

* [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (3 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-17  7:52   ` Luca Ceresoli
  2025-09-06 13:53 ` [PATCH v2 06/23] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
                   ` (18 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Existing 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     | 2 +-
 drivers/staging/media/tegra-video/vi.h     | 2 +-
 drivers/staging/media/tegra-video/video.c  | 2 +-
 drivers/staging/media/tegra-video/vip.c    | 4 ++--
 5 files changed, 6 insertions(+), 5 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..7c44a3448588 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1956,7 +1956,7 @@ static void tegra_vi_remove(struct platform_device *pdev)
 }
 
 static const struct of_device_id tegra_vi_of_id_table[] = {
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 	{ .compatible = "nvidia,tegra20-vi",  .data = &tegra20_vi_soc },
 #endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
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..6fe8d5301b9c 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -123,7 +123,7 @@ 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)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 	{ .compatible = "nvidia,tegra20-vip", },
 	{ .compatible = "nvidia,tegra20-vi", },
 #endif
diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c
index 5ec717f3afd5..34397b73bb61 100644
--- a/drivers/staging/media/tegra-video/vip.c
+++ b/drivers/staging/media/tegra-video/vip.c
@@ -263,12 +263,12 @@ 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)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
 	{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
 #endif
 	{ }
-- 
2.48.1


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

* [PATCH v2 06/23] staging: media: tegra-video: vi: adjust get_selection op check
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (4 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 07/23] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
                   ` (17 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 7c44a3448588..856b7c18b551 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] 71+ messages in thread

* [PATCH v2 07/23] staging: media: tegra-video: vi: add flip controls only if no source controls are provided
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (5 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 06/23] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 08/23] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
                   ` (16 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 856b7c18b551..90473729b546 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] 71+ messages in thread

* [PATCH v2 08/23] staging: media: tegra-video: csi: move CSI helpers to header
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (6 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 07/23] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations Svyatoslav Ryhel
                   ` (15 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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] 71+ messages in thread

* [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (7 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 08/23] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-19  6:47   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 10/23] staging: media: tegra-video: csi: add support for SoCs with integrated MIPI calibration Svyatoslav Ryhel
                   ` (14 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

This commit converts the existing MIPI code to use operations, which is a
necessary step for the Tegra20/Tegra30 SoCs. Additionally, it creates a
dedicated header file, tegra-mipi-cal.h, to contain the MIPI calibration
functions, improving code organization and readability.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/gpu/drm/tegra/dsi.c             |   1 +
 drivers/gpu/host1x/mipi.c               |  40 +++------
 drivers/staging/media/tegra-video/csi.c |   1 +
 include/linux/host1x.h                  |  10 ---
 include/linux/tegra-mipi-cal.h          | 111 ++++++++++++++++++++++++
 5 files changed, 126 insertions(+), 37 deletions(-)
 create mode 100644 include/linux/tegra-mipi-cal.h

diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 64f12a85a9dd..278bf2c85524 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -14,6 +14,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 #include <linux/reset.h>
+#include <linux/tegra-mipi-cal.h>
 
 #include <video/mipi_display.h>
 
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
index e51b43dd15a3..2fa339a428f3 100644
--- a/drivers/gpu/host1x/mipi.c
+++ b/drivers/gpu/host1x/mipi.c
@@ -27,6 +27,7 @@
 #include <linux/of_platform.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
+#include <linux/tegra-mipi-cal.h>
 
 #include "dev.h"
 
@@ -116,23 +117,6 @@ struct tegra_mipi_soc {
 	u8 hsclkpuos;
 };
 
-struct tegra_mipi {
-	const struct tegra_mipi_soc *soc;
-	struct device *dev;
-	void __iomem *regs;
-	struct mutex lock;
-	struct clk *clk;
-
-	unsigned long usage_count;
-};
-
-struct tegra_mipi_device {
-	struct platform_device *pdev;
-	struct tegra_mipi *mipi;
-	struct device *device;
-	unsigned long pads;
-};
-
 static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
 				   unsigned long offset)
 {
@@ -261,7 +245,7 @@ void tegra_mipi_free(struct tegra_mipi_device *device)
 }
 EXPORT_SYMBOL(tegra_mipi_free);
 
-int tegra_mipi_enable(struct tegra_mipi_device *dev)
+static int tegra114_mipi_enable(struct tegra_mipi_device *dev)
 {
 	int err = 0;
 
@@ -273,11 +257,9 @@ int tegra_mipi_enable(struct tegra_mipi_device *dev)
 	mutex_unlock(&dev->mipi->lock);
 
 	return err;
-
 }
-EXPORT_SYMBOL(tegra_mipi_enable);
 
-int tegra_mipi_disable(struct tegra_mipi_device *dev)
+static int tegra114_mipi_disable(struct tegra_mipi_device *dev)
 {
 	int err = 0;
 
@@ -289,11 +271,9 @@ int tegra_mipi_disable(struct tegra_mipi_device *dev)
 	mutex_unlock(&dev->mipi->lock);
 
 	return err;
-
 }
-EXPORT_SYMBOL(tegra_mipi_disable);
 
-int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
+static int tegra114_mipi_finish_calibration(struct tegra_mipi_device *device)
 {
 	struct tegra_mipi *mipi = device->mipi;
 	void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
@@ -309,9 +289,8 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
 
 	return err;
 }
-EXPORT_SYMBOL(tegra_mipi_finish_calibration);
 
-int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
+static int tegra114_mipi_start_calibration(struct tegra_mipi_device *device)
 {
 	const struct tegra_mipi_soc *soc = device->mipi->soc;
 	unsigned int i;
@@ -384,7 +363,13 @@ int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
 
 	return 0;
 }
-EXPORT_SYMBOL(tegra_mipi_start_calibration);
+
+static const struct tegra_mipi_ops tegra114_mipi_ops = {
+	.tegra_mipi_enable = tegra114_mipi_enable,
+	.tegra_mipi_disable = tegra114_mipi_disable,
+	.tegra_mipi_start_calibration = tegra114_mipi_start_calibration,
+	.tegra_mipi_finish_calibration = tegra114_mipi_finish_calibration,
+};
 
 static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
 	{ .data = MIPI_CAL_CONFIG_CSIA },
@@ -512,6 +497,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
 
 	mipi->soc = match->data;
 	mipi->dev = &pdev->dev;
+	mipi->ops = &tegra114_mipi_ops;
 
 	mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
 	if (IS_ERR(mipi->regs))
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 74c92db1032f..9e3bd6109781 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -12,6 +12,7 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/tegra-mipi-cal.h>
 
 #include <media/v4l2-fwnode.h>
 
diff --git a/include/linux/host1x.h b/include/linux/host1x.h
index 9fa9c30a34e6..b1c6514859d3 100644
--- a/include/linux/host1x.h
+++ b/include/linux/host1x.h
@@ -453,16 +453,6 @@ void host1x_client_unregister(struct host1x_client *client);
 int host1x_client_suspend(struct host1x_client *client);
 int host1x_client_resume(struct host1x_client *client);
 
-struct tegra_mipi_device;
-
-struct tegra_mipi_device *tegra_mipi_request(struct device *device,
-					     struct device_node *np);
-void tegra_mipi_free(struct tegra_mipi_device *device);
-int tegra_mipi_enable(struct tegra_mipi_device *device);
-int tegra_mipi_disable(struct tegra_mipi_device *device);
-int tegra_mipi_start_calibration(struct tegra_mipi_device *device);
-int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
-
 /* host1x memory contexts */
 
 struct host1x_memory_context {
diff --git a/include/linux/tegra-mipi-cal.h b/include/linux/tegra-mipi-cal.h
new file mode 100644
index 000000000000..2bfdbfd3cb77
--- /dev/null
+++ b/include/linux/tegra-mipi-cal.h
@@ -0,0 +1,111 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef __TEGRA_MIPI_CAL_H_
+#define __TEGRA_MIPI_CAL_H_
+
+struct tegra_mipi {
+	const struct tegra_mipi_soc *soc;
+	const struct tegra_mipi_ops *ops;
+	struct device *dev;
+	void __iomem *regs;
+	struct mutex lock;
+	struct clk *clk;
+
+	unsigned long usage_count;
+};
+
+struct tegra_mipi_device {
+	struct platform_device *pdev;
+	struct tegra_mipi *mipi;
+	struct device *device;
+	unsigned long pads;
+};
+
+/**
+ * Operations for Tegra MIPI calibration device
+ */
+struct tegra_mipi_ops {
+	/**
+	 * @tegra_mipi_enable:
+	 *
+	 * Enable MIPI calibration device
+	 */
+	int (*tegra_mipi_enable)(struct tegra_mipi_device *device);
+
+	/**
+	 * @tegra_mipi_disable:
+	 *
+	 * Disable MIPI calibration device
+	 */
+	int (*tegra_mipi_disable)(struct tegra_mipi_device *device);
+
+	/**
+	 * @tegra_mipi_start_calibration:
+	 *
+	 * Start MIPI calibration
+	 */
+	int (*tegra_mipi_start_calibration)(struct tegra_mipi_device *device);
+
+	/**
+	 * @tegra_mipi_finish_calibration:
+	 *
+	 * Finish MIPI calibration
+	 */
+	int (*tegra_mipi_finish_calibration)(struct tegra_mipi_device *device);
+};
+
+struct tegra_mipi_device *tegra_mipi_request(struct device *device,
+					     struct device_node *np);
+
+void tegra_mipi_free(struct tegra_mipi_device *device);
+
+static inline int tegra_mipi_enable(struct tegra_mipi_device *device)
+{
+	/* Tegra114+ has a dedicated MIPI calibration block */
+	if (device->mipi) {
+		if (!device->mipi->ops->tegra_mipi_enable)
+			return 0;
+
+		return device->mipi->ops->tegra_mipi_enable(device);
+	}
+
+	return -ENOSYS;
+}
+
+static inline int tegra_mipi_disable(struct tegra_mipi_device *device)
+{
+	if (device->mipi) {
+		if (!device->mipi->ops->tegra_mipi_disable)
+			return 0;
+
+		return device->mipi->ops->tegra_mipi_disable(device);
+	}
+
+	return -ENOSYS;
+}
+
+static inline int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
+{
+	if (device->mipi) {
+		if (!device->mipi->ops->tegra_mipi_start_calibration)
+			return 0;
+
+		return device->mipi->ops->tegra_mipi_start_calibration(device);
+	}
+
+	return -ENOSYS;
+}
+
+static inline int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
+{
+	if (device->mipi) {
+		if (!device->mipi->ops->tegra_mipi_finish_calibration)
+			return 0;
+
+		return device->mipi->ops->tegra_mipi_finish_calibration(device);
+	}
+
+	return -ENOSYS;
+}
+
+#endif /* __TEGRA_MIPI_CAL_H_ */
-- 
2.48.1


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

* [PATCH v2 10/23] staging: media: tegra-video: csi: add support for SoCs with integrated MIPI calibration
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (8 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev Svyatoslav Ryhel
                   ` (13 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Tegra20/Tegra30 SoC have MIPI calibration logic integrated into CSI block.
This commit adds support for using the entire CSI block for MIPI
calibration not only for CSI itself but for DSI too.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/gpu/host1x/mipi.c                     | 18 ++++++++---
 drivers/staging/media/tegra-video/csi.c       |  7 +++-
 drivers/staging/media/tegra-video/tegra20.c   |  1 +
 drivers/staging/media/tegra-video/tegra210.c  |  2 +-
 drivers/staging/media/tegra-video/vi.h        |  3 +-
 .../csi.h => include/linux/tegra-csi.h        |  6 ++++
 include/linux/tegra-mipi-cal.h                | 32 +++++++++++++++++++
 7 files changed, 61 insertions(+), 8 deletions(-)
 rename drivers/staging/media/tegra-video/csi.h => include/linux/tegra-csi.h (95%)

diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
index 2fa339a428f3..262f71296b75 100644
--- a/drivers/gpu/host1x/mipi.c
+++ b/drivers/gpu/host1x/mipi.c
@@ -215,10 +215,20 @@ struct tegra_mipi_device *tegra_mipi_request(struct device *device,
 		goto free;
 	}
 
-	dev->mipi = platform_get_drvdata(dev->pdev);
-	if (!dev->mipi) {
-		err = -EPROBE_DEFER;
-		goto put;
+	/* Tegra20/Tegra30 add CSI structure to MIPI device */
+	if (of_machine_is_compatible("nvidia,tegra20") ||
+	    of_machine_is_compatible("nvidia,tegra30")) {
+		dev->csi = platform_get_drvdata(dev->pdev);
+		if (!dev->csi) {
+			err = -EPROBE_DEFER;
+			goto put;
+		}
+	} else {
+		dev->mipi = platform_get_drvdata(dev->pdev);
+		if (!dev->mipi) {
+			err = -EPROBE_DEFER;
+			goto put;
+		}
 	}
 
 	of_node_put(args.np);
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 9e3bd6109781..3d1d5e1615c2 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -12,11 +12,11 @@
 #include <linux/of_graph.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
+#include <linux/tegra-csi.h>
 #include <linux/tegra-mipi-cal.h>
 
 #include <media/v4l2-fwnode.h>
 
-#include "csi.h"
 #include "video.h"
 
 #define MHZ			1000000
@@ -794,6 +794,11 @@ static int tegra_csi_probe(struct platform_device *pdev)
 
 	csi->dev = &pdev->dev;
 	csi->ops = csi->soc->ops;
+	if (csi->soc->mipi_ops)
+		csi->mipi_ops = csi->soc->mipi_ops;
+
+	mutex_init(&csi->mipi_lock);
+
 	platform_set_drvdata(pdev, csi);
 	pm_runtime_enable(&pdev->dev);
 
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 7b8f8f810b35..461593c49594 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -16,6 +16,7 @@
 #include <linux/host1x.h>
 #include <linux/kernel.h>
 #include <linux/kthread.h>
+#include <linux/tegra-csi.h>
 #include <linux/v4l2-mediabus.h>
 
 #include "vip.h"
diff --git a/drivers/staging/media/tegra-video/tegra210.c b/drivers/staging/media/tegra-video/tegra210.c
index da99f19a39e7..59224c2f9948 100644
--- a/drivers/staging/media/tegra-video/tegra210.c
+++ b/drivers/staging/media/tegra-video/tegra210.c
@@ -13,8 +13,8 @@
 #include <linux/delay.h>
 #include <linux/host1x.h>
 #include <linux/kthread.h>
+#include <linux/tegra-csi.h>
 
-#include "csi.h"
 #include "vi.h"
 
 #define TEGRA210_MIN_WIDTH	32U
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index cac0c0d0e225..64655ac1b41f 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -12,6 +12,7 @@
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/wait.h>
+#include <linux/tegra-csi.h>
 
 #include <media/media-entity.h>
 #include <media/v4l2-async.h>
@@ -21,8 +22,6 @@
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-v4l2.h>
 
-#include "csi.h"
-
 #define V4L2_CID_TEGRA_SYNCPT_TIMEOUT_RETRY	(V4L2_CTRL_CLASS_CAMERA | 0x1001)
 
 #define TEGRA_DEF_WIDTH		1920
diff --git a/drivers/staging/media/tegra-video/csi.h b/include/linux/tegra-csi.h
similarity index 95%
rename from drivers/staging/media/tegra-video/csi.h
rename to include/linux/tegra-csi.h
index 3ed2dbc73ce9..b47f48ef7115 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/include/linux/tegra-csi.h
@@ -115,6 +115,7 @@ struct tegra_csi_ops {
  * struct tegra_csi_soc - NVIDIA Tegra CSI SoC structure
  *
  * @ops: csi hardware operations
+ * @mipi_ops: MIPI calibration operations
  * @csi_max_channels: supported max streaming channels
  * @clk_names: csi and cil clock names
  * @num_clks: total clocks count
@@ -123,6 +124,7 @@ struct tegra_csi_ops {
  */
 struct tegra_csi_soc {
 	const struct tegra_csi_ops *ops;
+	const struct tegra_mipi_ops *mipi_ops;
 	unsigned int csi_max_channels;
 	const char * const *clk_names;
 	unsigned int num_clks;
@@ -139,6 +141,8 @@ struct tegra_csi_soc {
  * @clks: clock for CSI and CIL
  * @soc: pointer to SoC data structure
  * @ops: csi operations
+ * @mipi_ops: MIPI calibration operations
+ * @mipi_lock: for MIPI calibration operations
  * @csi_chans: list head for CSI channels
  */
 struct tegra_csi {
@@ -148,6 +152,8 @@ struct tegra_csi {
 	struct clk_bulk_data *clks;
 	const struct tegra_csi_soc *soc;
 	const struct tegra_csi_ops *ops;
+	const struct tegra_mipi_ops *mipi_ops;
+	struct mutex mipi_lock;
 	struct list_head csi_chans;
 };
 
diff --git a/include/linux/tegra-mipi-cal.h b/include/linux/tegra-mipi-cal.h
index 2bfdbfd3cb77..81784b1f2135 100644
--- a/include/linux/tegra-mipi-cal.h
+++ b/include/linux/tegra-mipi-cal.h
@@ -3,6 +3,8 @@
 #ifndef __TEGRA_MIPI_CAL_H_
 #define __TEGRA_MIPI_CAL_H_
 
+#include <linux/tegra-csi.h>
+
 struct tegra_mipi {
 	const struct tegra_mipi_soc *soc;
 	const struct tegra_mipi_ops *ops;
@@ -17,6 +19,7 @@ struct tegra_mipi {
 struct tegra_mipi_device {
 	struct platform_device *pdev;
 	struct tegra_mipi *mipi;
+	struct tegra_csi *csi;
 	struct device *device;
 	unsigned long pads;
 };
@@ -69,6 +72,14 @@ static inline int tegra_mipi_enable(struct tegra_mipi_device *device)
 		return device->mipi->ops->tegra_mipi_enable(device);
 	}
 
+	/* Tegra20/Tegra30 have MIPI calibration logic inside CSI block */
+	if (device->csi) {
+		if (!device->csi->mipi_ops->tegra_mipi_enable)
+			return 0;
+
+		return device->csi->mipi_ops->tegra_mipi_enable(device);
+	}
+
 	return -ENOSYS;
 }
 
@@ -81,6 +92,13 @@ static inline int tegra_mipi_disable(struct tegra_mipi_device *device)
 		return device->mipi->ops->tegra_mipi_disable(device);
 	}
 
+	if (device->csi) {
+		if (!device->csi->mipi_ops->tegra_mipi_disable)
+			return 0;
+
+		return device->csi->mipi_ops->tegra_mipi_disable(device);
+	}
+
 	return -ENOSYS;
 }
 
@@ -93,6 +111,13 @@ static inline int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
 		return device->mipi->ops->tegra_mipi_start_calibration(device);
 	}
 
+	if (device->csi) {
+		if (!device->csi->mipi_ops->tegra_mipi_start_calibration)
+			return 0;
+
+		return device->csi->mipi_ops->tegra_mipi_start_calibration(device);
+	}
+
 	return -ENOSYS;
 }
 
@@ -105,6 +130,13 @@ static inline int tegra_mipi_finish_calibration(struct tegra_mipi_device *device
 		return device->mipi->ops->tegra_mipi_finish_calibration(device);
 	}
 
+	if (device->csi) {
+		if (!device->csi->mipi_ops->tegra_mipi_finish_calibration)
+			return 0;
+
+		return device->csi->mipi_ops->tegra_mipi_finish_calibration(device);
+	}
+
 	return -ENOSYS;
 }
 
-- 
2.48.1


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

* [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (9 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 10/23] staging: media: tegra-video: csi: add support for SoCs with integrated MIPI calibration Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-16 16:04   ` Luca Ceresoli
  2025-09-06 13:53 ` [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI Svyatoslav Ryhel
                   ` (12 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

By default tegra_channel_get_remote_csi_subdev returns next device in pipe
assuming it is CSI but in case of Tegra20 and Tegra30 it can also be VIP
or even HOST. Lets check if returned device is actually CSI by comparing
subdevice operations.

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

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 3d1d5e1615c2..c848e4ab51ac 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -445,6 +445,22 @@ static const struct v4l2_subdev_ops tegra_csi_ops = {
 	.pad    = &tegra_csi_pad_ops,
 };
 
+struct v4l2_subdev *tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
+{
+	struct media_pad *pad;
+	struct v4l2_subdev *subdev;
+
+	pad = media_pad_remote_pad_first(&chan->pad);
+	if (!pad)
+		return NULL;
+
+	subdev = media_entity_to_v4l2_subdev(pad->entity);
+	if (!subdev)
+		return NULL;
+
+	return subdev->ops == &tegra_csi_ops ? subdev : NULL;
+}
+
 static int tegra_csi_channel_alloc(struct tegra_csi *csi,
 				   struct device_node *node,
 				   unsigned int port_num, unsigned int lanes,
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 90473729b546..2deb615547be 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -160,18 +160,6 @@ static void tegra_channel_buffer_queue(struct vb2_buffer *vb)
 	wake_up_interruptible(&chan->start_wait);
 }
 
-struct v4l2_subdev *
-tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
-{
-	struct media_pad *pad;
-
-	pad = media_pad_remote_pad_first(&chan->pad);
-	if (!pad)
-		return NULL;
-
-	return media_entity_to_v4l2_subdev(pad->entity);
-}
-
 /*
  * Walk up the chain until the initial source (e.g. image sensor)
  */
-- 
2.48.1


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

* [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (10 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-09  0:49   ` Rob Herring (Arm)
  2025-09-09  0:57   ` Rob Herring
  2025-09-06 13:53 ` [PATCH v2 13/23] staging: media: tegra-video: csi: " Svyatoslav Ryhel
                   ` (11 subsequent siblings)
  23 siblings, 2 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

The avdd-dsi-csi-supply is CSI power supply, it has nothing to do with VI,
like same supply is used with DSI and has nothing to do with DC. Move it
to correct place.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 .../devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml   | 3 ---
 .../devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml | 3 +++
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
index dd67d4162884..bb138277d5e8 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
@@ -75,9 +75,6 @@ properties:
   ranges:
     maxItems: 1
 
-  avdd-dsi-csi-supply:
-    description: DSI/CSI power supply. Must supply 1.2 V.
-
   vip:
     $ref: /schemas/display/tegra/nvidia,tegra20-vip.yaml
 
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
index fa07a40d1004..37f6129c9c92 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
@@ -37,6 +37,9 @@ properties:
       - const: cile
       - const: csi_tpg
 
+  avdd-dsi-csi-supply:
+    description: DSI/CSI power supply. Must supply 1.2 V.
+
   power-domains:
     maxItems: 1
 
-- 
2.48.1


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

* [PATCH v2 13/23] staging: media: tegra-video: csi: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (11 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-17  7:52   ` Luca Ceresoli
  2025-09-22  4:11   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 14/23] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
                   ` (10 subsequent siblings)
  23 siblings, 2 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

The avdd-dsi-csi-supply is CSI power supply not VI, hence move it to
proper place.

Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
 drivers/staging/media/tegra-video/csi.c | 19 ++++++++++++++++++-
 drivers/staging/media/tegra-video/vi.c  | 23 ++---------------------
 drivers/staging/media/tegra-video/vi.h  |  2 --
 include/linux/tegra-csi.h               |  2 ++
 4 files changed, 22 insertions(+), 24 deletions(-)

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index c848e4ab51ac..1677eb51ec21 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -710,6 +710,8 @@ static int __maybe_unused csi_runtime_suspend(struct device *dev)
 
 	clk_bulk_disable_unprepare(csi->soc->num_clks, csi->clks);
 
+	regulator_disable(csi->vdd);
+
 	return 0;
 }
 
@@ -718,13 +720,23 @@ static int __maybe_unused csi_runtime_resume(struct device *dev)
 	struct tegra_csi *csi = dev_get_drvdata(dev);
 	int ret;
 
+	ret = regulator_enable(csi->vdd);
+	if (ret) {
+		dev_err(dev, "failed to enable VDD supply: %d\n", ret);
+		return ret;
+	}
+
 	ret = clk_bulk_prepare_enable(csi->soc->num_clks, csi->clks);
 	if (ret < 0) {
 		dev_err(csi->dev, "failed to enable clocks: %d\n", ret);
-		return ret;
+		goto disable_vdd;
 	}
 
 	return 0;
+
+disable_vdd:
+	regulator_disable(csi->vdd);
+	return ret;
 }
 
 static int tegra_csi_init(struct host1x_client *client)
@@ -802,6 +814,11 @@ static int tegra_csi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
+	csi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
+	if (IS_ERR(csi->vdd))
+		return dev_err_probe(&pdev->dev, PTR_ERR(csi->vdd),
+				     "failed to get VDD supply");
+
 	if (!pdev->dev.pm_domain) {
 		ret = -ENOENT;
 		dev_warn(&pdev->dev, "PM domain is not attached: %d\n", ret);
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 2deb615547be..05af718b3cdf 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1405,29 +1405,19 @@ static int __maybe_unused vi_runtime_resume(struct device *dev)
 	struct tegra_vi *vi = dev_get_drvdata(dev);
 	int ret;
 
-	ret = regulator_enable(vi->vdd);
-	if (ret) {
-		dev_err(dev, "failed to enable VDD supply: %d\n", ret);
-		return ret;
-	}
-
 	ret = clk_set_rate(vi->clk, vi->soc->vi_max_clk_hz);
 	if (ret) {
 		dev_err(dev, "failed to set vi clock rate: %d\n", ret);
-		goto disable_vdd;
+		return ret;
 	}
 
 	ret = clk_prepare_enable(vi->clk);
 	if (ret) {
 		dev_err(dev, "failed to enable vi clock: %d\n", ret);
-		goto disable_vdd;
+		return ret;
 	}
 
 	return 0;
-
-disable_vdd:
-	regulator_disable(vi->vdd);
-	return ret;
 }
 
 static int __maybe_unused vi_runtime_suspend(struct device *dev)
@@ -1436,8 +1426,6 @@ static int __maybe_unused vi_runtime_suspend(struct device *dev)
 
 	clk_disable_unprepare(vi->clk);
 
-	regulator_disable(vi->vdd);
-
 	return 0;
 }
 
@@ -1882,13 +1870,6 @@ static int tegra_vi_probe(struct platform_device *pdev)
 		return ret;
 	}
 
-	vi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
-	if (IS_ERR(vi->vdd)) {
-		ret = PTR_ERR(vi->vdd);
-		dev_err(&pdev->dev, "failed to get VDD supply: %d\n", ret);
-		return ret;
-	}
-
 	if (!pdev->dev.pm_domain) {
 		ret = -ENOENT;
 		dev_warn(&pdev->dev, "PM domain is not attached: %d\n", ret);
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index 64655ac1b41f..367667adf745 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -93,7 +93,6 @@ struct tegra_vi_soc {
  * @client: host1x_client struct
  * @iomem: register base
  * @clk: main clock for VI block
- * @vdd: vdd regulator for VI hardware, normally it is avdd_dsi_csi
  * @soc: pointer to SoC data structure
  * @ops: vi operations
  * @vi_chans: list head for VI channels
@@ -103,7 +102,6 @@ struct tegra_vi {
 	struct host1x_client client;
 	void __iomem *iomem;
 	struct clk *clk;
-	struct regulator *vdd;
 	const struct tegra_vi_soc *soc;
 	const struct tegra_vi_ops *ops;
 	struct list_head vi_chans;
diff --git a/include/linux/tegra-csi.h b/include/linux/tegra-csi.h
index b47f48ef7115..85c74e22a0cb 100644
--- a/include/linux/tegra-csi.h
+++ b/include/linux/tegra-csi.h
@@ -139,6 +139,7 @@ struct tegra_csi_soc {
  * @client: host1x_client struct
  * @iomem: register base
  * @clks: clock for CSI and CIL
+ * @vdd: vdd regulator for CSI hardware, usually avdd_dsi_csi
  * @soc: pointer to SoC data structure
  * @ops: csi operations
  * @mipi_ops: MIPI calibration operations
@@ -150,6 +151,7 @@ struct tegra_csi {
 	struct host1x_client client;
 	void __iomem *iomem;
 	struct clk_bulk_data *clks;
+	struct regulator *vdd;
 	const struct tegra_csi_soc *soc;
 	const struct tegra_csi_ops *ops;
 	const struct tegra_mipi_ops *mipi_ops;
-- 
2.48.1


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

* [PATCH v2 14/23] staging: media: tegra-video: tegra20: set correct maximum width and height
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (12 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 13/23] staging: media: tegra-video: csi: " Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
                   ` (9 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.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 461593c49594..3dc26f5552eb 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -24,11 +24,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] 71+ messages in thread

* [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (13 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 14/23] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-22  4:29   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
                   ` (8 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 | 82 ++++++++++++---------
 1 file changed, 46 insertions(+), 36 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 3dc26f5552eb..6e0b3b728623 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -29,13 +29,19 @@
 #define TEGRA20_MIN_HEIGHT	32U
 #define TEGRA20_MAX_HEIGHT	8190U
 
+/* Tegra20/Tegra30 has 2 outputs in VI */
+enum tegra_vi_out {
+	TEGRA_VI_OUT_1 = 0,
+	TEGRA_VI_OUT_2 = 1,
+};
+
 /* --------------------------------------------------------------------------
  * 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)
@@ -47,6 +53,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
@@ -67,7 +74,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)
@@ -81,6 +88,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 */
@@ -90,26 +98,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
@@ -137,7 +145,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)
 
@@ -367,8 +375,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(TEGRA_VI_OUT_1),  base);
+		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), base + chan->start_offset);
 		break;
 	}
 }
@@ -456,6 +464,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;
+	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
 	int main_output_format;
 	int yuv_output_format;
 
@@ -473,33 +482,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)
@@ -588,7 +597,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,
-	.vi_max_channels = 1, /* parallel input (VIP) */
+	.vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
 	.vi_max_clk_hz = 150000000,
 	.has_h_v_flip = true,
 };
@@ -608,6 +617,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;
+	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
 
 	unsigned int main_input_format;
 	unsigned int yuv_input_format;
@@ -638,10 +648,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] 71+ messages in thread

* [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (14 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-22  4:44   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 17/23] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
                   ` (7 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 6e0b3b728623..781c4e8ec856 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -280,20 +280,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;
 }
 
 /*
@@ -576,20 +564,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] 71+ messages in thread

* [PATCH v2 17/23] staging: media: tegra-video: tegra20: set VI HW revision
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (15 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
                   ` (6 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 781c4e8ec856..e0da496bb50f 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -588,6 +588,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 = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
 	.vi_max_clk_hz = 150000000,
 	.has_h_v_flip = true,
-- 
2.48.1


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

* [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (16 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 17/23] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-22  4:54   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
                   ` (5 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 e0da496bb50f..3c5bafebfcd8 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -590,7 +590,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 	.ops = &tegra20_vi_ops,
 	.hw_revision = 1,
 	.vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
-	.vi_max_clk_hz = 150000000,
+	.vi_max_clk_hz = 450000000,
 	.has_h_v_flip = true,
 };
 
-- 
2.48.1


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

* [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (17 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-22  5:00   ` Mikko Perttunen
  2025-09-06 13:53 ` [PATCH v2 20/23] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
                   ` (4 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 | 72 ++++++++++++++++++++-
 1 file changed, 69 insertions(+), 3 deletions(-)

diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 3c5bafebfcd8..f9adb0611638 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -187,6 +187,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:
+		(*main_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
+		break;
 	}
 }
 
@@ -221,6 +233,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;
 	}
 }
 
@@ -301,6 +325,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)
@@ -366,6 +400,19 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
 		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_1),  base);
 		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_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(TEGRA_VI_OUT_2),  base);
+		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), base + chan->start_offset);
+		break;
 	}
 }
 
@@ -447,12 +494,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;
-	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
+	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+					    data_type == TEGRA_IMAGE_DT_RAW10) ?
+					    TEGRA_VI_OUT_2 : TEGRA_VI_OUT_1;
 	int main_output_format;
 	int yuv_output_format;
 
@@ -581,6 +631,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 = {
@@ -607,10 +671,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;
-	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
-
+	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+					    data_type == TEGRA_IMAGE_DT_RAW10) ?
+					    TEGRA_VI_OUT_2 : TEGRA_VI_OUT_1;
 	unsigned int main_input_format;
 	unsigned int yuv_input_format;
 
-- 
2.48.1


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

* [PATCH v2 20/23] staging: media: tegra-video: tegra20: adjust luma buffer stride
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (18 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
                   ` (3 subsequent siblings)
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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>
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.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 f9adb0611638..20cdcc4e01aa 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -497,7 +497,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;
 	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
-- 
2.48.1


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

* [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (19 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 20/23] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-09 16:26   ` Rob Herring
  2025-09-06 13:53 ` [PATCH v2 22/23] ARM: tegra: add CSI nodes for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (2 subsequent siblings)
  23 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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,tegra20-csi.yaml     | 104 ++++++++++++++++
 .../display/tegra/nvidia,tegra30-csi.yaml     | 115 ++++++++++++++++++
 2 files changed, 219 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
 create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml

diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
new file mode 100644
index 000000000000..1a2858a5893c
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
@@ -0,0 +1,104 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra20-csi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra20 CSI controller
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - nvidia,tegra20-csi
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  avdd-dsi-csi-supply:
+    description: DSI/CSI power supply. Must supply 1.2 V.
+
+  power-domains:
+    maxItems: 1
+
+  "#nvidia,mipi-calibrate-cells":
+    description: The number of cells in a MIPI calibration specifier.
+      Should be 1. The single cell specifies an id of the pads that
+      need to be calibrated for a given device.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    const: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^channel@[0-1]$":
+    type: object
+    description: channel 0 represents CSI-A and 1 represents CSI-B
+    additionalProperties: false
+
+    properties:
+      reg:
+        maxItems: 1
+
+      nvidia,mipi-calibrate:
+        description: Should contain a phandle and a specifier specifying
+          which pads are used by this DSI output and need to be
+          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI.
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: port receiving the video stream from the sensor
+
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes: true
+
+            required:
+              - data-lanes
+
+        required:
+          - endpoint
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: port sending the video stream to the VI
+
+    required:
+      - reg
+      - "#address-cells"
+      - "#size-cells"
+      - port@0
+      - port@1
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - power-domains
+  - "#address-cells"
+  - "#size-cells"
+
+# see nvidia,tegra20-vi.yaml for an example
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
new file mode 100644
index 000000000000..ea5ebd2f3c65
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
@@ -0,0 +1,115 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra30-csi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: NVIDIA Tegra30 CSI controller
+
+maintainers:
+  - Svyatoslav Ryhel <clamor95@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - nvidia,tegra30-csi
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: module clock
+      - description: PAD A clock
+      - description: PAD B clock
+
+  clock-names:
+    items:
+      - const: csi
+      - const: csia-pad
+      - const: csib-pad
+
+  avdd-dsi-csi-supply:
+    description: DSI/CSI power supply. Must supply 1.2 V.
+
+  power-domains:
+    maxItems: 1
+
+  "#nvidia,mipi-calibrate-cells":
+    description: The number of cells in a MIPI calibration specifier.
+      Should be 1. The single cell specifies an id of the pads that
+      need to be calibrated for a given device.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    const: 1
+
+  "#address-cells":
+    const: 1
+
+  "#size-cells":
+    const: 0
+
+patternProperties:
+  "^channel@[0-1]$":
+    type: object
+    description: channel 0 represents CSI-A and 1 represents CSI-B
+    additionalProperties: false
+
+    properties:
+      reg:
+        maxItems: 1
+
+      nvidia,mipi-calibrate:
+        description: Should contain a phandle and a specifier specifying
+          which pads are used by this DSI output and need to be
+          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI-A and
+          3 is for DSI-B
+        $ref: /schemas/types.yaml#/definitions/phandle-array
+
+      "#address-cells":
+        const: 1
+
+      "#size-cells":
+        const: 0
+
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: port receiving the video stream from the sensor
+
+        properties:
+          endpoint:
+            $ref: /schemas/media/video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes: true
+
+            required:
+              - data-lanes
+
+        required:
+          - endpoint
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: port sending the video stream to the VI
+
+    required:
+      - reg
+      - "#address-cells"
+      - "#size-cells"
+      - port@0
+      - port@1
+
+additionalProperties: false
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - power-domains
+  - "#address-cells"
+  - "#size-cells"
+
+# see nvidia,tegra20-vi.yaml for an example
-- 
2.48.1


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

* [PATCH v2 22/23] ARM: tegra: add CSI nodes for Tegra20 and Tegra30
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (20 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-06 13:53 ` [PATCH v2 23/23] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
  2025-09-11 16:03 ` (subset) [PATCH v2 00/23] " Thierry Reding
  23 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	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 | 19 ++++++++++++++++++-
 arch/arm/boot/dts/nvidia/tegra30.dtsi | 24 ++++++++++++++++++++++--
 2 files changed, 40 insertions(+), 3 deletions(-)

diff --git a/arch/arm/boot/dts/nvidia/tegra20.dtsi b/arch/arm/boot/dts/nvidia/tegra20.dtsi
index 6ae07b316c8a..5cdbf1246cf8 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,23 @@ 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: csi@800 {
+				compatible = "nvidia,tegra20-csi";
+				reg = <0x800 0x200>;
+				clocks = <&tegra_car TEGRA20_CLK_CSI>;
+				power-domains = <&pd_venc>;
+				#nvidia,mipi-calibrate-cells = <1>;
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
 		};
 
 		epp@540c0000 {
diff --git a/arch/arm/boot/dts/nvidia/tegra30.dtsi b/arch/arm/boot/dts/nvidia/tegra30.dtsi
index 20b3248d4d2f..be752a245a55 100644
--- a/arch/arm/boot/dts/nvidia/tegra30.dtsi
+++ b/arch/arm/boot/dts/nvidia/tegra30.dtsi
@@ -150,8 +150,8 @@ mpe@54040000 {
 		};
 
 		vi@54080000 {
-			compatible = "nvidia,tegra30-vi";
-			reg = <0x54080000 0x00040000>;
+			compatible = "nvidia,tegra30-vi", "nvidia,tegra20-vi";
+			reg = <0x54080000 0x00000800>;
 			interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
 			clocks = <&tegra_car TEGRA30_CLK_VI>;
 			resets = <&tegra_car 20>;
@@ -162,6 +162,26 @@ vi@54080000 {
 			iommus = <&mc TEGRA_SWGROUP_VI>;
 
 			status = "disabled";
+
+			#address-cells = <1>;
+			#size-cells = <1>;
+
+			ranges = <0x0 0x54080000 0x4000>;
+
+			csi: 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>;
+				#nvidia,mipi-calibrate-cells = <1>;
+				status = "disabled";
+
+				#address-cells = <1>;
+				#size-cells = <0>;
+			};
 		};
 
 		epp@540c0000 {
-- 
2.48.1


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

* [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (21 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 22/23] ARM: tegra: add CSI nodes for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-09-06 13:53 ` Svyatoslav Ryhel
  2025-09-15  5:46   ` kernel test robot
  2025-09-22  5:15   ` Mikko Perttunen
  2025-09-11 16:03 ` (subset) [PATCH v2 00/23] " Thierry Reding
  23 siblings, 2 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-06 13:53 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

Add support for MIPI CSI device and calibration logic 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 | 593 ++++++++++++++++++--
 drivers/staging/media/tegra-video/vi.h      |   2 +
 drivers/staging/media/tegra-video/video.c   |   6 +
 4 files changed, 573 insertions(+), 40 deletions(-)

diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 1677eb51ec21..d3f85f964ada 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
 #include <linux/tegra-csi.h>
+#include <linux/tegra-mipi-cal.h>
 #include <linux/v4l2-mediabus.h>
 
 #include "vip.h"
@@ -43,6 +51,9 @@ enum tegra_vi_out {
 #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)
@@ -88,6 +99,8 @@ enum tegra_vi_out {
 #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
@@ -152,8 +165,106 @@ enum tegra_vi_out {
 #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_CONFIG			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)
@@ -161,6 +272,35 @@ 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);
+}
+
+static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
+{
+	writel(val, mipi->csi->iomem + addr);
+}
+
+static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
+{
+	return readl(mipi->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.
@@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
@@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
+					 struct tegra_csi_channel *csi_chan)
 {
 	int err;
 
-	chan->next_out_sp_idx++;
-
 	tegra20_channel_vi_buffer_setup(chan, buf);
 
-	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
+	if (csi_chan) {
+		u32 port = csi_chan->csi_port_nums[0] & 1;
+
+		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);
+
+		err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
+					 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
+		if (err) {
+			if (err != -ERESTARTSYS)
+				dev_err_ratelimited(&chan->video.dev,
+						    "frame start syncpt timeout: %d\n", err);
+		} else {
+			chan->next_fs_sp_value++;
+		}
+
+		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)
 {
 	struct tegra_vi_channel *chan = data;
 	struct tegra_channel_buffer *buf;
+	struct v4l2_subdev *csi_subdev = NULL;
+	struct tegra_csi_channel *csi_chan = NULL;
 	unsigned int retries = 0;
 	int err = 0;
 
+	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
+	if (csi_subdev)
+		csi_chan = to_csi_chan(csi_subdev);
+
 	while (1) {
 		/*
 		 * Source is not streaming if error is non-zero.
@@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
 		list_del_init(&buf->queue);
 		spin_unlock(&chan->start_lock);
 
-		err = tegra20_channel_capture_frame(chan, buf);
+		err = tegra20_channel_capture_frame(chan, buf, csi_chan);
 		if (!err) {
 			retries = 0;
 			continue;
@@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
 	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
 					    data_type == TEGRA_IMAGE_DT_RAW10) ?
 					    TEGRA_VI_OUT_2 : TEGRA_VI_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),
@@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
 	struct media_pipeline *pipe = &chan->video.pipe;
 	int err;
 
+	chan->next_fs_sp_value = 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);
+
 	chan->sequence = 0;
 
 	chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
@@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
 	.has_h_v_flip = true,
 };
 
+/* --------------------------------------------------------------------------
+ * MIPI Calibration
+ */
+static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
+{
+	struct tegra_csi *csi = mipi->csi;
+	unsigned int port = mipi->pads;
+	u32 value;
+	int ret;
+
+	guard(mutex)(&csi->mipi_lock);
+
+	ret = pm_runtime_resume_and_get(csi->dev);
+	if (ret < 0) {
+		dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
+		return ret;
+	}
+
+	tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
+			   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)
+		value |= CSI_CIL_MIPI_CAL_SEL_B;
+
+	tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
+
+	tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
+
+	return 0;
+}
+
+static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
+{
+	struct tegra_csi *csi = mipi->csi;
+	void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
+	unsigned int port = mipi->pads;
+	u32 value, pp, cil;
+	int ret;
+
+	/* This part is only for CSI */
+	if (port > PORT_B) {
+		pm_runtime_put(csi->dev);
+
+		return 0;
+	}
+
+	guard(mutex)(&csi->mipi_lock);
+
+	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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+	cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
+	if (pp | cil) {
+		dev_warn(csi->dev, "Calibration status not been cleared!\n");
+		ret = -EINVAL;
+		goto exit;
+	}
+
+exit:
+	tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
+
+	/* un-select to avoid interference with DSI */
+	tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
+
+	pm_runtime_put(csi->dev);
+
+	return ret;
+}
+
+static const struct tegra_mipi_ops tegra20_mipi_ops = {
+	.tegra_mipi_start_calibration = tegra20_start_pad_calibration,
+	.tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
+};
+
+/* --------------------------------------------------------------------------
+ * 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;
+	enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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[] = {
+	NULL,
+};
+
+/* Tegra20 CSI SoC data */
+const struct tegra_csi_soc tegra20_csi_soc = {
+	.ops = &tegra20_csi_ops,
+	.mipi_ops = &tegra20_mipi_ops,
+	.csi_max_channels = 2, /* CSI-A and CSI-B */
+	.clk_names = tegra20_csi_clks,
+	.num_clks = ARRAY_SIZE(tegra20_csi_clks),
+};
+
+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,
+	.mipi_ops = &tegra20_mipi_ops,
+	.csi_max_channels = 2, /* CSI-A and CSI-B */
+	.clk_names = tegra30_csi_clks,
+	.num_clks = ARRAY_SIZE(tegra30_csi_clks),
+};
+
 /* --------------------------------------------------------------------------
  * VIP
  */
@@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
 	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
 					    data_type == TEGRA_IMAGE_DT_RAW10) ?
 					    TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -124,6 +124,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
@@ -188,6 +189,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_value;
 
 	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 6fe8d5301b9c..9f2bddc460bf 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
 	{ .compatible = "nvidia,tegra20-vip", },
 	{ .compatible = "nvidia,tegra20-vi", },
 #endif
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+	{ .compatible = "nvidia,tegra20-csi", },
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+	{ .compatible = "nvidia,tegra30-csi", },
+#endif
 #if defined(CONFIG_ARCH_TEGRA_210_SOC)
 	{ .compatible = "nvidia,tegra210-csi", },
 	{ .compatible = "nvidia,tegra210-vi", },
-- 
2.48.1


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

* Re: [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP
  2025-09-06 13:53 ` [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP Svyatoslav Ryhel
@ 2025-09-06 19:17   ` Rob Herring (Arm)
  0 siblings, 0 replies; 71+ messages in thread
From: Rob Herring (Arm) @ 2025-09-06 19:17 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Conor Dooley, Charan Pedumuru, Jonas Schwöbel,
	Thierry Reding, David Airlie, Thierry Reding, linux-clk,
	linux-media, linux-staging, Maxime Ripard, Michael Turquette,
	Dmitry Osipenko, Simona Vetter, Sowjanya Komatineni,
	Krzysztof Kozlowski, Mauro Carvalho Chehab, Prashant Gaikwad,
	linux-tegra, dri-devel, Greg Kroah-Hartman, Luca Ceresoli,
	Mikko Perttunen, Maarten Lankhorst, Thomas Zimmermann,
	Jonathan Hunter, Stephen Boyd, linux-kernel, devicetree


On Sat, 06 Sep 2025 16:53:25 +0300, Svyatoslav Ryhel wrote:
> Existing Parallel VI interface schema for Tegra20 is fully compatible with
> Tegra30; hence, lets reuse it by setting fallback for Tegra30.
> 
> Adjust existing VI schema to reflect that Tegra20 VI is compatible with
> Tegra30 by setting a fallback for Tegra30. Additionally, switch to using
> an enum instead of list of const.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../display/tegra/nvidia,tegra20-vi.yaml      | 19 ++++++++++++-------
>  .../display/tegra/nvidia,tegra20-vip.yaml     |  9 +++++++--
>  2 files changed, 19 insertions(+), 9 deletions(-)
> 

My bot found errors running 'make dt_binding_check' on your patch:

yamllint warnings/errors:

dtschema/dtc warnings/errors:
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml: properties:compatible: 'anyOf' conditional failed, one must be fixed:
	'one0f' is not one of ['$ref', 'additionalItems', 'additionalProperties', 'allOf', 'anyOf', 'const', 'contains', 'default', 'dependencies', 'dependentRequired', 'dependentSchemas', 'deprecated', 'description', 'else', 'enum', 'exclusiveMaximum', 'exclusiveMinimum', 'items', 'if', 'minItems', 'minimum', 'maxItems', 'maximum', 'multipleOf', 'not', 'oneOf', 'pattern', 'patternProperties', 'properties', 'required', 'then', 'typeSize', 'unevaluatedProperties', 'uniqueItems']
	'type' was expected
	from schema $id: http://devicetree.org/meta-schemas/keywords.yaml#
/builds/robherring/dt-review-ci/linux/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml: properties:compatible: Additional properties are not allowed ('one0f' was unexpected)
	from schema $id: http://devicetree.org/meta-schemas/string-array.yaml#

doc reference errors (make refcheckdocs):

See https://patchwork.ozlabs.org/project/devicetree-bindings/patch/20250906135345.241229-5-clamor95@gmail.com

The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.

If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:

pip3 install dtschema --upgrade

Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.


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

* Re: [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks
  2025-09-06 13:53 ` [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks Svyatoslav Ryhel
@ 2025-09-07  9:34   ` Krzysztof Kozlowski
  2025-09-07  9:43     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-07  9:34 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, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Sat, Sep 06, 2025 at 04:53:23PM +0300, Svyatoslav Ryhel wrote:
> Tegra30 has CSI pad clock enable bits embedded into PLLD/PLLD2 registers.
> Add ids for these clocks. Additionally, move TEGRA30_CLK_CLK_MAX into
> clk-tegra30 source.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra30.c         | 1 +
>  include/dt-bindings/clock/tegra30-car.h | 3 ++-
>  2 files changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
> index ca367184e185..ca738bc64615 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -53,6 +53,7 @@
>  #define SYSTEM_CLK_RATE 0x030
>  
>  #define TEGRA30_CLK_PERIPH_BANKS	5
> +#define TEGRA30_CLK_CLK_MAX		311

Unused define drop.

Also, don't mix bindings and drivers. You cannot create such
dependencies.

Best regards,
Krzysztof


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

* Re: [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks
  2025-09-07  9:34   ` Krzysztof Kozlowski
@ 2025-09-07  9:43     ` Svyatoslav Ryhel
  2025-09-07 18:25       ` Krzysztof Kozlowski
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-07  9:43 UTC (permalink / raw)
  To: Krzysztof Kozlowski
  Cc: 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

нд, 7 вер. 2025 р. о 12:34 Krzysztof Kozlowski <krzk@kernel.org> пише:
>
> On Sat, Sep 06, 2025 at 04:53:23PM +0300, Svyatoslav Ryhel wrote:
> > Tegra30 has CSI pad clock enable bits embedded into PLLD/PLLD2 registers.
> > Add ids for these clocks. Additionally, move TEGRA30_CLK_CLK_MAX into
> > clk-tegra30 source.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/clk/tegra/clk-tegra30.c         | 1 +
> >  include/dt-bindings/clock/tegra30-car.h | 3 ++-
> >  2 files changed, 3 insertions(+), 1 deletion(-)
> >
> > diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
> > index ca367184e185..ca738bc64615 100644
> > --- a/drivers/clk/tegra/clk-tegra30.c
> > +++ b/drivers/clk/tegra/clk-tegra30.c
> > @@ -53,6 +53,7 @@
> >  #define SYSTEM_CLK_RATE 0x030
> >
> >  #define TEGRA30_CLK_PERIPH_BANKS     5
> > +#define TEGRA30_CLK_CLK_MAX          311
>
> Unused define drop.
>

Specify, your comment is not clear.

> Also, don't mix bindings and drivers. You cannot create such
> dependencies.

I literally did what you told me to do! TEGRA30_CLK_CLK_MAX was
removed from binding, but it is used by the driver, so how you propose
to handle this without redefining TEGRA30_CLK_CLK_MAX and breaking
build with missing TEGRA30_CLK_CLK_MAX?

>
> Best regards,
> Krzysztof
>

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

* Re: [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks
  2025-09-07  9:43     ` Svyatoslav Ryhel
@ 2025-09-07 18:25       ` Krzysztof Kozlowski
  0 siblings, 0 replies; 71+ messages in thread
From: Krzysztof Kozlowski @ 2025-09-07 18:25 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, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On 07/09/2025 11:43, Svyatoslav Ryhel wrote:
> нд, 7 вер. 2025 р. о 12:34 Krzysztof Kozlowski <krzk@kernel.org> пише:
>>
>> On Sat, Sep 06, 2025 at 04:53:23PM +0300, Svyatoslav Ryhel wrote:
>>> Tegra30 has CSI pad clock enable bits embedded into PLLD/PLLD2 registers.
>>> Add ids for these clocks. Additionally, move TEGRA30_CLK_CLK_MAX into
>>> clk-tegra30 source.
>>>
>>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>>> ---
>>>  drivers/clk/tegra/clk-tegra30.c         | 1 +
>>>  include/dt-bindings/clock/tegra30-car.h | 3 ++-
>>>  2 files changed, 3 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
>>> index ca367184e185..ca738bc64615 100644
>>> --- a/drivers/clk/tegra/clk-tegra30.c
>>> +++ b/drivers/clk/tegra/clk-tegra30.c
>>> @@ -53,6 +53,7 @@
>>>  #define SYSTEM_CLK_RATE 0x030
>>>
>>>  #define TEGRA30_CLK_PERIPH_BANKS     5
>>> +#define TEGRA30_CLK_CLK_MAX          311
>>
>> Unused define drop.
>>
> 
> Specify, your comment is not clear.
> 
>> Also, don't mix bindings and drivers. You cannot create such
>> dependencies.
> 
> I literally did what you told me to do! TEGRA30_CLK_CLK_MAX was
> removed from binding, but it is used by the driver, so how you propose


I missed that you remove here old CLK_MAX... well, you did it quite
different than all other cases leading to driver-binding dependency.
Really, I thought you will just fix it immediately after my feedback and
then new bindings come later, just like we did for every other SoC.

> to handle this without redefining TEGRA30_CLK_CLK_MAX and breaking
> build with missing TEGRA30_CLK_CLK_MAX?
There is really no problem there and if you put here at least some
effort you would see how everyone else did it - add define to the driver
in cleanup series, month ago or so and then change bindings.

Fine to do it that way

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>



Best regards,
Krzysztof

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

* Re: [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 ` [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI Svyatoslav Ryhel
@ 2025-09-09  0:49   ` Rob Herring (Arm)
  2025-09-09  0:57   ` Rob Herring
  1 sibling, 0 replies; 71+ messages in thread
From: Rob Herring (Arm) @ 2025-09-09  0:49 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Jonathan Hunter, Mauro Carvalho Chehab,
	linux-staging, Krzysztof Kozlowski, linux-tegra, Prashant Gaikwad,
	linux-kernel, Mikko Perttunen, Thomas Zimmermann, Charan Pedumuru,
	Maxime Ripard, Michael Turquette, linux-clk, Simona Vetter,
	Maarten Lankhorst, Dmitry Osipenko, Stephen Boyd,
	Greg Kroah-Hartman, Conor Dooley, David Airlie, devicetree,
	linux-media, dri-devel, Thierry Reding, Sowjanya Komatineni,
	Luca Ceresoli, Jonas Schwöbel


On Sat, 06 Sep 2025 16:53:33 +0300, Svyatoslav Ryhel wrote:
> The avdd-dsi-csi-supply is CSI power supply, it has nothing to do with VI,
> like same supply is used with DSI and has nothing to do with DC. Move it
> to correct place.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml   | 3 ---
>  .../devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml | 3 +++
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 

Acked-by: Rob Herring (Arm) <robh@kernel.org>


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

* Re: [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 ` [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI Svyatoslav Ryhel
  2025-09-09  0:49   ` Rob Herring (Arm)
@ 2025-09-09  0:57   ` Rob Herring
  2025-09-09  5:00     ` Svyatoslav Ryhel
  1 sibling, 1 reply; 71+ messages in thread
From: Rob Herring @ 2025-09-09  0:57 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Sat, Sep 06, 2025 at 04:53:33PM +0300, Svyatoslav Ryhel wrote:
> The avdd-dsi-csi-supply is CSI power supply, it has nothing to do with VI,
> like same supply is used with DSI and has nothing to do with DC. Move it
> to correct place.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  .../devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml   | 3 ---
>  .../devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml | 3 +++
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> index dd67d4162884..bb138277d5e8 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> @@ -75,9 +75,6 @@ properties:
>    ranges:
>      maxItems: 1
>  
> -  avdd-dsi-csi-supply:
> -    description: DSI/CSI power supply. Must supply 1.2 V.
> -
>    vip:
>      $ref: /schemas/display/tegra/nvidia,tegra20-vip.yaml
>  
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> index fa07a40d1004..37f6129c9c92 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> @@ -37,6 +37,9 @@ properties:
>        - const: cile
>        - const: csi_tpg
>  
> +  avdd-dsi-csi-supply:
> +    description: DSI/CSI power supply. Must supply 1.2 V.

On further thought, why does this have 'dsi' in the name at all. If it 
happens to be the same supply for DSI and CSI, that's an SoC integration 
detail. The name here should be local to the module. Perhaps 
'avdd-supply' is enough? Fine to rename it as you are breaking the ABI 
moving it anyways.

Rob

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

* Re: [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  2025-09-09  0:57   ` Rob Herring
@ 2025-09-09  5:00     ` Svyatoslav Ryhel
  2025-09-09 16:03       ` Rob Herring
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-09  5:00 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

вт, 9 вер. 2025 р. о 03:57 Rob Herring <robh@kernel.org> пише:
>
> On Sat, Sep 06, 2025 at 04:53:33PM +0300, Svyatoslav Ryhel wrote:
> > The avdd-dsi-csi-supply is CSI power supply, it has nothing to do with VI,
> > like same supply is used with DSI and has nothing to do with DC. Move it
> > to correct place.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  .../devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml   | 3 ---
> >  .../devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml | 3 +++
> >  2 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > index dd67d4162884..bb138277d5e8 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > @@ -75,9 +75,6 @@ properties:
> >    ranges:
> >      maxItems: 1
> >
> > -  avdd-dsi-csi-supply:
> > -    description: DSI/CSI power supply. Must supply 1.2 V.
> > -
> >    vip:
> >      $ref: /schemas/display/tegra/nvidia,tegra20-vip.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > index fa07a40d1004..37f6129c9c92 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > @@ -37,6 +37,9 @@ properties:
> >        - const: cile
> >        - const: csi_tpg
> >
> > +  avdd-dsi-csi-supply:
> > +    description: DSI/CSI power supply. Must supply 1.2 V.
>
> On further thought, why does this have 'dsi' in the name at all. If it
> happens to be the same supply for DSI and CSI, that's an SoC integration
> detail. The name here should be local to the module. Perhaps
> 'avdd-supply' is enough? Fine to rename it as you are breaking the ABI
> moving it anyways.
>

Not only this supply is common for DSI and CSI, on all schematics I
have seem so far input for this supply on CSI block is always called
avdd-dsi-csi and supply is named accordingly. This patch aims not to
rename supply, which has correct naming IMHO, but to place it in
correct place - CSI, not VI as it is ATM.

> Rob

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

* Re: [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
  2025-09-09  5:00     ` Svyatoslav Ryhel
@ 2025-09-09 16:03       ` Rob Herring
  0 siblings, 0 replies; 71+ messages in thread
From: Rob Herring @ 2025-09-09 16:03 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Tue, Sep 09, 2025 at 08:00:04AM +0300, Svyatoslav Ryhel wrote:
> вт, 9 вер. 2025 р. о 03:57 Rob Herring <robh@kernel.org> пише:
> >
> > On Sat, Sep 06, 2025 at 04:53:33PM +0300, Svyatoslav Ryhel wrote:
> > > The avdd-dsi-csi-supply is CSI power supply, it has nothing to do with VI,
> > > like same supply is used with DSI and has nothing to do with DC. Move it
> > > to correct place.
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > >  .../devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml   | 3 ---
> > >  .../devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml | 3 +++
> > >  2 files changed, 3 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > > index dd67d4162884..bb138277d5e8 100644
> > > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vi.yaml
> > > @@ -75,9 +75,6 @@ properties:
> > >    ranges:
> > >      maxItems: 1
> > >
> > > -  avdd-dsi-csi-supply:
> > > -    description: DSI/CSI power supply. Must supply 1.2 V.
> > > -
> > >    vip:
> > >      $ref: /schemas/display/tegra/nvidia,tegra20-vip.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > index fa07a40d1004..37f6129c9c92 100644
> > > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > @@ -37,6 +37,9 @@ properties:
> > >        - const: cile
> > >        - const: csi_tpg
> > >
> > > +  avdd-dsi-csi-supply:
> > > +    description: DSI/CSI power supply. Must supply 1.2 V.
> >
> > On further thought, why does this have 'dsi' in the name at all. If it
> > happens to be the same supply for DSI and CSI, that's an SoC integration
> > detail. The name here should be local to the module. Perhaps
> > 'avdd-supply' is enough? Fine to rename it as you are breaking the ABI
> > moving it anyways.
> >
> 
> Not only this supply is common for DSI and CSI, on all schematics I
> have seem so far input for this supply on CSI block is always called
> avdd-dsi-csi and supply is named accordingly. This patch aims not to
> rename supply, which has correct naming IMHO, but to place it in
> correct place - CSI, not VI as it is ATM.

Okay, then my Ack stands.

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

* Re: [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-09-06 13:53 ` [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-09-09 16:26   ` Rob Herring
  2025-09-09 16:39     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Rob Herring @ 2025-09-09 16:26 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Sat, Sep 06, 2025 at 04:53:42PM +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,tegra20-csi.yaml     | 104 ++++++++++++++++
>  .../display/tegra/nvidia,tegra30-csi.yaml     | 115 ++++++++++++++++++
>  2 files changed, 219 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
>  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> 
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> new file mode 100644
> index 000000000000..1a2858a5893c
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> @@ -0,0 +1,104 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra20-csi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NVIDIA Tegra20 CSI controller
> +
> +maintainers:
> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - nvidia,tegra20-csi
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    maxItems: 1
> +
> +  avdd-dsi-csi-supply:
> +    description: DSI/CSI power supply. Must supply 1.2 V.
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  "#nvidia,mipi-calibrate-cells":
> +    description: The number of cells in a MIPI calibration specifier.
> +      Should be 1. The single cell specifies an id of the pads that
> +      need to be calibrated for a given device.
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    const: 1

This property goes in the provider. Is the parent node the provider? You 
don't really need any of it if it's all one block.

> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +patternProperties:
> +  "^channel@[0-1]$":
> +    type: object
> +    description: channel 0 represents CSI-A and 1 represents CSI-B
> +    additionalProperties: false
> +
> +    properties:
> +      reg:
> +        maxItems: 1

Instead:

maximum: 1


> +
> +      nvidia,mipi-calibrate:
> +        description: Should contain a phandle and a specifier specifying
> +          which pads are used by this DSI output and need to be
> +          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI.
> +        $ref: /schemas/types.yaml#/definitions/phandle-array

Is DSI applicable here?

> +
> +      "#address-cells":
> +        const: 1
> +
> +      "#size-cells":
> +        const: 0
> +
> +      port@0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: port receiving the video stream from the sensor
> +
> +        properties:
> +          endpoint:
> +            $ref: /schemas/media/video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +            properties:
> +              data-lanes: true

Drop. No need unless you have some constraints like number of lanes?

> +
> +            required:
> +              - data-lanes
> +
> +        required:
> +          - endpoint

Drop.

> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: port sending the video stream to the VI
> +
> +    required:
> +      - reg
> +      - "#address-cells"
> +      - "#size-cells"
> +      - port@0
> +      - port@1
> +
> +additionalProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - power-domains
> +  - "#address-cells"
> +  - "#size-cells"
> +
> +# see nvidia,tegra20-vi.yaml for an example
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> new file mode 100644
> index 000000000000..ea5ebd2f3c65
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> @@ -0,0 +1,115 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra30-csi.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: NVIDIA Tegra30 CSI controller
> +
> +maintainers:
> +  - Svyatoslav Ryhel <clamor95@gmail.com>
> +
> +properties:
> +  compatible:
> +    enum:
> +      - nvidia,tegra30-csi
> +
> +  reg:
> +    maxItems: 1
> +
> +  clocks:
> +    items:
> +      - description: module clock
> +      - description: PAD A clock
> +      - description: PAD B clock
> +
> +  clock-names:
> +    items:
> +      - const: csi
> +      - const: csia-pad
> +      - const: csib-pad

Looks like clocks are the only difference? I think these 2 schemas can 
be merged.

> +
> +  avdd-dsi-csi-supply:
> +    description: DSI/CSI power supply. Must supply 1.2 V.
> +
> +  power-domains:
> +    maxItems: 1
> +
> +  "#nvidia,mipi-calibrate-cells":
> +    description: The number of cells in a MIPI calibration specifier.
> +      Should be 1. The single cell specifies an id of the pads that
> +      need to be calibrated for a given device.
> +    $ref: /schemas/types.yaml#/definitions/uint32
> +    const: 1
> +
> +  "#address-cells":
> +    const: 1
> +
> +  "#size-cells":
> +    const: 0
> +
> +patternProperties:
> +  "^channel@[0-1]$":
> +    type: object
> +    description: channel 0 represents CSI-A and 1 represents CSI-B
> +    additionalProperties: false
> +
> +    properties:
> +      reg:
> +        maxItems: 1
> +
> +      nvidia,mipi-calibrate:
> +        description: Should contain a phandle and a specifier specifying
> +          which pads are used by this DSI output and need to be
> +          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI-A and
> +          3 is for DSI-B
> +        $ref: /schemas/types.yaml#/definitions/phandle-array
> +
> +      "#address-cells":
> +        const: 1
> +
> +      "#size-cells":
> +        const: 0
> +
> +      port@0:
> +        $ref: /schemas/graph.yaml#/$defs/port-base
> +        unevaluatedProperties: false
> +        description: port receiving the video stream from the sensor
> +
> +        properties:
> +          endpoint:
> +            $ref: /schemas/media/video-interfaces.yaml#
> +            unevaluatedProperties: false
> +
> +            properties:
> +              data-lanes: true
> +
> +            required:
> +              - data-lanes
> +
> +        required:
> +          - endpoint
> +
> +      port@1:
> +        $ref: /schemas/graph.yaml#/properties/port
> +        description: port sending the video stream to the VI
> +
> +    required:
> +      - reg
> +      - "#address-cells"
> +      - "#size-cells"
> +      - port@0
> +      - port@1
> +
> +additionalProperties: false
> +
> +required:
> +  - compatible
> +  - reg
> +  - clocks
> +  - clock-names
> +  - power-domains
> +  - "#address-cells"
> +  - "#size-cells"
> +
> +# see nvidia,tegra20-vi.yaml for an example
> -- 
> 2.48.1
> 

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

* Re: [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-09-09 16:26   ` Rob Herring
@ 2025-09-09 16:39     ` Svyatoslav Ryhel
  2025-09-10  2:13       ` Rob Herring
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-09 16: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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

вт, 9 вер. 2025 р. о 19:26 Rob Herring <robh@kernel.org> пише:
>
> On Sat, Sep 06, 2025 at 04:53:42PM +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,tegra20-csi.yaml     | 104 ++++++++++++++++
> >  .../display/tegra/nvidia,tegra30-csi.yaml     | 115 ++++++++++++++++++
> >  2 files changed, 219 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> >  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> > new file mode 100644
> > index 000000000000..1a2858a5893c
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> > @@ -0,0 +1,104 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra20-csi.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: NVIDIA Tegra20 CSI controller
> > +
> > +maintainers:
> > +  - Svyatoslav Ryhel <clamor95@gmail.com>
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - nvidia,tegra20-csi
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    maxItems: 1
> > +
> > +  avdd-dsi-csi-supply:
> > +    description: DSI/CSI power supply. Must supply 1.2 V.
> > +
> > +  power-domains:
> > +    maxItems: 1
> > +
> > +  "#nvidia,mipi-calibrate-cells":
> > +    description: The number of cells in a MIPI calibration specifier.
> > +      Should be 1. The single cell specifies an id of the pads that
> > +      need to be calibrated for a given device.
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    const: 1
>
> This property goes in the provider. Is the parent node the provider? You
> don't really need any of it if it's all one block.
>

Yes parent node is provides and channel is one of receivers, other one
is DSI node.

> > +
> > +  "#address-cells":
> > +    const: 1
> > +
> > +  "#size-cells":
> > +    const: 0
> > +
> > +patternProperties:
> > +  "^channel@[0-1]$":
> > +    type: object
> > +    description: channel 0 represents CSI-A and 1 represents CSI-B
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      reg:
> > +        maxItems: 1
>
> Instead:
>
> maximum: 1
>
>
> > +
> > +      nvidia,mipi-calibrate:
> > +        description: Should contain a phandle and a specifier specifying
> > +          which pads are used by this DSI output and need to be
> > +          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI.
> > +        $ref: /schemas/types.yaml#/definitions/phandle-array
>
> Is DSI applicable here?
>

It is because CSI is calibration provider. I can move it up into
#nvidia,mipi-calibrate-cells which may be more appropriate place.

> > +
> > +      "#address-cells":
> > +        const: 1
> > +
> > +      "#size-cells":
> > +        const: 0
> > +
> > +      port@0:
> > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > +        unevaluatedProperties: false
> > +        description: port receiving the video stream from the sensor
> > +
> > +        properties:
> > +          endpoint:
> > +            $ref: /schemas/media/video-interfaces.yaml#
> > +            unevaluatedProperties: false
> > +
> > +            properties:
> > +              data-lanes: true
>
> Drop. No need unless you have some constraints like number of lanes?
>
> > +
> > +            required:
> > +              - data-lanes
> > +
> > +        required:
> > +          - endpoint
>
> Drop.
>
> > +
> > +      port@1:
> > +        $ref: /schemas/graph.yaml#/properties/port
> > +        description: port sending the video stream to the VI
> > +
> > +    required:
> > +      - reg
> > +      - "#address-cells"
> > +      - "#size-cells"
> > +      - port@0
> > +      - port@1
> > +
> > +additionalProperties: false
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - clocks
> > +  - power-domains
> > +  - "#address-cells"
> > +  - "#size-cells"
> > +
> > +# see nvidia,tegra20-vi.yaml for an example
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> > new file mode 100644
> > index 000000000000..ea5ebd2f3c65
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> > @@ -0,0 +1,115 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra30-csi.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: NVIDIA Tegra30 CSI controller
> > +
> > +maintainers:
> > +  - Svyatoslav Ryhel <clamor95@gmail.com>
> > +
> > +properties:
> > +  compatible:
> > +    enum:
> > +      - nvidia,tegra30-csi
> > +
> > +  reg:
> > +    maxItems: 1
> > +
> > +  clocks:
> > +    items:
> > +      - description: module clock
> > +      - description: PAD A clock
> > +      - description: PAD B clock
> > +
> > +  clock-names:
> > +    items:
> > +      - const: csi
> > +      - const: csia-pad
> > +      - const: csib-pad
>
> Looks like clocks are the only difference? I think these 2 schemas can
> be merged.
>
> > +
> > +  avdd-dsi-csi-supply:
> > +    description: DSI/CSI power supply. Must supply 1.2 V.
> > +
> > +  power-domains:
> > +    maxItems: 1
> > +
> > +  "#nvidia,mipi-calibrate-cells":
> > +    description: The number of cells in a MIPI calibration specifier.
> > +      Should be 1. The single cell specifies an id of the pads that
> > +      need to be calibrated for a given device.
> > +    $ref: /schemas/types.yaml#/definitions/uint32
> > +    const: 1
> > +
> > +  "#address-cells":
> > +    const: 1
> > +
> > +  "#size-cells":
> > +    const: 0
> > +
> > +patternProperties:
> > +  "^channel@[0-1]$":
> > +    type: object
> > +    description: channel 0 represents CSI-A and 1 represents CSI-B
> > +    additionalProperties: false
> > +
> > +    properties:
> > +      reg:
> > +        maxItems: 1
> > +
> > +      nvidia,mipi-calibrate:
> > +        description: Should contain a phandle and a specifier specifying
> > +          which pads are used by this DSI output and need to be
> > +          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI-A and
> > +          3 is for DSI-B
> > +        $ref: /schemas/types.yaml#/definitions/phandle-array
> > +
> > +      "#address-cells":
> > +        const: 1
> > +
> > +      "#size-cells":
> > +        const: 0
> > +
> > +      port@0:
> > +        $ref: /schemas/graph.yaml#/$defs/port-base
> > +        unevaluatedProperties: false
> > +        description: port receiving the video stream from the sensor
> > +
> > +        properties:
> > +          endpoint:
> > +            $ref: /schemas/media/video-interfaces.yaml#
> > +            unevaluatedProperties: false
> > +
> > +            properties:
> > +              data-lanes: true
> > +
> > +            required:
> > +              - data-lanes
> > +
> > +        required:
> > +          - endpoint
> > +
> > +      port@1:
> > +        $ref: /schemas/graph.yaml#/properties/port
> > +        description: port sending the video stream to the VI
> > +
> > +    required:
> > +      - reg
> > +      - "#address-cells"
> > +      - "#size-cells"
> > +      - port@0
> > +      - port@1
> > +
> > +additionalProperties: false
> > +
> > +required:
> > +  - compatible
> > +  - reg
> > +  - clocks
> > +  - clock-names
> > +  - power-domains
> > +  - "#address-cells"
> > +  - "#size-cells"
> > +
> > +# see nvidia,tegra20-vi.yaml for an example
> > --
> > 2.48.1
> >

Every comment which was not answered will be applied, thank you

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

* Re: [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
  2025-09-09 16:39     ` Svyatoslav Ryhel
@ 2025-09-10  2:13       ` Rob Herring
  0 siblings, 0 replies; 71+ messages in thread
From: Rob Herring @ 2025-09-10  2:13 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Tue, Sep 09, 2025 at 07:39:02PM +0300, Svyatoslav Ryhel wrote:
> вт, 9 вер. 2025 р. о 19:26 Rob Herring <robh@kernel.org> пише:
> >
> > On Sat, Sep 06, 2025 at 04:53:42PM +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,tegra20-csi.yaml     | 104 ++++++++++++++++
> > >  .../display/tegra/nvidia,tegra30-csi.yaml     | 115 ++++++++++++++++++
> > >  2 files changed, 219 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> > >  create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra30-csi.yaml
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> > > new file mode 100644
> > > index 000000000000..1a2858a5893c
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-csi.yaml
> > > @@ -0,0 +1,104 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra20-csi.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: NVIDIA Tegra20 CSI controller
> > > +
> > > +maintainers:
> > > +  - Svyatoslav Ryhel <clamor95@gmail.com>
> > > +
> > > +properties:
> > > +  compatible:
> > > +    enum:
> > > +      - nvidia,tegra20-csi
> > > +
> > > +  reg:
> > > +    maxItems: 1
> > > +
> > > +  clocks:
> > > +    maxItems: 1
> > > +
> > > +  avdd-dsi-csi-supply:
> > > +    description: DSI/CSI power supply. Must supply 1.2 V.
> > > +
> > > +  power-domains:
> > > +    maxItems: 1
> > > +
> > > +  "#nvidia,mipi-calibrate-cells":
> > > +    description: The number of cells in a MIPI calibration specifier.
> > > +      Should be 1. The single cell specifies an id of the pads that
> > > +      need to be calibrated for a given device.
> > > +    $ref: /schemas/types.yaml#/definitions/uint32
> > > +    const: 1
> >
> > This property goes in the provider. Is the parent node the provider? You
> > don't really need any of it if it's all one block.
> >
> 
> Yes parent node is provides and channel is one of receivers, other one
> is DSI node.

Please make that clear in the descriptions somewhere.

> 
> > > +
> > > +  "#address-cells":
> > > +    const: 1
> > > +
> > > +  "#size-cells":
> > > +    const: 0
> > > +
> > > +patternProperties:
> > > +  "^channel@[0-1]$":
> > > +    type: object
> > > +    description: channel 0 represents CSI-A and 1 represents CSI-B
> > > +    additionalProperties: false
> > > +
> > > +    properties:
> > > +      reg:
> > > +        maxItems: 1
> >
> > Instead:
> >
> > maximum: 1
> >
> >
> > > +
> > > +      nvidia,mipi-calibrate:
> > > +        description: Should contain a phandle and a specifier specifying
> > > +          which pads are used by this DSI output and need to be
> > > +          calibrated. 0 is for CSI-A, 1 is for CSI-B, 2 is for DSI.
> > > +        $ref: /schemas/types.yaml#/definitions/phandle-array
> >
> > Is DSI applicable here?
> >
> 
> It is because CSI is calibration provider. I can move it up into
> #nvidia,mipi-calibrate-cells which may be more appropriate place.

Yes, as the provider defines the meaning of the cells (and they are 
opaque to the consumer).

Rob

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

* Re: (subset) [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
                   ` (22 preceding siblings ...)
  2025-09-06 13:53 ` [PATCH v2 23/23] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
@ 2025-09-11 16:03 ` Thierry Reding
  23 siblings, 0 replies; 71+ messages in thread
From: Thierry Reding @ 2025-09-11 16:03 UTC (permalink / raw)
  To: 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

From: Thierry Reding <treding@nvidia.com>


On Sat, 06 Sep 2025 16:53:21 +0300, Svyatoslav Ryhel wrote:
> Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC along
> with a set of changes required for that.
> 

Applied, thanks!

[12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI
        (no commit info)

Best regards,
-- 
Thierry Reding <treding@nvidia.com>

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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-06 13:53 ` [PATCH v2 23/23] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
@ 2025-09-15  5:46   ` kernel test robot
  2025-09-22  5:15   ` Mikko Perttunen
  1 sibling, 0 replies; 71+ messages in thread
From: kernel test robot @ 2025-09-15  5:46 UTC (permalink / raw)
  To: Svyatoslav Ryhel, 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,
	Prashant Gaikwad, Michael Turquette, Stephen Boyd,
	Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru
  Cc: oe-kbuild-all, linux-media, dri-devel, devicetree, linux-tegra,
	linux-kernel, linux-clk, linux-staging

Hi Svyatoslav,

kernel test robot noticed the following build warnings:

[auto build test WARNING on tegra/for-next]
[also build test WARNING on robh/for-next clk/clk-next linus/master v6.17-rc6]
[cannot apply to next-20250912]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Svyatoslav-Ryhel/clk-tegra-set-CSUS-as-vi_sensors-gate-for-Tegra20-Tegra30-and-Tegra114/20250906-215750
base:   https://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git for-next
patch link:    https://lore.kernel.org/r/20250906135345.241229-24-clamor95%40gmail.com
patch subject: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
config: arm-randconfig-r131-20250915 (https://download.01.org/0day-ci/archive/20250915/202509151319.M4lQXwA8-lkp@intel.com/config)
compiler: clang version 22.0.0git (https://github.com/llvm/llvm-project 21857ae337e0892a5522b6e7337899caa61de2a6)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250915/202509151319.M4lQXwA8-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202509151319.M4lQXwA8-lkp@intel.com/

All warnings (new ones prefixed by >>):

   In file included from <built-in>:3:
   In file included from include/linux/compiler_types.h:171:
   include/linux/compiler-clang.h:28:9: warning: '__SANITIZE_ADDRESS__' macro redefined [-Wmacro-redefined]
      28 | #define __SANITIZE_ADDRESS__
         |         ^
   <built-in>:366:9: note: previous definition is here
     366 | #define __SANITIZE_ADDRESS__ 1
         |         ^
>> drivers/staging/media/tegra-video/tegra20.c:909:6: warning: variable 'pp' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     909 |         if (ret < 0) {
         |             ^~~~~~~
   drivers/staging/media/tegra-video/tegra20.c:923:53: note: uninitialized use occurs here
     923 |         tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
         |                                                            ^~
   drivers/staging/media/tegra-video/tegra20.c:909:2: note: remove the 'if' if its condition is always false
     909 |         if (ret < 0) {
         |         ^~~~~~~~~~~~~~
     910 |                 dev_warn(csi->dev, "MIPI calibration status timeout!\n");
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     911 |                 goto exit;
         |                 ~~~~~~~~~~
     912 |         }
         |         ~
   drivers/staging/media/tegra-video/tegra20.c:900:6: warning: variable 'pp' is used uninitialized whenever 'if' condition is true [-Wsometimes-uninitialized]
     900 |         if (ret < 0) {
         |             ^~~~~~~
   drivers/staging/media/tegra-video/tegra20.c:923:53: note: uninitialized use occurs here
     923 |         tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
         |                                                            ^~
   drivers/staging/media/tegra-video/tegra20.c:900:2: note: remove the 'if' if its condition is always false
     900 |         if (ret < 0) {
         |         ^~~~~~~~~~~~~~
     901 |                 dev_warn(csi->dev, "MIPI calibration timeout!\n");
         |                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
     902 |                 goto exit;
         |                 ~~~~~~~~~~
     903 |         }
         |         ~
   drivers/staging/media/tegra-video/tegra20.c:886:15: note: initialize the variable 'pp' to silence this warning
     886 |         u32 value, pp, cil;
         |                      ^
         |                       = 0
   3 warnings generated.


vim +909 drivers/staging/media/tegra-video/tegra20.c

   880	
   881	static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
   882	{
   883		struct tegra_csi *csi = mipi->csi;
   884		void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
   885		unsigned int port = mipi->pads;
   886		u32 value, pp, cil;
   887		int ret;
   888	
   889		/* This part is only for CSI */
   890		if (port > PORT_B) {
   891			pm_runtime_put(csi->dev);
   892	
   893			return 0;
   894		}
   895	
   896		guard(mutex)(&csi->mipi_lock);
   897	
   898		ret = readl_relaxed_poll_timeout(cil_status_reg, value,
   899						 value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
   900		if (ret < 0) {
   901			dev_warn(csi->dev, "MIPI calibration timeout!\n");
   902			goto exit;
   903		}
   904	
   905		/* clear status */
   906		tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, value);
   907		ret = readl_relaxed_poll_timeout(cil_status_reg, value,
   908						 !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
 > 909		if (ret < 0) {
   910			dev_warn(csi->dev, "MIPI calibration status timeout!\n");
   911			goto exit;
   912		}
   913	
   914		pp = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
   915		cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
   916		if (pp | cil) {
   917			dev_warn(csi->dev, "Calibration status not been cleared!\n");
   918			ret = -EINVAL;
   919			goto exit;
   920		}
   921	
   922	exit:
   923		tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
   924	
   925		/* un-select to avoid interference with DSI */
   926		tegra20_mipi_write(mipi, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
   927				   CSI_CIL_MIPI_CAL_HSPDOS(0) |
   928				   CSI_CIL_MIPI_CAL_HSPUOS(0) |
   929				   CSI_CIL_MIPI_CAL_TERMOS(4));
   930	
   931		tegra20_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
   932				   CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
   933				   CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
   934				   CSI_CIL_MIPI_CAL_HSPDOS(0) |
   935				   CSI_CIL_MIPI_CAL_HSPUOS(0) |
   936				   CSI_CIL_MIPI_CAL_TERMOS(4));
   937	
   938		pm_runtime_put(csi->dev);
   939	
   940		return ret;
   941	}
   942	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

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

* Re: [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev
  2025-09-06 13:53 ` [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev Svyatoslav Ryhel
@ 2025-09-16 16:04   ` Luca Ceresoli
  2025-09-16 16:24     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Luca Ceresoli @ 2025-09-16 16:04 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

Hello Svyatoslav,

On Sat,  6 Sep 2025 16:53:32 +0300
Svyatoslav Ryhel <clamor95@gmail.com> wrote:

> By default tegra_channel_get_remote_csi_subdev returns next device in pipe
> assuming it is CSI but in case of Tegra20 and Tegra30 it can also be VIP
> or even HOST. Lets check if returned device is actually CSI by comparing
> subdevice operations.

This is just for extra safety, or is there a real case where the lack
of this check creates some issues in your use case?

> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -445,6 +445,22 @@ static const struct v4l2_subdev_ops tegra_csi_ops = {
>  	.pad    = &tegra_csi_pad_ops,
>  };
>  
> +struct v4l2_subdev *tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
> +{
> +	struct media_pad *pad;
> +	struct v4l2_subdev *subdev;
> +
> +	pad = media_pad_remote_pad_first(&chan->pad);
> +	if (!pad)
> +		return NULL;
> +
> +	subdev = media_entity_to_v4l2_subdev(pad->entity);
> +	if (!subdev)
> +		return NULL;
> +
> +	return subdev->ops == &tegra_csi_ops ? subdev : NULL;
> +}

I tested your series on a Tegra20 with a parallel camera, so using the
VIP for parallel input.

The added check on subdev->ops breaks probing the video device:

  tegra-vi 54080000.vi: failed to setup channel controls: -19
  tegra-vi 54080000.vi: failed to register channel 0 notifier: -19

This is because tegra20_chan_capture_kthread_start() is also calling
tegra_channel_get_remote_csi_subdev(), but when using VIP subdev->ops
points to tegra_vip_ops, not tegra_csi_ops.

Surely the "csi" infix in the function name here is misleading. At
quick glance I don't see a good reason for its presence however, as the
callers are not CSI-specific.

If such quick analysis is correct, instead of this diff we should:
 * not move the function out of vi.c
 * rename the function toremove the "_csi" infix
 * if a check is really needed (see comment above), maybe extend it:
   return (subdev->ops == &tegra_csi_ops ||
           subdev->ops == &tegra_vip_ops) ? subdev : NULL;

Let me know your thoughts.

Best regards,
Luca

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev
  2025-09-16 16:04   ` Luca Ceresoli
@ 2025-09-16 16:24     ` Svyatoslav Ryhel
  2025-09-17  7:25       ` Luca Ceresoli
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-16 16:24 UTC (permalink / raw)
  To: Luca Ceresoli
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

вт, 16 вер. 2025 р. о 19:04 Luca Ceresoli <luca.ceresoli@bootlin.com> пише:
>
> Hello Svyatoslav,
>
> On Sat,  6 Sep 2025 16:53:32 +0300
> Svyatoslav Ryhel <clamor95@gmail.com> wrote:
>
> > By default tegra_channel_get_remote_csi_subdev returns next device in pipe
> > assuming it is CSI but in case of Tegra20 and Tegra30 it can also be VIP
> > or even HOST. Lets check if returned device is actually CSI by comparing
> > subdevice operations.
>
> This is just for extra safety, or is there a real case where the lack
> of this check creates some issues in your use case?
>
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -445,6 +445,22 @@ static const struct v4l2_subdev_ops tegra_csi_ops = {
> >       .pad    = &tegra_csi_pad_ops,
> >  };
> >
> > +struct v4l2_subdev *tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
> > +{
> > +     struct media_pad *pad;
> > +     struct v4l2_subdev *subdev;
> > +
> > +     pad = media_pad_remote_pad_first(&chan->pad);
> > +     if (!pad)
> > +             return NULL;
> > +
> > +     subdev = media_entity_to_v4l2_subdev(pad->entity);
> > +     if (!subdev)
> > +             return NULL;
> > +
> > +     return subdev->ops == &tegra_csi_ops ? subdev : NULL;
> > +}
>
> I tested your series on a Tegra20 with a parallel camera, so using the
> VIP for parallel input.
>
> The added check on subdev->ops breaks probing the video device:
>
>   tegra-vi 54080000.vi: failed to setup channel controls: -19
>   tegra-vi 54080000.vi: failed to register channel 0 notifier: -19
>
> This is because tegra20_chan_capture_kthread_start() is also calling
> tegra_channel_get_remote_csi_subdev(), but when using VIP subdev->ops
> points to tegra_vip_ops, not tegra_csi_ops.
>

Your assumption is wrong. 'tegra_channel_get_remote_csi_subdev' is
designed to get next device which is expected to be CSI, NOT VIP
(obviously, Tegra210 has no VIP). It seems that VIP implementation did
not take into account that CSI even exists.  -19 errors are due to
tegra_vi_graph_notify_complete not able to get next media device in
the line. Correct approach would be to add similar helper for VIP and
check if next device is VIP. Since I have no devices with VIP support
I could not test this properly. I can add this in next iteration if
you are willing to test.

Best regards,
Svyatoslav R.

> Surely the "csi" infix in the function name here is misleading. At
> quick glance I don't see a good reason for its presence however, as the
> callers are not CSI-specific.
>
> If such quick analysis is correct, instead of this diff we should:
>  * not move the function out of vi.c
>  * rename the function toremove the "_csi" infix
>  * if a check is really needed (see comment above), maybe extend it:
>    return (subdev->ops == &tegra_csi_ops ||
>            subdev->ops == &tegra_vip_ops) ? subdev : NULL;
>
> Let me know your thoughts.
>
> Best regards,
> Luca
>
> --
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

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

* Re: [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev
  2025-09-16 16:24     ` Svyatoslav Ryhel
@ 2025-09-17  7:25       ` Luca Ceresoli
  2025-09-17  7:49         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Luca Ceresoli @ 2025-09-17  7:25 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

Hello Svyatoslav,

On Tue, 16 Sep 2025 19:24:52 +0300
Svyatoslav Ryhel <clamor95@gmail.com> wrote:

> вт, 16 вер. 2025 р. о 19:04 Luca Ceresoli <luca.ceresoli@bootlin.com> пише:
> >
> > Hello Svyatoslav,
> >
> > On Sat,  6 Sep 2025 16:53:32 +0300
> > Svyatoslav Ryhel <clamor95@gmail.com> wrote:
> >  
> > > By default tegra_channel_get_remote_csi_subdev returns next device in pipe
> > > assuming it is CSI but in case of Tegra20 and Tegra30 it can also be VIP
> > > or even HOST. Lets check if returned device is actually CSI by comparing
> > > subdevice operations.  
> >
> > This is just for extra safety, or is there a real case where the lack
> > of this check creates some issues in your use case?
> >  
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -445,6 +445,22 @@ static const struct v4l2_subdev_ops tegra_csi_ops = {
> > >       .pad    = &tegra_csi_pad_ops,
> > >  };
> > >
> > > +struct v4l2_subdev *tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
> > > +{
> > > +     struct media_pad *pad;
> > > +     struct v4l2_subdev *subdev;
> > > +
> > > +     pad = media_pad_remote_pad_first(&chan->pad);
> > > +     if (!pad)
> > > +             return NULL;
> > > +
> > > +     subdev = media_entity_to_v4l2_subdev(pad->entity);
> > > +     if (!subdev)
> > > +             return NULL;
> > > +
> > > +     return subdev->ops == &tegra_csi_ops ? subdev : NULL;
> > > +}  
> >
> > I tested your series on a Tegra20 with a parallel camera, so using the
> > VIP for parallel input.
> >
> > The added check on subdev->ops breaks probing the video device:
> >
> >   tegra-vi 54080000.vi: failed to setup channel controls: -19
> >   tegra-vi 54080000.vi: failed to register channel 0 notifier: -19
> >
> > This is because tegra20_chan_capture_kthread_start() is also calling
> > tegra_channel_get_remote_csi_subdev(), but when using VIP subdev->ops
> > points to tegra_vip_ops, not tegra_csi_ops.
> >  
> 
> Your assumption is wrong. 'tegra_channel_get_remote_csi_subdev' is
> designed to get next device which is expected to be CSI, NOT VIP
> (obviously, Tegra210 has no VIP). It seems that VIP implementation did
> not take into account that CSI even exists.

IIRC it's rather the initial VI implementation was meant to be open to
supporting both VIP and CSI but some CSI assumptions sneaked in. Which
is somewhat unavoidable if only CSI could be tested, isn't it? So I had
to change some when adding VIP (trying hard myself to not break CSI and
T210).

>  -19 errors are due to
> tegra_vi_graph_notify_complete not able to get next media device in
> the line. Correct approach would be to add similar helper for VIP and
> check if next device is VIP.

I think it's almost correct.

tegra_channel_get_remote_csi_subdev() is called:
 * in vi.c, where it is expeted to return either a CSI or VIP subdev
 * in tegra210.c, which apparently supports CSI only 
   (I don't know whether the hardware has parallel input)
 * in tegra20.c [added by patch 23 in this series] where only a CSI
   subdev is wanted

Based on that,  you're right that we need two functions, but they
should be:

 1. one to return the remote subdev, be it CSI or VIP
    a. perhaps called tegra_channel_get_remote_subdev()
    b. perhaps in vi.c
    c. not checking subdev->ops (or checking for csi||vip)
 2. one to return the remote subdev, only if it is CSI
    a. perhaps called tegra_channel_get_remote_csi_subdev()
    b. perhaps in csi.c
    c. checking subdev->ops == tegra_csi_ops

The function in mainline as of now complies with 2a, 1b, 1c, so it is a
hybrid.

In other words, what I propose is:

 * rename the current tegra_channel_get_remote_csi_subdev()
   to remove the "_csi" infix, so the name reflects what it does
   - optionally add the check for (csi||vip)
 * add tegra_channel_get_remote_csi_subdev() for where a CSI-only
   subdev is needed: that's exactly the function you are adding to csi.c
   in this patch

Does it look correct?

> Since I have no devices with VIP support
> I could not test this properly.

Of course, no problem. I can test it (but I cannot test CSI).

> I can add this in next iteration if
> you are willing to test.

Yes, please do, thanks.

Luca

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev
  2025-09-17  7:25       ` Luca Ceresoli
@ 2025-09-17  7:49         ` Svyatoslav Ryhel
  0 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-17  7:49 UTC (permalink / raw)
  To: Luca Ceresoli
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

ср, 17 вер. 2025 р. о 10:25 Luca Ceresoli <luca.ceresoli@bootlin.com> пише:
>
> Hello Svyatoslav,
>
> On Tue, 16 Sep 2025 19:24:52 +0300
> Svyatoslav Ryhel <clamor95@gmail.com> wrote:
>
> > вт, 16 вер. 2025 р. о 19:04 Luca Ceresoli <luca.ceresoli@bootlin.com> пише:
> > >
> > > Hello Svyatoslav,
> > >
> > > On Sat,  6 Sep 2025 16:53:32 +0300
> > > Svyatoslav Ryhel <clamor95@gmail.com> wrote:
> > >
> > > > By default tegra_channel_get_remote_csi_subdev returns next device in pipe
> > > > assuming it is CSI but in case of Tegra20 and Tegra30 it can also be VIP
> > > > or even HOST. Lets check if returned device is actually CSI by comparing
> > > > subdevice operations.
> > >
> > > This is just for extra safety, or is there a real case where the lack
> > > of this check creates some issues in your use case?
> > >
> > > > --- a/drivers/staging/media/tegra-video/csi.c
> > > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > > @@ -445,6 +445,22 @@ static const struct v4l2_subdev_ops tegra_csi_ops = {
> > > >       .pad    = &tegra_csi_pad_ops,
> > > >  };
> > > >
> > > > +struct v4l2_subdev *tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
> > > > +{
> > > > +     struct media_pad *pad;
> > > > +     struct v4l2_subdev *subdev;
> > > > +
> > > > +     pad = media_pad_remote_pad_first(&chan->pad);
> > > > +     if (!pad)
> > > > +             return NULL;
> > > > +
> > > > +     subdev = media_entity_to_v4l2_subdev(pad->entity);
> > > > +     if (!subdev)
> > > > +             return NULL;
> > > > +
> > > > +     return subdev->ops == &tegra_csi_ops ? subdev : NULL;
> > > > +}
> > >
> > > I tested your series on a Tegra20 with a parallel camera, so using the
> > > VIP for parallel input.
> > >
> > > The added check on subdev->ops breaks probing the video device:
> > >
> > >   tegra-vi 54080000.vi: failed to setup channel controls: -19
> > >   tegra-vi 54080000.vi: failed to register channel 0 notifier: -19
> > >
> > > This is because tegra20_chan_capture_kthread_start() is also calling
> > > tegra_channel_get_remote_csi_subdev(), but when using VIP subdev->ops
> > > points to tegra_vip_ops, not tegra_csi_ops.
> > >
> >
> > Your assumption is wrong. 'tegra_channel_get_remote_csi_subdev' is
> > designed to get next device which is expected to be CSI, NOT VIP
> > (obviously, Tegra210 has no VIP). It seems that VIP implementation did
> > not take into account that CSI even exists.
>
> IIRC it's rather the initial VI implementation was meant to be open to
> supporting both VIP and CSI but some CSI assumptions sneaked in. Which
> is somewhat unavoidable if only CSI could be tested, isn't it? So I had
> to change some when adding VIP (trying hard myself to not break CSI and
> T210).
>

It may be initial VI, that is not that important since my goal is not
blame anyone but to implement stuff I would like to see working. If my
words offended you, I am sorry for that.

> >  -19 errors are due to
> > tegra_vi_graph_notify_complete not able to get next media device in
> > the line. Correct approach would be to add similar helper for VIP and
> > check if next device is VIP.
>
> I think it's almost correct.
>
> tegra_channel_get_remote_csi_subdev() is called:
>  * in vi.c, where it is expeted to return either a CSI or VIP subdev
>  * in tegra210.c, which apparently supports CSI only
>    (I don't know whether the hardware has parallel input)
>  * in tegra20.c [added by patch 23 in this series] where only a CSI
>    subdev is wanted
>
> Based on that,  you're right that we need two functions, but they
> should be:
>
>  1. one to return the remote subdev, be it CSI or VIP
>     a. perhaps called tegra_channel_get_remote_subdev()
>     b. perhaps in vi.c
>     c. not checking subdev->ops (or checking for csi||vip)
>  2. one to return the remote subdev, only if it is CSI
>     a. perhaps called tegra_channel_get_remote_csi_subdev()
>     b. perhaps in csi.c
>     c. checking subdev->ops == tegra_csi_ops
>
> The function in mainline as of now complies with 2a, 1b, 1c, so it is a
> hybrid.
>
> In other words, what I propose is:
>
>  * rename the current tegra_channel_get_remote_csi_subdev()
>    to remove the "_csi" infix, so the name reflects what it does
>    - optionally add the check for (csi||vip)
>  * add tegra_channel_get_remote_csi_subdev() for where a CSI-only
>    subdev is needed: that's exactly the function you are adding to csi.c
>    in this patch
>
> Does it look correct?
>

Yes, if this was your initial idea then I must have misunderstood you,
you are correct. We can agree that each VI source should have its own
get_remote_device function since VI configuration cannot be agnostic
in relation to the source. ATM since only CSI and VIP are supported we
can have only one for CSI and use VIP as default option, which is
fine. Meanwhile, since core VI configuration (vi.c) does not perform
any specific operations with VIs source, we can leave
tegra_channel_get_remote_csi_subdev structure as is, just call it smth
like tegra_channel_get_remote_bridge_subdev and use it in vi, it will
get any VIs source device in the pipe regardless of its type.

> > Since I have no devices with VIP support
> > I could not test this properly.
>
> Of course, no problem. I can test it (but I cannot test CSI).
>

Good, CSI is not an issue, I am always checking if it remains functional.

> > I can add this in next iteration if
> > you are willing to test.
>
> Yes, please do, thanks.
>
> Luca
>
> --
> Luca Ceresoli, Bootlin
> Embedded Linux and Kernel engineering
> https://bootlin.com

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

* Re: [PATCH v2 13/23] staging: media: tegra-video: csi: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 ` [PATCH v2 13/23] staging: media: tegra-video: csi: " Svyatoslav Ryhel
@ 2025-09-17  7:52   ` Luca Ceresoli
  2025-09-22  4:11   ` Mikko Perttunen
  1 sibling, 0 replies; 71+ messages in thread
From: Luca Ceresoli @ 2025-09-17  7:52 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Sat,  6 Sep 2025 16:53:34 +0300
Svyatoslav Ryhel <clamor95@gmail.com> wrote:

> The avdd-dsi-csi-supply is CSI power supply not VI, hence move it to
> proper place.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>

Tested-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # Tegra20 VIP
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30
  2025-09-06 13:53 ` [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-09-17  7:52   ` Luca Ceresoli
  0 siblings, 0 replies; 71+ messages in thread
From: Luca Ceresoli @ 2025-09-17  7:52 UTC (permalink / raw)
  To: Svyatoslav Ryhel
  Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
	Sowjanya Komatineni, David Airlie, Simona Vetter,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

Hello Svyatoslav,

On Sat,  6 Sep 2025 16:53:26 +0300
Svyatoslav Ryhel <clamor95@gmail.com> wrote:

> Existing VI and VIP implementation for Tegra20 is fully compatible with
> Tegra30.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>

Tested-by: Luca Ceresoli <luca.ceresoli@bootlin.com> # Tegra20 VIP
Reviewed-by: Luca Ceresoli <luca.ceresoli@bootlin.com>

-- 
Luca Ceresoli, Bootlin
Embedded Linux and Kernel engineering
https://bootlin.com

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

* Re: [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114
  2025-09-06 13:53 ` [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114 Svyatoslav Ryhel
@ 2025-09-19  6:29   ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-19  6: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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> CSUS clock which is camera MCLK, is also a clock gate for vi_sensor so
> lets model it by creating CSUS grate with vi_sensor as a parent.

s/grate/gate/; "vi_sensor's" in commit message.

The commit message is a bit difficult to understand (to me at least), perhaps explain it in terms of the clock signal flow, e.g. "The CSUS clock is a clock gate for the output clock signal primarily sourced from the VI_SENSOR clock. This clock signal is used as an input MCLK clock for cameras."

For Tegra30/114, I think this is correct. For Tegra20, I noticed that for the two other output clocks -- cdev1 and cdev2 -- we already are modelling the source clock muxing in the clock framework through clocks called cdev1_mux and cdev2_mux which are registered as read-only mux clocks in pinctrl-tegra20.c. So I think the same should be done for csus -- add a csus_mux clock in pinctrl-tegra20.c, and make it csus's parent. For Tegra30 and later chips, these output clocks seem to have only one source clock.

Thanks,
Mikko

> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra114.c | 7 ++++++-
>  drivers/clk/tegra/clk-tegra20.c  | 7 ++++++-
>  drivers/clk/tegra/clk-tegra30.c  | 7 ++++++-
>  3 files changed, 18 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
> index 186b0b81c1ec..00282b0d3763 100644
> --- a/drivers/clk/tegra/clk-tegra114.c
> +++ b/drivers/clk/tegra/clk-tegra114.c
> @@ -691,7 +691,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
>  	[tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true },
>  	[tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true },
>  	[tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true },
> -	[tegra_clk_csus] = { .dt_id = TEGRA114_CLK_CSUS, .present = true },
>  	[tegra_clk_mselect] = { .dt_id = TEGRA114_CLK_MSELECT, .present = true },
>  	[tegra_clk_tsensor] = { .dt_id = TEGRA114_CLK_TSENSOR, .present = true },
>  	[tegra_clk_i2s3] = { .dt_id = TEGRA114_CLK_I2S3, .present = true },
> @@ -1047,6 +1046,12 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
>  					     0, 82, periph_clk_enb_refcnt);
>  	clks[TEGRA114_CLK_DSIB] = clk;
>  
> +	/* csus */
> +	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
> +					     clk_base, 0, TEGRA114_CLK_CSUS,
> +					     periph_clk_enb_refcnt);
> +	clks[TEGRA114_CLK_CSUS] = clk;
> +
>  	/* emc mux */
>  	clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
>  			       ARRAY_SIZE(mux_pllmcp_clkm),
> diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
> index 2c58ce25af75..bf9a9f8ddf62 100644
> --- a/drivers/clk/tegra/clk-tegra20.c
> +++ b/drivers/clk/tegra/clk-tegra20.c
> @@ -530,7 +530,6 @@ static struct tegra_clk tegra20_clks[tegra_clk_max] __initdata = {
>  	[tegra_clk_rtc] = { .dt_id = TEGRA20_CLK_RTC, .present = true },
>  	[tegra_clk_timer] = { .dt_id = TEGRA20_CLK_TIMER, .present = true },
>  	[tegra_clk_kbc] = { .dt_id = TEGRA20_CLK_KBC, .present = true },
> -	[tegra_clk_csus] = { .dt_id = TEGRA20_CLK_CSUS, .present = true },
>  	[tegra_clk_vcp] = { .dt_id = TEGRA20_CLK_VCP, .present = true },
>  	[tegra_clk_bsea] = { .dt_id = TEGRA20_CLK_BSEA, .present = true },
>  	[tegra_clk_bsev] = { .dt_id = TEGRA20_CLK_BSEV, .present = true },
> @@ -807,6 +806,12 @@ static void __init tegra20_periph_clk_init(void)
>  	clk_register_clkdev(clk, NULL, "dsi");
>  	clks[TEGRA20_CLK_DSI] = clk;
>  
> +	/* csus */
> +	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
> +					     clk_base, 0, TEGRA20_CLK_CSUS,
> +					     periph_clk_enb_refcnt);
> +	clks[TEGRA20_CLK_CSUS] = clk;
> +
>  	/* pex */
>  	clk = tegra_clk_register_periph_gate("pex", "clk_m", 0, clk_base, 0, 70,
>  				    periph_clk_enb_refcnt);
> diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
> index 82a8cb9545eb..ca367184e185 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -779,7 +779,6 @@ static struct tegra_clk tegra30_clks[tegra_clk_max] __initdata = {
>  	[tegra_clk_rtc] = { .dt_id = TEGRA30_CLK_RTC, .present = true },
>  	[tegra_clk_timer] = { .dt_id = TEGRA30_CLK_TIMER, .present = true },
>  	[tegra_clk_kbc] = { .dt_id = TEGRA30_CLK_KBC, .present = true },
> -	[tegra_clk_csus] = { .dt_id = TEGRA30_CLK_CSUS, .present = true },
>  	[tegra_clk_vcp] = { .dt_id = TEGRA30_CLK_VCP, .present = true },
>  	[tegra_clk_bsea] = { .dt_id = TEGRA30_CLK_BSEA, .present = true },
>  	[tegra_clk_bsev] = { .dt_id = TEGRA30_CLK_BSEV, .present = true },
> @@ -1008,6 +1007,12 @@ static void __init tegra30_periph_clk_init(void)
>  				    0, 48, periph_clk_enb_refcnt);
>  	clks[TEGRA30_CLK_DSIA] = clk;
>  
> +	/* csus */
> +	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
> +					     clk_base, 0, TEGRA30_CLK_CSUS,
> +					     periph_clk_enb_refcnt);
> +	clks[TEGRA30_CLK_CSUS] = 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] 71+ messages in thread

* Re: [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates
  2025-09-06 13:53 ` [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates Svyatoslav Ryhel
@ 2025-09-19  6:33   ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-19  6:33 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI pad bits in both PLLD and PLLD2 clocks that are required
> for the correct work of the CSI block. Add CSI pad A and pad B clock gates
> with PLLD/PLLD2 parents, respectively. Add plld2 spinlock, like one plld
> has to be used for clock gate registration.

I might add a note that the spinlocks are needed since both the PLLDx and CSIx_PAD clocks use the same registers.

In any case,

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

> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/clk/tegra/clk-tegra30.c | 13 ++++++++++++-
>  1 file changed, 12 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
> index ca738bc64615..61fe527ee6c1 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -154,6 +154,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,16 @@ 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);
> +	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);
> +	clks[TEGRA30_CLK_CSIB_PAD] = clk;
> +
>  	/* csus */
>  	clk = tegra_clk_register_periph_gate("csus", "vi_sensor", 0,
>  					     clk_base, 0, TEGRA30_CLK_CSUS,
> 





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

* Re: [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations
  2025-09-06 13:53 ` [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations Svyatoslav Ryhel
@ 2025-09-19  6:47   ` Mikko Perttunen
  2025-09-19  7:58     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-19  6:47 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> This commit converts the existing MIPI code to use operations, which is a
> necessary step for the Tegra20/Tegra30 SoCs. Additionally, it creates a
> dedicated header file, tegra-mipi-cal.h, to contain the MIPI calibration
> functions, improving code organization and readability.

I'd write out "operation function pointers", at least the first time. Just "operations" isn't clear to me.

Please write the commit message in imperative mood (like you've done in other patches).

> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/gpu/drm/tegra/dsi.c             |   1 +
>  drivers/gpu/host1x/mipi.c               |  40 +++------
>  drivers/staging/media/tegra-video/csi.c |   1 +
>  include/linux/host1x.h                  |  10 ---
>  include/linux/tegra-mipi-cal.h          | 111 ++++++++++++++++++++++++
>  5 files changed, 126 insertions(+), 37 deletions(-)
>  create mode 100644 include/linux/tegra-mipi-cal.h
> 
> diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> index 64f12a85a9dd..278bf2c85524 100644
> --- a/drivers/gpu/drm/tegra/dsi.c
> +++ b/drivers/gpu/drm/tegra/dsi.c
> @@ -14,6 +14,7 @@
>  #include <linux/pm_runtime.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/reset.h>
> +#include <linux/tegra-mipi-cal.h>
>  
>  #include <video/mipi_display.h>
>  
> diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
> index e51b43dd15a3..2fa339a428f3 100644
> --- a/drivers/gpu/host1x/mipi.c
> +++ b/drivers/gpu/host1x/mipi.c
> @@ -27,6 +27,7 @@
>  #include <linux/of_platform.h>
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
> +#include <linux/tegra-mipi-cal.h>
>  
>  #include "dev.h"
>  
> @@ -116,23 +117,6 @@ struct tegra_mipi_soc {
>  	u8 hsclkpuos;
>  };
>  
> -struct tegra_mipi {
> -	const struct tegra_mipi_soc *soc;
> -	struct device *dev;
> -	void __iomem *regs;
> -	struct mutex lock;
> -	struct clk *clk;
> -
> -	unsigned long usage_count;
> -};
> -
> -struct tegra_mipi_device {
> -	struct platform_device *pdev;
> -	struct tegra_mipi *mipi;
> -	struct device *device;
> -	unsigned long pads;
> -};
> -
>  static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
>  				   unsigned long offset)
>  {
> @@ -261,7 +245,7 @@ void tegra_mipi_free(struct tegra_mipi_device *device)
>  }
>  EXPORT_SYMBOL(tegra_mipi_free);
>  
> -int tegra_mipi_enable(struct tegra_mipi_device *dev)
> +static int tegra114_mipi_enable(struct tegra_mipi_device *dev)
>  {
>  	int err = 0;
>  
> @@ -273,11 +257,9 @@ int tegra_mipi_enable(struct tegra_mipi_device *dev)
>  	mutex_unlock(&dev->mipi->lock);
>  
>  	return err;
> -
>  }
> -EXPORT_SYMBOL(tegra_mipi_enable);
>  
> -int tegra_mipi_disable(struct tegra_mipi_device *dev)
> +static int tegra114_mipi_disable(struct tegra_mipi_device *dev)
>  {
>  	int err = 0;
>  
> @@ -289,11 +271,9 @@ int tegra_mipi_disable(struct tegra_mipi_device *dev)
>  	mutex_unlock(&dev->mipi->lock);
>  
>  	return err;
> -
>  }
> -EXPORT_SYMBOL(tegra_mipi_disable);
>  
> -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> +static int tegra114_mipi_finish_calibration(struct tegra_mipi_device *device)
>  {
>  	struct tegra_mipi *mipi = device->mipi;
>  	void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
> @@ -309,9 +289,8 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
>  
>  	return err;
>  }
> -EXPORT_SYMBOL(tegra_mipi_finish_calibration);
>  
> -int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> +static int tegra114_mipi_start_calibration(struct tegra_mipi_device *device)
>  {
>  	const struct tegra_mipi_soc *soc = device->mipi->soc;
>  	unsigned int i;
> @@ -384,7 +363,13 @@ int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
>  
>  	return 0;
>  }
> -EXPORT_SYMBOL(tegra_mipi_start_calibration);
> +
> +static const struct tegra_mipi_ops tegra114_mipi_ops = {
> +	.tegra_mipi_enable = tegra114_mipi_enable,
> +	.tegra_mipi_disable = tegra114_mipi_disable,
> +	.tegra_mipi_start_calibration = tegra114_mipi_start_calibration,
> +	.tegra_mipi_finish_calibration = tegra114_mipi_finish_calibration,
> +};
>  
>  static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
>  	{ .data = MIPI_CAL_CONFIG_CSIA },
> @@ -512,6 +497,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
>  
>  	mipi->soc = match->data;
>  	mipi->dev = &pdev->dev;
> +	mipi->ops = &tegra114_mipi_ops;
>  
>  	mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
>  	if (IS_ERR(mipi->regs))
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index 74c92db1032f..9e3bd6109781 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -12,6 +12,7 @@
>  #include <linux/of_graph.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_runtime.h>
> +#include <linux/tegra-mipi-cal.h>
>  
>  #include <media/v4l2-fwnode.h>
>  
> diff --git a/include/linux/host1x.h b/include/linux/host1x.h
> index 9fa9c30a34e6..b1c6514859d3 100644
> --- a/include/linux/host1x.h
> +++ b/include/linux/host1x.h
> @@ -453,16 +453,6 @@ void host1x_client_unregister(struct host1x_client *client);
>  int host1x_client_suspend(struct host1x_client *client);
>  int host1x_client_resume(struct host1x_client *client);
>  
> -struct tegra_mipi_device;
> -
> -struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> -					     struct device_node *np);
> -void tegra_mipi_free(struct tegra_mipi_device *device);
> -int tegra_mipi_enable(struct tegra_mipi_device *device);
> -int tegra_mipi_disable(struct tegra_mipi_device *device);
> -int tegra_mipi_start_calibration(struct tegra_mipi_device *device);
> -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
> -
>  /* host1x memory contexts */
>  
>  struct host1x_memory_context {
> diff --git a/include/linux/tegra-mipi-cal.h b/include/linux/tegra-mipi-cal.h
> new file mode 100644
> index 000000000000..2bfdbfd3cb77
> --- /dev/null
> +++ b/include/linux/tegra-mipi-cal.h
> @@ -0,0 +1,111 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef __TEGRA_MIPI_CAL_H_
> +#define __TEGRA_MIPI_CAL_H_
> +
> +struct tegra_mipi {
> +	const struct tegra_mipi_soc *soc;
> +	const struct tegra_mipi_ops *ops;
> +	struct device *dev;
> +	void __iomem *regs;
> +	struct mutex lock;
> +	struct clk *clk;
> +
> +	unsigned long usage_count;
> +};
> +
> +struct tegra_mipi_device {
> +	struct platform_device *pdev;
> +	struct tegra_mipi *mipi;
> +	struct device *device;
> +	unsigned long pads;
> +};

We should avoid putting implementation details / chip-specific things in the public header. Here's a sketch of what I'm thinking about:

--- tegra-mipi-cal.h:

struct tegra_mipi_device;

struct tegra_mipi_ops {
	// ...
};

int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops);

int tegra_mipi_enable(...);
// ...

--- host1x/mipi.c:

// move tegra114-mipi specific stuff to a new file, e.g. host1x/tegra114-mipi.c

struct tegra_mipi_device {
	struct tegra_mipi_ops *ops;
	struct platform_device *pdev;
};

/* only need to support one provider */
static struct {
	struct device_node *np;
	struct tegra_mipi_ops *ops;
} provider;

int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops)
{
	if (provider.np)
		return -EBUSY;

	provider.np = np;
	provider.ops = ops;

	return 0;
}

struct tegra_mipi_device *tegra_mipi_request(struct *device, struct device_node *np)
{
	struct device_node *phandle_np = /* ... */;
	struct platform_device *pdev;
	struct tegra_mipi_device *mipidev;

	if (provider.np != phandle_np)
		return -ENODEV;

	pdev = /* ... */;

	mipidev = kzalloc(...);
	mipidev->ops = provider.ops;
	mipidev->pdev = pdev;
	mipidev->cells = phandle_cells;

	return mipidev;
}

int tegra_mipi_enable(struct tegra_mipi_device *device)
{
	return device->ops->enable(platform_get_drvdata(device->pdev), device->cells);
}

> +
> +/**
> + * Operations for Tegra MIPI calibration device
> + */
> +struct tegra_mipi_ops {
> +	/**
> +	 * @tegra_mipi_enable:
> +	 *
> +	 * Enable MIPI calibration device
> +	 */
> +	int (*tegra_mipi_enable)(struct tegra_mipi_device *device);

The tegra_mipi_ prefix should be dropped for the field names.

> +
> +	/**
> +	 * @tegra_mipi_disable:
> +	 *
> +	 * Disable MIPI calibration device
> +	 */
> +	int (*tegra_mipi_disable)(struct tegra_mipi_device *device);
> +
> +	/**
> +	 * @tegra_mipi_start_calibration:
> +	 *
> +	 * Start MIPI calibration
> +	 */
> +	int (*tegra_mipi_start_calibration)(struct tegra_mipi_device *device);
> +
> +	/**
> +	 * @tegra_mipi_finish_calibration:
> +	 *
> +	 * Finish MIPI calibration
> +	 */
> +	int (*tegra_mipi_finish_calibration)(struct tegra_mipi_device *device);
> +};
> +
> +struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> +					     struct device_node *np);
> +
> +void tegra_mipi_free(struct tegra_mipi_device *device);
> +
> +static inline int tegra_mipi_enable(struct tegra_mipi_device *device)
> +{
> +	/* Tegra114+ has a dedicated MIPI calibration block */
> +	if (device->mipi) {
> +		if (!device->mipi->ops->tegra_mipi_enable)
> +			return 0;
> +
> +		return device->mipi->ops->tegra_mipi_enable(device);
> +	}
> +
> +	return -ENOSYS;
> +}
> +
> +static inline int tegra_mipi_disable(struct tegra_mipi_device *device)
> +{
> +	if (device->mipi) {
> +		if (!device->mipi->ops->tegra_mipi_disable)
> +			return 0;
> +
> +		return device->mipi->ops->tegra_mipi_disable(device);
> +	}
> +
> +	return -ENOSYS;
> +}
> +
> +static inline int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> +{
> +	if (device->mipi) {
> +		if (!device->mipi->ops->tegra_mipi_start_calibration)
> +			return 0;
> +
> +		return device->mipi->ops->tegra_mipi_start_calibration(device);
> +	}
> +
> +	return -ENOSYS;
> +}
> +
> +static inline int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> +{
> +	if (device->mipi) {
> +		if (!device->mipi->ops->tegra_mipi_finish_calibration)
> +			return 0;
> +
> +		return device->mipi->ops->tegra_mipi_finish_calibration(device);
> +	}
> +
> +	return -ENOSYS;
> +}
> +
> +#endif /* __TEGRA_MIPI_CAL_H_ */
> 





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

* Re: [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations
  2025-09-19  6:47   ` Mikko Perttunen
@ 2025-09-19  7:58     ` Svyatoslav Ryhel
  2025-09-19  8:56       ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-19  7:58 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пт, 19 вер. 2025 р. о 09:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > This commit converts the existing MIPI code to use operations, which is a
> > necessary step for the Tegra20/Tegra30 SoCs. Additionally, it creates a
> > dedicated header file, tegra-mipi-cal.h, to contain the MIPI calibration
> > functions, improving code organization and readability.
>
> I'd write out "operation function pointers", at least the first time. Just "operations" isn't clear to me.
>
> Please write the commit message in imperative mood (like you've done in other patches).
>
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> >  drivers/gpu/drm/tegra/dsi.c             |   1 +
> >  drivers/gpu/host1x/mipi.c               |  40 +++------
> >  drivers/staging/media/tegra-video/csi.c |   1 +
> >  include/linux/host1x.h                  |  10 ---
> >  include/linux/tegra-mipi-cal.h          | 111 ++++++++++++++++++++++++
> >  5 files changed, 126 insertions(+), 37 deletions(-)
> >  create mode 100644 include/linux/tegra-mipi-cal.h
> >
> > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> > index 64f12a85a9dd..278bf2c85524 100644
> > --- a/drivers/gpu/drm/tegra/dsi.c
> > +++ b/drivers/gpu/drm/tegra/dsi.c
> > @@ -14,6 +14,7 @@
> >  #include <linux/pm_runtime.h>
> >  #include <linux/regulator/consumer.h>
> >  #include <linux/reset.h>
> > +#include <linux/tegra-mipi-cal.h>
> >
> >  #include <video/mipi_display.h>
> >
> > diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
> > index e51b43dd15a3..2fa339a428f3 100644
> > --- a/drivers/gpu/host1x/mipi.c
> > +++ b/drivers/gpu/host1x/mipi.c
> > @@ -27,6 +27,7 @@
> >  #include <linux/of_platform.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/slab.h>
> > +#include <linux/tegra-mipi-cal.h>
> >
> >  #include "dev.h"
> >
> > @@ -116,23 +117,6 @@ struct tegra_mipi_soc {
> >       u8 hsclkpuos;
> >  };
> >
> > -struct tegra_mipi {
> > -     const struct tegra_mipi_soc *soc;
> > -     struct device *dev;
> > -     void __iomem *regs;
> > -     struct mutex lock;
> > -     struct clk *clk;
> > -
> > -     unsigned long usage_count;
> > -};
> > -
> > -struct tegra_mipi_device {
> > -     struct platform_device *pdev;
> > -     struct tegra_mipi *mipi;
> > -     struct device *device;
> > -     unsigned long pads;
> > -};
> > -
> >  static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
> >                                  unsigned long offset)
> >  {
> > @@ -261,7 +245,7 @@ void tegra_mipi_free(struct tegra_mipi_device *device)
> >  }
> >  EXPORT_SYMBOL(tegra_mipi_free);
> >
> > -int tegra_mipi_enable(struct tegra_mipi_device *dev)
> > +static int tegra114_mipi_enable(struct tegra_mipi_device *dev)
> >  {
> >       int err = 0;
> >
> > @@ -273,11 +257,9 @@ int tegra_mipi_enable(struct tegra_mipi_device *dev)
> >       mutex_unlock(&dev->mipi->lock);
> >
> >       return err;
> > -
> >  }
> > -EXPORT_SYMBOL(tegra_mipi_enable);
> >
> > -int tegra_mipi_disable(struct tegra_mipi_device *dev)
> > +static int tegra114_mipi_disable(struct tegra_mipi_device *dev)
> >  {
> >       int err = 0;
> >
> > @@ -289,11 +271,9 @@ int tegra_mipi_disable(struct tegra_mipi_device *dev)
> >       mutex_unlock(&dev->mipi->lock);
> >
> >       return err;
> > -
> >  }
> > -EXPORT_SYMBOL(tegra_mipi_disable);
> >
> > -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> > +static int tegra114_mipi_finish_calibration(struct tegra_mipi_device *device)
> >  {
> >       struct tegra_mipi *mipi = device->mipi;
> >       void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
> > @@ -309,9 +289,8 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> >
> >       return err;
> >  }
> > -EXPORT_SYMBOL(tegra_mipi_finish_calibration);
> >
> > -int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> > +static int tegra114_mipi_start_calibration(struct tegra_mipi_device *device)
> >  {
> >       const struct tegra_mipi_soc *soc = device->mipi->soc;
> >       unsigned int i;
> > @@ -384,7 +363,13 @@ int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> >
> >       return 0;
> >  }
> > -EXPORT_SYMBOL(tegra_mipi_start_calibration);
> > +
> > +static const struct tegra_mipi_ops tegra114_mipi_ops = {
> > +     .tegra_mipi_enable = tegra114_mipi_enable,
> > +     .tegra_mipi_disable = tegra114_mipi_disable,
> > +     .tegra_mipi_start_calibration = tegra114_mipi_start_calibration,
> > +     .tegra_mipi_finish_calibration = tegra114_mipi_finish_calibration,
> > +};
> >
> >  static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
> >       { .data = MIPI_CAL_CONFIG_CSIA },
> > @@ -512,6 +497,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
> >
> >       mipi->soc = match->data;
> >       mipi->dev = &pdev->dev;
> > +     mipi->ops = &tegra114_mipi_ops;
> >
> >       mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
> >       if (IS_ERR(mipi->regs))
> > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > index 74c92db1032f..9e3bd6109781 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -12,6 +12,7 @@
> >  #include <linux/of_graph.h>
> >  #include <linux/platform_device.h>
> >  #include <linux/pm_runtime.h>
> > +#include <linux/tegra-mipi-cal.h>
> >
> >  #include <media/v4l2-fwnode.h>
> >
> > diff --git a/include/linux/host1x.h b/include/linux/host1x.h
> > index 9fa9c30a34e6..b1c6514859d3 100644
> > --- a/include/linux/host1x.h
> > +++ b/include/linux/host1x.h
> > @@ -453,16 +453,6 @@ void host1x_client_unregister(struct host1x_client *client);
> >  int host1x_client_suspend(struct host1x_client *client);
> >  int host1x_client_resume(struct host1x_client *client);
> >
> > -struct tegra_mipi_device;
> > -
> > -struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> > -                                          struct device_node *np);
> > -void tegra_mipi_free(struct tegra_mipi_device *device);
> > -int tegra_mipi_enable(struct tegra_mipi_device *device);
> > -int tegra_mipi_disable(struct tegra_mipi_device *device);
> > -int tegra_mipi_start_calibration(struct tegra_mipi_device *device);
> > -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
> > -
> >  /* host1x memory contexts */
> >
> >  struct host1x_memory_context {
> > diff --git a/include/linux/tegra-mipi-cal.h b/include/linux/tegra-mipi-cal.h
> > new file mode 100644
> > index 000000000000..2bfdbfd3cb77
> > --- /dev/null
> > +++ b/include/linux/tegra-mipi-cal.h
> > @@ -0,0 +1,111 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +
> > +#ifndef __TEGRA_MIPI_CAL_H_
> > +#define __TEGRA_MIPI_CAL_H_
> > +
> > +struct tegra_mipi {
> > +     const struct tegra_mipi_soc *soc;
> > +     const struct tegra_mipi_ops *ops;
> > +     struct device *dev;
> > +     void __iomem *regs;
> > +     struct mutex lock;
> > +     struct clk *clk;
> > +
> > +     unsigned long usage_count;
> > +};
> > +
> > +struct tegra_mipi_device {
> > +     struct platform_device *pdev;
> > +     struct tegra_mipi *mipi;
> > +     struct device *device;
> > +     unsigned long pads;
> > +};
>
> We should avoid putting implementation details / chip-specific things in the public header. Here's a sketch of what I'm thinking about:
>
> --- tegra-mipi-cal.h:
>
> struct tegra_mipi_device;
>
> struct tegra_mipi_ops {
>         // ...
> };
>
> int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops);
>
> int tegra_mipi_enable(...);
> // ...
>
> --- host1x/mipi.c:
>
> // move tegra114-mipi specific stuff to a new file, e.g. host1x/tegra114-mipi.c
>
> struct tegra_mipi_device {
>         struct tegra_mipi_ops *ops;
>         struct platform_device *pdev;
> };
>
> /* only need to support one provider */
> static struct {
>         struct device_node *np;
>         struct tegra_mipi_ops *ops;
> } provider;
>
> int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops)
> {
>         if (provider.np)
>                 return -EBUSY;
>
>         provider.np = np;
>         provider.ops = ops;
>
>         return 0;
> }
>
> struct tegra_mipi_device *tegra_mipi_request(struct *device, struct device_node *np)
> {
>         struct device_node *phandle_np = /* ... */;
>         struct platform_device *pdev;
>         struct tegra_mipi_device *mipidev;
>
>         if (provider.np != phandle_np)
>                 return -ENODEV;
>
>         pdev = /* ... */;
>
>         mipidev = kzalloc(...);
>         mipidev->ops = provider.ops;
>         mipidev->pdev = pdev;
>         mipidev->cells = phandle_cells;
>
>         return mipidev;
> }
>
> int tegra_mipi_enable(struct tegra_mipi_device *device)
> {
>         return device->ops->enable(platform_get_drvdata(device->pdev), device->cells);
> }
>
> > +
> > +/**
> > + * Operations for Tegra MIPI calibration device
> > + */
> > +struct tegra_mipi_ops {
> > +     /**
> > +      * @tegra_mipi_enable:
> > +      *
> > +      * Enable MIPI calibration device
> > +      */
> > +     int (*tegra_mipi_enable)(struct tegra_mipi_device *device);
>
> The tegra_mipi_ prefix should be dropped for the field names.
>
> > +
> > +     /**
> > +      * @tegra_mipi_disable:
> > +      *
> > +      * Disable MIPI calibration device
> > +      */
> > +     int (*tegra_mipi_disable)(struct tegra_mipi_device *device);
> > +
> > +     /**
> > +      * @tegra_mipi_start_calibration:
> > +      *
> > +      * Start MIPI calibration
> > +      */
> > +     int (*tegra_mipi_start_calibration)(struct tegra_mipi_device *device);
> > +
> > +     /**
> > +      * @tegra_mipi_finish_calibration:
> > +      *
> > +      * Finish MIPI calibration
> > +      */
> > +     int (*tegra_mipi_finish_calibration)(struct tegra_mipi_device *device);
> > +};
> > +
> > +struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> > +                                          struct device_node *np);
> > +
> > +void tegra_mipi_free(struct tegra_mipi_device *device);
> > +
> > +static inline int tegra_mipi_enable(struct tegra_mipi_device *device)
> > +{
> > +     /* Tegra114+ has a dedicated MIPI calibration block */
> > +     if (device->mipi) {
> > +             if (!device->mipi->ops->tegra_mipi_enable)
> > +                     return 0;
> > +
> > +             return device->mipi->ops->tegra_mipi_enable(device);
> > +     }
> > +
> > +     return -ENOSYS;
> > +}
> > +
> > +static inline int tegra_mipi_disable(struct tegra_mipi_device *device)
> > +{
> > +     if (device->mipi) {
> > +             if (!device->mipi->ops->tegra_mipi_disable)
> > +                     return 0;
> > +
> > +             return device->mipi->ops->tegra_mipi_disable(device);
> > +     }
> > +
> > +     return -ENOSYS;
> > +}
> > +
> > +static inline int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> > +{
> > +     if (device->mipi) {
> > +             if (!device->mipi->ops->tegra_mipi_start_calibration)
> > +                     return 0;
> > +
> > +             return device->mipi->ops->tegra_mipi_start_calibration(device);
> > +     }
> > +
> > +     return -ENOSYS;
> > +}
> > +
> > +static inline int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> > +{
> > +     if (device->mipi) {
> > +             if (!device->mipi->ops->tegra_mipi_finish_calibration)
> > +                     return 0;
> > +
> > +             return device->mipi->ops->tegra_mipi_finish_calibration(device);
> > +     }
> > +
> > +     return -ENOSYS;
> > +}
> > +
> > +#endif /* __TEGRA_MIPI_CAL_H_ */
> >
>

All this is good, but how to include into this CSI? Adding support for
CSI is why I am even touching this at the first place.

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

* Re: [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations
  2025-09-19  7:58     ` Svyatoslav Ryhel
@ 2025-09-19  8:56       ` Svyatoslav Ryhel
  0 siblings, 0 replies; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-19  8:56 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пт, 19 вер. 2025 р. о 10:58 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> пт, 19 вер. 2025 р. о 09:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > This commit converts the existing MIPI code to use operations, which is a
> > > necessary step for the Tegra20/Tegra30 SoCs. Additionally, it creates a
> > > dedicated header file, tegra-mipi-cal.h, to contain the MIPI calibration
> > > functions, improving code organization and readability.
> >
> > I'd write out "operation function pointers", at least the first time. Just "operations" isn't clear to me.
> >
> > Please write the commit message in imperative mood (like you've done in other patches).
> >
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > >  drivers/gpu/drm/tegra/dsi.c             |   1 +
> > >  drivers/gpu/host1x/mipi.c               |  40 +++------
> > >  drivers/staging/media/tegra-video/csi.c |   1 +
> > >  include/linux/host1x.h                  |  10 ---
> > >  include/linux/tegra-mipi-cal.h          | 111 ++++++++++++++++++++++++
> > >  5 files changed, 126 insertions(+), 37 deletions(-)
> > >  create mode 100644 include/linux/tegra-mipi-cal.h
> > >
> > > diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
> > > index 64f12a85a9dd..278bf2c85524 100644
> > > --- a/drivers/gpu/drm/tegra/dsi.c
> > > +++ b/drivers/gpu/drm/tegra/dsi.c
> > > @@ -14,6 +14,7 @@
> > >  #include <linux/pm_runtime.h>
> > >  #include <linux/regulator/consumer.h>
> > >  #include <linux/reset.h>
> > > +#include <linux/tegra-mipi-cal.h>
> > >
> > >  #include <video/mipi_display.h>
> > >
> > > diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
> > > index e51b43dd15a3..2fa339a428f3 100644
> > > --- a/drivers/gpu/host1x/mipi.c
> > > +++ b/drivers/gpu/host1x/mipi.c
> > > @@ -27,6 +27,7 @@
> > >  #include <linux/of_platform.h>
> > >  #include <linux/platform_device.h>
> > >  #include <linux/slab.h>
> > > +#include <linux/tegra-mipi-cal.h>
> > >
> > >  #include "dev.h"
> > >
> > > @@ -116,23 +117,6 @@ struct tegra_mipi_soc {
> > >       u8 hsclkpuos;
> > >  };
> > >
> > > -struct tegra_mipi {
> > > -     const struct tegra_mipi_soc *soc;
> > > -     struct device *dev;
> > > -     void __iomem *regs;
> > > -     struct mutex lock;
> > > -     struct clk *clk;
> > > -
> > > -     unsigned long usage_count;
> > > -};
> > > -
> > > -struct tegra_mipi_device {
> > > -     struct platform_device *pdev;
> > > -     struct tegra_mipi *mipi;
> > > -     struct device *device;
> > > -     unsigned long pads;
> > > -};
> > > -
> > >  static inline u32 tegra_mipi_readl(struct tegra_mipi *mipi,
> > >                                  unsigned long offset)
> > >  {
> > > @@ -261,7 +245,7 @@ void tegra_mipi_free(struct tegra_mipi_device *device)
> > >  }
> > >  EXPORT_SYMBOL(tegra_mipi_free);
> > >
> > > -int tegra_mipi_enable(struct tegra_mipi_device *dev)
> > > +static int tegra114_mipi_enable(struct tegra_mipi_device *dev)
> > >  {
> > >       int err = 0;
> > >
> > > @@ -273,11 +257,9 @@ int tegra_mipi_enable(struct tegra_mipi_device *dev)
> > >       mutex_unlock(&dev->mipi->lock);
> > >
> > >       return err;
> > > -
> > >  }
> > > -EXPORT_SYMBOL(tegra_mipi_enable);
> > >
> > > -int tegra_mipi_disable(struct tegra_mipi_device *dev)
> > > +static int tegra114_mipi_disable(struct tegra_mipi_device *dev)
> > >  {
> > >       int err = 0;
> > >
> > > @@ -289,11 +271,9 @@ int tegra_mipi_disable(struct tegra_mipi_device *dev)
> > >       mutex_unlock(&dev->mipi->lock);
> > >
> > >       return err;
> > > -
> > >  }
> > > -EXPORT_SYMBOL(tegra_mipi_disable);
> > >
> > > -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> > > +static int tegra114_mipi_finish_calibration(struct tegra_mipi_device *device)
> > >  {
> > >       struct tegra_mipi *mipi = device->mipi;
> > >       void __iomem *status_reg = mipi->regs + (MIPI_CAL_STATUS << 2);
> > > @@ -309,9 +289,8 @@ int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> > >
> > >       return err;
> > >  }
> > > -EXPORT_SYMBOL(tegra_mipi_finish_calibration);
> > >
> > > -int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> > > +static int tegra114_mipi_start_calibration(struct tegra_mipi_device *device)
> > >  {
> > >       const struct tegra_mipi_soc *soc = device->mipi->soc;
> > >       unsigned int i;
> > > @@ -384,7 +363,13 @@ int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> > >
> > >       return 0;
> > >  }
> > > -EXPORT_SYMBOL(tegra_mipi_start_calibration);
> > > +
> > > +static const struct tegra_mipi_ops tegra114_mipi_ops = {
> > > +     .tegra_mipi_enable = tegra114_mipi_enable,
> > > +     .tegra_mipi_disable = tegra114_mipi_disable,
> > > +     .tegra_mipi_start_calibration = tegra114_mipi_start_calibration,
> > > +     .tegra_mipi_finish_calibration = tegra114_mipi_finish_calibration,
> > > +};
> > >
> > >  static const struct tegra_mipi_pad tegra114_mipi_pads[] = {
> > >       { .data = MIPI_CAL_CONFIG_CSIA },
> > > @@ -512,6 +497,7 @@ static int tegra_mipi_probe(struct platform_device *pdev)
> > >
> > >       mipi->soc = match->data;
> > >       mipi->dev = &pdev->dev;
> > > +     mipi->ops = &tegra114_mipi_ops;
> > >
> > >       mipi->regs = devm_platform_get_and_ioremap_resource(pdev, 0, NULL);
> > >       if (IS_ERR(mipi->regs))
> > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > index 74c92db1032f..9e3bd6109781 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -12,6 +12,7 @@
> > >  #include <linux/of_graph.h>
> > >  #include <linux/platform_device.h>
> > >  #include <linux/pm_runtime.h>
> > > +#include <linux/tegra-mipi-cal.h>
> > >
> > >  #include <media/v4l2-fwnode.h>
> > >
> > > diff --git a/include/linux/host1x.h b/include/linux/host1x.h
> > > index 9fa9c30a34e6..b1c6514859d3 100644
> > > --- a/include/linux/host1x.h
> > > +++ b/include/linux/host1x.h
> > > @@ -453,16 +453,6 @@ void host1x_client_unregister(struct host1x_client *client);
> > >  int host1x_client_suspend(struct host1x_client *client);
> > >  int host1x_client_resume(struct host1x_client *client);
> > >
> > > -struct tegra_mipi_device;
> > > -
> > > -struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> > > -                                          struct device_node *np);
> > > -void tegra_mipi_free(struct tegra_mipi_device *device);
> > > -int tegra_mipi_enable(struct tegra_mipi_device *device);
> > > -int tegra_mipi_disable(struct tegra_mipi_device *device);
> > > -int tegra_mipi_start_calibration(struct tegra_mipi_device *device);
> > > -int tegra_mipi_finish_calibration(struct tegra_mipi_device *device);
> > > -
> > >  /* host1x memory contexts */
> > >
> > >  struct host1x_memory_context {
> > > diff --git a/include/linux/tegra-mipi-cal.h b/include/linux/tegra-mipi-cal.h
> > > new file mode 100644
> > > index 000000000000..2bfdbfd3cb77
> > > --- /dev/null
> > > +++ b/include/linux/tegra-mipi-cal.h
> > > @@ -0,0 +1,111 @@
> > > +/* SPDX-License-Identifier: GPL-2.0 */
> > > +
> > > +#ifndef __TEGRA_MIPI_CAL_H_
> > > +#define __TEGRA_MIPI_CAL_H_
> > > +
> > > +struct tegra_mipi {
> > > +     const struct tegra_mipi_soc *soc;
> > > +     const struct tegra_mipi_ops *ops;
> > > +     struct device *dev;
> > > +     void __iomem *regs;
> > > +     struct mutex lock;
> > > +     struct clk *clk;
> > > +
> > > +     unsigned long usage_count;
> > > +};
> > > +
> > > +struct tegra_mipi_device {
> > > +     struct platform_device *pdev;
> > > +     struct tegra_mipi *mipi;
> > > +     struct device *device;
> > > +     unsigned long pads;
> > > +};
> >
> > We should avoid putting implementation details / chip-specific things in the public header. Here's a sketch of what I'm thinking about:
> >
> > --- tegra-mipi-cal.h:
> >
> > struct tegra_mipi_device;
> >
> > struct tegra_mipi_ops {
> >         // ...
> > };
> >
> > int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops);
> >
> > int tegra_mipi_enable(...);
> > // ...
> >
> > --- host1x/mipi.c:
> >
> > // move tegra114-mipi specific stuff to a new file, e.g. host1x/tegra114-mipi.c
> >
> > struct tegra_mipi_device {
> >         struct tegra_mipi_ops *ops;
> >         struct platform_device *pdev;
> > };
> >
> > /* only need to support one provider */
> > static struct {
> >         struct device_node *np;
> >         struct tegra_mipi_ops *ops;
> > } provider;
> >
> > int tegra_mipi_add_provider(struct device_node *np, struct tegra_mipi_ops *ops)
> > {
> >         if (provider.np)
> >                 return -EBUSY;
> >
> >         provider.np = np;
> >         provider.ops = ops;
> >
> >         return 0;
> > }
> >
> > struct tegra_mipi_device *tegra_mipi_request(struct *device, struct device_node *np)
> > {
> >         struct device_node *phandle_np = /* ... */;
> >         struct platform_device *pdev;
> >         struct tegra_mipi_device *mipidev;
> >
> >         if (provider.np != phandle_np)
> >                 return -ENODEV;
> >
> >         pdev = /* ... */;
> >
> >         mipidev = kzalloc(...);
> >         mipidev->ops = provider.ops;
> >         mipidev->pdev = pdev;
> >         mipidev->cells = phandle_cells;
> >
> >         return mipidev;
> > }
> >
> > int tegra_mipi_enable(struct tegra_mipi_device *device)
> > {
> >         return device->ops->enable(platform_get_drvdata(device->pdev), device->cells);
> > }
> >
> > > +
> > > +/**
> > > + * Operations for Tegra MIPI calibration device
> > > + */
> > > +struct tegra_mipi_ops {
> > > +     /**
> > > +      * @tegra_mipi_enable:
> > > +      *
> > > +      * Enable MIPI calibration device
> > > +      */
> > > +     int (*tegra_mipi_enable)(struct tegra_mipi_device *device);
> >
> > The tegra_mipi_ prefix should be dropped for the field names.
> >
> > > +
> > > +     /**
> > > +      * @tegra_mipi_disable:
> > > +      *
> > > +      * Disable MIPI calibration device
> > > +      */
> > > +     int (*tegra_mipi_disable)(struct tegra_mipi_device *device);
> > > +
> > > +     /**
> > > +      * @tegra_mipi_start_calibration:
> > > +      *
> > > +      * Start MIPI calibration
> > > +      */
> > > +     int (*tegra_mipi_start_calibration)(struct tegra_mipi_device *device);
> > > +
> > > +     /**
> > > +      * @tegra_mipi_finish_calibration:
> > > +      *
> > > +      * Finish MIPI calibration
> > > +      */
> > > +     int (*tegra_mipi_finish_calibration)(struct tegra_mipi_device *device);
> > > +};
> > > +
> > > +struct tegra_mipi_device *tegra_mipi_request(struct device *device,
> > > +                                          struct device_node *np);
> > > +
> > > +void tegra_mipi_free(struct tegra_mipi_device *device);
> > > +
> > > +static inline int tegra_mipi_enable(struct tegra_mipi_device *device)
> > > +{
> > > +     /* Tegra114+ has a dedicated MIPI calibration block */
> > > +     if (device->mipi) {
> > > +             if (!device->mipi->ops->tegra_mipi_enable)
> > > +                     return 0;
> > > +
> > > +             return device->mipi->ops->tegra_mipi_enable(device);
> > > +     }
> > > +
> > > +     return -ENOSYS;
> > > +}
> > > +
> > > +static inline int tegra_mipi_disable(struct tegra_mipi_device *device)
> > > +{
> > > +     if (device->mipi) {
> > > +             if (!device->mipi->ops->tegra_mipi_disable)
> > > +                     return 0;
> > > +
> > > +             return device->mipi->ops->tegra_mipi_disable(device);
> > > +     }
> > > +
> > > +     return -ENOSYS;
> > > +}
> > > +
> > > +static inline int tegra_mipi_start_calibration(struct tegra_mipi_device *device)
> > > +{
> > > +     if (device->mipi) {
> > > +             if (!device->mipi->ops->tegra_mipi_start_calibration)
> > > +                     return 0;
> > > +
> > > +             return device->mipi->ops->tegra_mipi_start_calibration(device);
> > > +     }
> > > +
> > > +     return -ENOSYS;
> > > +}
> > > +
> > > +static inline int tegra_mipi_finish_calibration(struct tegra_mipi_device *device)
> > > +{
> > > +     if (device->mipi) {
> > > +             if (!device->mipi->ops->tegra_mipi_finish_calibration)
> > > +                     return 0;
> > > +
> > > +             return device->mipi->ops->tegra_mipi_finish_calibration(device);
> > > +     }
> > > +
> > > +     return -ENOSYS;
> > > +}
> > > +
> > > +#endif /* __TEGRA_MIPI_CAL_H_ */
> > >
> >
>
> All this is good, but how to include into this CSI? Adding support for
> CSI is why I am even touching this at the first place.

Nevermind, I have figured it all out.

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

* Re: [PATCH v2 13/23] staging: media: tegra-video: csi: move avdd-dsi-csi-supply from VI to CSI
  2025-09-06 13:53 ` [PATCH v2 13/23] staging: media: tegra-video: csi: " Svyatoslav Ryhel
  2025-09-17  7:52   ` Luca Ceresoli
@ 2025-09-22  4:11   ` Mikko Perttunen
  1 sibling, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  4:11 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> The avdd-dsi-csi-supply is CSI power supply not VI, hence move it to
> proper place.
> 
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
>  drivers/staging/media/tegra-video/csi.c | 19 ++++++++++++++++++-
>  drivers/staging/media/tegra-video/vi.c  | 23 ++---------------------
>  drivers/staging/media/tegra-video/vi.h  |  2 --
>  include/linux/tegra-csi.h               |  2 ++
>  4 files changed, 22 insertions(+), 24 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index c848e4ab51ac..1677eb51ec21 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -710,6 +710,8 @@ static int __maybe_unused csi_runtime_suspend(struct device *dev)
>  
>  	clk_bulk_disable_unprepare(csi->soc->num_clks, csi->clks);
>  
> +	regulator_disable(csi->vdd);
> +
>  	return 0;
>  }
>  
> @@ -718,13 +720,23 @@ static int __maybe_unused csi_runtime_resume(struct device *dev)
>  	struct tegra_csi *csi = dev_get_drvdata(dev);
>  	int ret;
>  
> +	ret = regulator_enable(csi->vdd);
> +	if (ret) {
> +		dev_err(dev, "failed to enable VDD supply: %d\n", ret);
> +		return ret;
> +	}
> +
>  	ret = clk_bulk_prepare_enable(csi->soc->num_clks, csi->clks);
>  	if (ret < 0) {
>  		dev_err(csi->dev, "failed to enable clocks: %d\n", ret);
> -		return ret;
> +		goto disable_vdd;
>  	}
>  
>  	return 0;
> +
> +disable_vdd:
> +	regulator_disable(csi->vdd);
> +	return ret;
>  }
>  
>  static int tegra_csi_init(struct host1x_client *client)
> @@ -802,6 +814,11 @@ static int tegra_csi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	csi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
> +	if (IS_ERR(csi->vdd))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(csi->vdd),
> +				     "failed to get VDD supply");
> +
>  	if (!pdev->dev.pm_domain) {
>  		ret = -ENOENT;
>  		dev_warn(&pdev->dev, "PM domain is not attached: %d\n", ret);
> diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
> index 2deb615547be..05af718b3cdf 100644
> --- a/drivers/staging/media/tegra-video/vi.c
> +++ b/drivers/staging/media/tegra-video/vi.c
> @@ -1405,29 +1405,19 @@ static int __maybe_unused vi_runtime_resume(struct device *dev)
>  	struct tegra_vi *vi = dev_get_drvdata(dev);
>  	int ret;
>  
> -	ret = regulator_enable(vi->vdd);
> -	if (ret) {
> -		dev_err(dev, "failed to enable VDD supply: %d\n", ret);
> -		return ret;
> -	}
> -
>  	ret = clk_set_rate(vi->clk, vi->soc->vi_max_clk_hz);
>  	if (ret) {
>  		dev_err(dev, "failed to set vi clock rate: %d\n", ret);
> -		goto disable_vdd;
> +		return ret;
>  	}
>  
>  	ret = clk_prepare_enable(vi->clk);
>  	if (ret) {
>  		dev_err(dev, "failed to enable vi clock: %d\n", ret);
> -		goto disable_vdd;
> +		return ret;
>  	}
>  
>  	return 0;
> -
> -disable_vdd:
> -	regulator_disable(vi->vdd);
> -	return ret;
>  }
>  
>  static int __maybe_unused vi_runtime_suspend(struct device *dev)
> @@ -1436,8 +1426,6 @@ static int __maybe_unused vi_runtime_suspend(struct device *dev)
>  
>  	clk_disable_unprepare(vi->clk);
>  
> -	regulator_disable(vi->vdd);
> -
>  	return 0;
>  }
>  
> @@ -1882,13 +1870,6 @@ static int tegra_vi_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> -	vi->vdd = devm_regulator_get(&pdev->dev, "avdd-dsi-csi");
> -	if (IS_ERR(vi->vdd)) {
> -		ret = PTR_ERR(vi->vdd);
> -		dev_err(&pdev->dev, "failed to get VDD supply: %d\n", ret);
> -		return ret;
> -	}
> -
>  	if (!pdev->dev.pm_domain) {
>  		ret = -ENOENT;
>  		dev_warn(&pdev->dev, "PM domain is not attached: %d\n", ret);
> diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> index 64655ac1b41f..367667adf745 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -93,7 +93,6 @@ struct tegra_vi_soc {
>   * @client: host1x_client struct
>   * @iomem: register base
>   * @clk: main clock for VI block
> - * @vdd: vdd regulator for VI hardware, normally it is avdd_dsi_csi
>   * @soc: pointer to SoC data structure
>   * @ops: vi operations
>   * @vi_chans: list head for VI channels
> @@ -103,7 +102,6 @@ struct tegra_vi {
>  	struct host1x_client client;
>  	void __iomem *iomem;
>  	struct clk *clk;
> -	struct regulator *vdd;
>  	const struct tegra_vi_soc *soc;
>  	const struct tegra_vi_ops *ops;
>  	struct list_head vi_chans;
> diff --git a/include/linux/tegra-csi.h b/include/linux/tegra-csi.h
> index b47f48ef7115..85c74e22a0cb 100644
> --- a/include/linux/tegra-csi.h
> +++ b/include/linux/tegra-csi.h
> @@ -139,6 +139,7 @@ struct tegra_csi_soc {
>   * @client: host1x_client struct
>   * @iomem: register base
>   * @clks: clock for CSI and CIL
> + * @vdd: vdd regulator for CSI hardware, usually avdd_dsi_csi
>   * @soc: pointer to SoC data structure
>   * @ops: csi operations
>   * @mipi_ops: MIPI calibration operations
> @@ -150,6 +151,7 @@ struct tegra_csi {
>  	struct host1x_client client;
>  	void __iomem *iomem;
>  	struct clk_bulk_data *clks;
> +	struct regulator *vdd;
>  	const struct tegra_csi_soc *soc;
>  	const struct tegra_csi_ops *ops;
>  	const struct tegra_mipi_ops *mipi_ops;
> 

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





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

* Re: [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI
  2025-09-06 13:53 ` [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-09-22  4:29   ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 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 | 82 ++++++++++++---------
>  1 file changed, 46 insertions(+), 36 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> index 3dc26f5552eb..6e0b3b728623 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -29,13 +29,19 @@
>  #define TEGRA20_MIN_HEIGHT	32U
>  #define TEGRA20_MAX_HEIGHT	8190U
>  
> +/* Tegra20/Tegra30 has 2 outputs in VI */
> +enum tegra_vi_out {
> +	TEGRA_VI_OUT_1 = 0,
> +	TEGRA_VI_OUT_2 = 1,
> +};
> +
>  /* --------------------------------------------------------------------------
>   * 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)
> @@ -47,6 +53,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
> @@ -67,7 +74,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)
> @@ -81,6 +88,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)

I would perhaps add a note here that values below are only supported by OUT_2.

> +#define       VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT	(9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
>  

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

>  #define TEGRA_VI_VIP_H_ACTIVE				0x00a4
>  #define       VI_VIP_H_ACTIVE_PERIOD_SFT		16 /* active pixels/line, must be even */
> @@ -90,26 +98,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
> @@ -137,7 +145,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)
>  
> @@ -367,8 +375,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(TEGRA_VI_OUT_1),  base);
> +		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_1), base + chan->start_offset);
>  		break;
>  	}
>  }
> @@ -456,6 +464,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;
> +	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
>  	int main_output_format;
>  	int yuv_output_format;
>  
> @@ -473,33 +482,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)
> @@ -588,7 +597,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,
> -	.vi_max_channels = 1, /* parallel input (VIP) */
> +	.vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
>  	.vi_max_clk_hz = 150000000,
>  	.has_h_v_flip = true,
>  };
> @@ -608,6 +617,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;
> +	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
>  
>  	unsigned int main_input_format;
>  	unsigned int yuv_input_format;
> @@ -638,10 +648,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] 71+ messages in thread

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-06 13:53 ` [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
@ 2025-09-22  4:44   ` Mikko Perttunen
  2025-09-22  5:13     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  4: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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> 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 6e0b3b728623..781c4e8ec856 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -280,20 +280,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);

Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.

> +	pix->sizeimage = pix->bytesperline * pix->height;
>  }
>  
>  /*
> @@ -576,20 +564,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 = {
> 





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

* Re: [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
  2025-09-06 13:53 ` [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
@ 2025-09-22  4:54   ` Mikko Perttunen
  2025-09-22  4:58     ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  4:54 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> 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 e0da496bb50f..3c5bafebfcd8 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -590,7 +590,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
>  	.ops = &tegra20_vi_ops,
>  	.hw_revision = 1,
>  	.vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
> -	.vi_max_clk_hz = 150000000,
> +	.vi_max_clk_hz = 450000000,
>  	.has_h_v_flip = true,
>  };
>  
> 

Where does the 450MHz come from? Instead of hardcoding this value for each SoC, could we just clk_set_rate(ULONG_MAX) like e.g. the vic driver does, or does that get a too high rate?




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

* Re: [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
  2025-09-22  4:54   ` Mikko Perttunen
@ 2025-09-22  4:58     ` Svyatoslav Ryhel
  2025-09-22  6:23       ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  4:58 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 07:54 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > 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 e0da496bb50f..3c5bafebfcd8 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -590,7 +590,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> >       .ops = &tegra20_vi_ops,
> >       .hw_revision = 1,
> >       .vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
> > -     .vi_max_clk_hz = 150000000,
> > +     .vi_max_clk_hz = 450000000,
> >       .has_h_v_flip = true,
> >  };
> >
> >
>
> Where does the 450MHz come from? Instead of hardcoding this value for each SoC, could we just clk_set_rate(ULONG_MAX) like e.g. the vic driver does, or does that get a too high rate?
>

This values comes from downstream 3.1 tegra30 sources and setting it
higher breaks VI, I have tried. If it is set lower (150MHz as it was)
it breaks VI for cameras with resolution higher then 2MP

>

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

* Re: [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
  2025-09-06 13:53 ` [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-09-22  5:00   ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  5: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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 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 | 72 ++++++++++++++++++++-
>  1 file changed, 69 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> index 3c5bafebfcd8..f9adb0611638 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -187,6 +187,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:
> +		(*main_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
> +		break;
>  	}
>  }
>  
> @@ -221,6 +233,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;
>  	}
>  }
>  
> @@ -301,6 +325,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)
> @@ -366,6 +400,19 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
>  		tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(TEGRA_VI_OUT_1),  base);
>  		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_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(TEGRA_VI_OUT_2),  base);
> +		tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(TEGRA_VI_OUT_2), base + chan->start_offset);
> +		break;
>  	}
>  }
>  
> @@ -447,12 +494,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;
> -	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
> +	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> +					    data_type == TEGRA_IMAGE_DT_RAW10) ?
> +					    TEGRA_VI_OUT_2 : TEGRA_VI_OUT_1;
>  	int main_output_format;
>  	int yuv_output_format;
>  
> @@ -581,6 +631,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 = {
> @@ -607,10 +671,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;
> -	enum tegra_vi_out output_channel = TEGRA_VI_OUT_1;
> -
> +	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> +					    data_type == TEGRA_IMAGE_DT_RAW10) ?
> +					    TEGRA_VI_OUT_2 : TEGRA_VI_OUT_1;
>  	unsigned int main_input_format;
>  	unsigned int yuv_input_format;
>  
> 

Seems fine by me though I'm not familiar with the v4l2 specifics.

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





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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  4:44   ` Mikko Perttunen
@ 2025-09-22  5:13     ` Svyatoslav Ryhel
  2025-09-22  6:23       ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  5:13 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > 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 6e0b3b728623..781c4e8ec856 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -280,20 +280,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);
>
> Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
>

Downstream uses soc_mbus_bytes_per_line for this calculation which was
deprecated some time ago, here is a fragment

s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
{
 if (mf->fourcc == V4L2_PIX_FMT_JPEG)
 return 0;

 if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
 return width * mf->bits_per_sample / 8;

 switch (mf->packing) {
 case SOC_MBUS_PACKING_NONE:
  return width * mf->bits_per_sample / 8;
 case SOC_MBUS_PACKING_2X8_PADHI:
 case SOC_MBUS_PACKING_2X8_PADLO:
 case SOC_MBUS_PACKING_EXTEND16:
  return width * 2;
 case SOC_MBUS_PACKING_1_5X8:
  return width * 3 / 2;
 case SOC_MBUS_PACKING_VARIABLE:
  return 0;
 }
   return -EINVAL;
}

V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2

> > +     pix->sizeimage = pix->bytesperline * pix->height;
> >  }
> >
> >  /*
> > @@ -576,20 +564,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 = {
> >
>
>
>
>

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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-06 13:53 ` [PATCH v2 23/23] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
  2025-09-15  5:46   ` kernel test robot
@ 2025-09-22  5:15   ` Mikko Perttunen
  2025-09-22  5:19     ` Svyatoslav Ryhel
  2025-09-22  6:16     ` Svyatoslav Ryhel
  1 sibling, 2 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  5:15 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Svyatoslav Ryhel, Dmitry Osipenko,
	Jonas Schwöbel, Charan Pedumuru, Svyatoslav Ryhel
  Cc: dri-devel, devicetree, linux-tegra, linux-kernel, linux-media,
	linux-clk, linux-staging

On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> Add support for MIPI CSI device and calibration logic found in Tegra20 and
> Tegra30 SoC.

The patch is on the longer side. I'd add some more explanation in the commit message on the steps done in the patch.

> 
> 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 | 593 ++++++++++++++++++--
>  drivers/staging/media/tegra-video/vi.h      |   2 +
>  drivers/staging/media/tegra-video/video.c   |   6 +
>  4 files changed, 573 insertions(+), 40 deletions(-)
> 
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index 1677eb51ec21..d3f85f964ada 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
>  #include <linux/tegra-csi.h>
> +#include <linux/tegra-mipi-cal.h>
>  #include <linux/v4l2-mediabus.h>
>  
>  #include "vip.h"
> @@ -43,6 +51,9 @@ enum tegra_vi_out {
>  #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)
> @@ -88,6 +99,8 @@ enum tegra_vi_out {
>  #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
> @@ -152,8 +165,106 @@ enum tegra_vi_out {
>  #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_CONFIG			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)
> @@ -161,6 +272,35 @@ 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);
> +}
> +
> +static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
> +{
> +	writel(val, mipi->csi->iomem + addr);
> +}
> +
> +static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
> +{
> +	return readl(mipi->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.
> @@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
> @@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
> +					 struct tegra_csi_channel *csi_chan)
>  {
>  	int err;
>  
> -	chan->next_out_sp_idx++;
> -
>  	tegra20_channel_vi_buffer_setup(chan, buf);
>  
> -	tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> +	if (csi_chan) {
> +		u32 port = csi_chan->csi_port_nums[0] & 1;
> +
> +		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);
> +
> +		err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
> +					 TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> +		if (err) {
> +			if (err != -ERESTARTSYS)
> +				dev_err_ratelimited(&chan->video.dev,
> +						    "frame start syncpt timeout: %d\n", err);
> +		} else {
> +			chan->next_fs_sp_value++;
> +		}

Did you try the idea about resetting the HW and re-checking the syncpoint value to avoid race conditions?

> +
> +		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)
>  {
>  	struct tegra_vi_channel *chan = data;
>  	struct tegra_channel_buffer *buf;
> +	struct v4l2_subdev *csi_subdev = NULL;
> +	struct tegra_csi_channel *csi_chan = NULL;
>  	unsigned int retries = 0;
>  	int err = 0;
>  
> +	csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> +	if (csi_subdev)
> +		csi_chan = to_csi_chan(csi_subdev);
> +
>  	while (1) {
>  		/*
>  		 * Source is not streaming if error is non-zero.
> @@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
>  		list_del_init(&buf->queue);
>  		spin_unlock(&chan->start_lock);
>  
> -		err = tegra20_channel_capture_frame(chan, buf);
> +		err = tegra20_channel_capture_frame(chan, buf, csi_chan);
>  		if (!err) {
>  			retries = 0;
>  			continue;
> @@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
>  	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
>  					    data_type == TEGRA_IMAGE_DT_RAW10) ?
>  					    TEGRA_VI_OUT_2 : TEGRA_VI_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),
> @@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
>  	struct media_pipeline *pipe = &chan->video.pipe;
>  	int err;
>  
> +	chan->next_fs_sp_value = 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);
> +
>  	chan->sequence = 0;
>  
>  	chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> @@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
>  	.has_h_v_flip = true,
>  };
>  
> +/* --------------------------------------------------------------------------
> + * MIPI Calibration
> + */
> +static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
> +{
> +	struct tegra_csi *csi = mipi->csi;
> +	unsigned int port = mipi->pads;
> +	u32 value;
> +	int ret;
> +
> +	guard(mutex)(&csi->mipi_lock);
> +
> +	ret = pm_runtime_resume_and_get(csi->dev);
> +	if (ret < 0) {
> +		dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
> +		return ret;
> +	}
> +
> +	tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
> +			   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)
> +		value |= CSI_CIL_MIPI_CAL_SEL_B;
> +
> +	tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> +
> +	tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> +
> +	return 0;
> +}
> +
> +static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
> +{
> +	struct tegra_csi *csi = mipi->csi;
> +	void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> +	unsigned int port = mipi->pads;
> +	u32 value, pp, cil;
> +	int ret;
> +
> +	/* This part is only for CSI */
> +	if (port > PORT_B) {
> +		pm_runtime_put(csi->dev);
> +
> +		return 0;
> +	}
> +
> +	guard(mutex)(&csi->mipi_lock);
> +
> +	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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> +	cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
> +	if (pp | cil) {
> +		dev_warn(csi->dev, "Calibration status not been cleared!\n");
> +		ret = -EINVAL;
> +		goto exit;
> +	}
> +
> +exit:
> +	tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
> +
> +	/* un-select to avoid interference with DSI */
> +	tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
> +
> +	pm_runtime_put(csi->dev);
> +
> +	return ret;
> +}
> +
> +static const struct tegra_mipi_ops tegra20_mipi_ops = {
> +	.tegra_mipi_start_calibration = tegra20_start_pad_calibration,
> +	.tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
> +};

This patch is very long, maybe split the MIPI calibration into a separate patch to make it easier to read.

> +
> +/* --------------------------------------------------------------------------
> + * 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;
> +	enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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 */

These comments don't add much.

Thanks,
Mikko

> +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[] = {
> +	NULL,
> +};
> +
> +/* Tegra20 CSI SoC data */
> +const struct tegra_csi_soc tegra20_csi_soc = {
> +	.ops = &tegra20_csi_ops,
> +	.mipi_ops = &tegra20_mipi_ops,
> +	.csi_max_channels = 2, /* CSI-A and CSI-B */
> +	.clk_names = tegra20_csi_clks,
> +	.num_clks = ARRAY_SIZE(tegra20_csi_clks),
> +};
> +
> +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,
> +	.mipi_ops = &tegra20_mipi_ops,
> +	.csi_max_channels = 2, /* CSI-A and CSI-B */
> +	.clk_names = tegra30_csi_clks,
> +	.num_clks = ARRAY_SIZE(tegra30_csi_clks),
> +};
> +
>  /* --------------------------------------------------------------------------
>   * VIP
>   */
> @@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
>  	enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
>  					    data_type == TEGRA_IMAGE_DT_RAW10) ?
>  					    TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -124,6 +124,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
> @@ -188,6 +189,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_value;
>  
>  	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 6fe8d5301b9c..9f2bddc460bf 100644
> --- a/drivers/staging/media/tegra-video/video.c
> +++ b/drivers/staging/media/tegra-video/video.c
> @@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
>  	{ .compatible = "nvidia,tegra20-vip", },
>  	{ .compatible = "nvidia,tegra20-vi", },
>  #endif
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +	{ .compatible = "nvidia,tegra20-csi", },
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +	{ .compatible = "nvidia,tegra30-csi", },
> +#endif
>  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>  	{ .compatible = "nvidia,tegra210-csi", },
>  	{ .compatible = "nvidia,tegra210-vi", },
> 





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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-22  5:15   ` Mikko Perttunen
@ 2025-09-22  5:19     ` Svyatoslav Ryhel
  2025-09-22  5:38       ` Mikko Perttunen
  2025-09-22  6:16     ` Svyatoslav Ryhel
  1 sibling, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  5:19 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 08:16 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > Add support for MIPI CSI device and calibration logic found in Tegra20 and
> > Tegra30 SoC.
>
> The patch is on the longer side. I'd add some more explanation in the commit message on the steps done in the patch.
>
> >
> > 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 | 593 ++++++++++++++++++--
> >  drivers/staging/media/tegra-video/vi.h      |   2 +
> >  drivers/staging/media/tegra-video/video.c   |   6 +
> >  4 files changed, 573 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > index 1677eb51ec21..d3f85f964ada 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
> >  #include <linux/tegra-csi.h>
> > +#include <linux/tegra-mipi-cal.h>
> >  #include <linux/v4l2-mediabus.h>
> >
> >  #include "vip.h"
> > @@ -43,6 +51,9 @@ enum tegra_vi_out {
> >  #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)
> > @@ -88,6 +99,8 @@ enum tegra_vi_out {
> >  #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
> > @@ -152,8 +165,106 @@ enum tegra_vi_out {
> >  #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_CONFIG                        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)
> > @@ -161,6 +272,35 @@ 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);
> > +}
> > +
> > +static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
> > +{
> > +     writel(val, mipi->csi->iomem + addr);
> > +}
> > +
> > +static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
> > +{
> > +     return readl(mipi->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.
> > @@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
> > @@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
> > +                                      struct tegra_csi_channel *csi_chan)
> >  {
> >       int err;
> >
> > -     chan->next_out_sp_idx++;
> > -
> >       tegra20_channel_vi_buffer_setup(chan, buf);
> >
> > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > +     if (csi_chan) {
> > +             u32 port = csi_chan->csi_port_nums[0] & 1;
> > +
> > +             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);
> > +
> > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
> > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > +             if (err) {
> > +                     if (err != -ERESTARTSYS)
> > +                             dev_err_ratelimited(&chan->video.dev,
> > +                                                 "frame start syncpt timeout: %d\n", err);
> > +             } else {
> > +                     chan->next_fs_sp_value++;
> > +             }
>
> Did you try the idea about resetting the HW and re-checking the syncpoint value to avoid race conditions?
>

In previous iteration you said that passing sp_values +1 to
host1x_syncpt_wait should be enough, so I did not dig into this
further since your suggestion worked.

> > +
> > +             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)
> >  {
> >       struct tegra_vi_channel *chan = data;
> >       struct tegra_channel_buffer *buf;
> > +     struct v4l2_subdev *csi_subdev = NULL;
> > +     struct tegra_csi_channel *csi_chan = NULL;
> >       unsigned int retries = 0;
> >       int err = 0;
> >
> > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > +     if (csi_subdev)
> > +             csi_chan = to_csi_chan(csi_subdev);
> > +
> >       while (1) {
> >               /*
> >                * Source is not streaming if error is non-zero.
> > @@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
> >               list_del_init(&buf->queue);
> >               spin_unlock(&chan->start_lock);
> >
> > -             err = tegra20_channel_capture_frame(chan, buf);
> > +             err = tegra20_channel_capture_frame(chan, buf, csi_chan);
> >               if (!err) {
> >                       retries = 0;
> >                       continue;
> > @@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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),
> > @@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> >       struct media_pipeline *pipe = &chan->video.pipe;
> >       int err;
> >
> > +     chan->next_fs_sp_value = 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);
> > +
> >       chan->sequence = 0;
> >
> >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > @@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> >       .has_h_v_flip = true,
> >  };
> >
> > +/* --------------------------------------------------------------------------
> > + * MIPI Calibration
> > + */
> > +static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
> > +{
> > +     struct tegra_csi *csi = mipi->csi;
> > +     unsigned int port = mipi->pads;
> > +     u32 value;
> > +     int ret;
> > +
> > +     guard(mutex)(&csi->mipi_lock);
> > +
> > +     ret = pm_runtime_resume_and_get(csi->dev);
> > +     if (ret < 0) {
> > +             dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
> > +                        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)
> > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > +
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > +
> > +     tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > +
> > +     return 0;
> > +}
> > +
> > +static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
> > +{
> > +     struct tegra_csi *csi = mipi->csi;
> > +     void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > +     unsigned int port = mipi->pads;
> > +     u32 value, pp, cil;
> > +     int ret;
> > +
> > +     /* This part is only for CSI */
> > +     if (port > PORT_B) {
> > +             pm_runtime_put(csi->dev);
> > +
> > +             return 0;
> > +     }
> > +
> > +     guard(mutex)(&csi->mipi_lock);
> > +
> > +     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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > +     cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
> > +     if (pp | cil) {
> > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > +             ret = -EINVAL;
> > +             goto exit;
> > +     }
> > +
> > +exit:
> > +     tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > +
> > +     /* un-select to avoid interference with DSI */
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
> > +
> > +     pm_runtime_put(csi->dev);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct tegra_mipi_ops tegra20_mipi_ops = {
> > +     .tegra_mipi_start_calibration = tegra20_start_pad_calibration,
> > +     .tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
> > +};
>
> This patch is very long, maybe split the MIPI calibration into a separate patch to make it easier to read.
>
> > +
> > +/* --------------------------------------------------------------------------
> > + * 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;
> > +     enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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 */
>
> These comments don't add much.
>
> Thanks,
> Mikko
>
> > +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[] = {
> > +     NULL,
> > +};
> > +
> > +/* Tegra20 CSI SoC data */
> > +const struct tegra_csi_soc tegra20_csi_soc = {
> > +     .ops = &tegra20_csi_ops,
> > +     .mipi_ops = &tegra20_mipi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra20_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > +};
> > +
> > +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,
> > +     .mipi_ops = &tegra20_mipi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra30_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > +};
> > +
> >  /* --------------------------------------------------------------------------
> >   * VIP
> >   */
> > @@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
> > --- a/drivers/staging/media/tegra-video/vi.h
> > +++ b/drivers/staging/media/tegra-video/vi.h
> > @@ -124,6 +124,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
> > @@ -188,6 +189,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_value;
> >
> >       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 6fe8d5301b9c..9f2bddc460bf 100644
> > --- a/drivers/staging/media/tegra-video/video.c
> > +++ b/drivers/staging/media/tegra-video/video.c
> > @@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
> >       { .compatible = "nvidia,tegra20-vip", },
> >       { .compatible = "nvidia,tegra20-vi", },
> >  #endif
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +     { .compatible = "nvidia,tegra20-csi", },
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +     { .compatible = "nvidia,tegra30-csi", },
> > +#endif
> >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >       { .compatible = "nvidia,tegra210-csi", },
> >       { .compatible = "nvidia,tegra210-vi", },
> >
>
>
>
>

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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-22  5:19     ` Svyatoslav Ryhel
@ 2025-09-22  5:38       ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  5:38 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 2:19 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 08:16 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > Add support for MIPI CSI device and calibration logic found in Tegra20 and
> > > Tegra30 SoC.
> >
> > The patch is on the longer side. I'd add some more explanation in the commit message on the steps done in the patch.
> >
> > >
> > > 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 | 593 ++++++++++++++++++--
> > >  drivers/staging/media/tegra-video/vi.h      |   2 +
> > >  drivers/staging/media/tegra-video/video.c   |   6 +
> > >  4 files changed, 573 insertions(+), 40 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > index 1677eb51ec21..d3f85f964ada 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
> > >  #include <linux/tegra-csi.h>
> > > +#include <linux/tegra-mipi-cal.h>
> > >  #include <linux/v4l2-mediabus.h>
> > >
> > >  #include "vip.h"
> > > @@ -43,6 +51,9 @@ enum tegra_vi_out {
> > >  #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)
> > > @@ -88,6 +99,8 @@ enum tegra_vi_out {
> > >  #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
> > > @@ -152,8 +165,106 @@ enum tegra_vi_out {
> > >  #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_CONFIG                        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)
> > > @@ -161,6 +272,35 @@ 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);
> > > +}
> > > +
> > > +static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
> > > +{
> > > +     writel(val, mipi->csi->iomem + addr);
> > > +}
> > > +
> > > +static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
> > > +{
> > > +     return readl(mipi->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.
> > > @@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
> > > @@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
> > > +                                      struct tegra_csi_channel *csi_chan)
> > >  {
> > >       int err;
> > >
> > > -     chan->next_out_sp_idx++;
> > > -
> > >       tegra20_channel_vi_buffer_setup(chan, buf);
> > >
> > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > +     if (csi_chan) {
> > > +             u32 port = csi_chan->csi_port_nums[0] & 1;
> > > +
> > > +             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);
> > > +
> > > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
> > > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > +             if (err) {
> > > +                     if (err != -ERESTARTSYS)
> > > +                             dev_err_ratelimited(&chan->video.dev,
> > > +                                                 "frame start syncpt timeout: %d\n", err);
> > > +             } else {
> > > +                     chan->next_fs_sp_value++;
> > > +             }
> >
> > Did you try the idea about resetting the HW and re-checking the syncpoint value to avoid race conditions?
> >
> 
> In previous iteration you said that passing sp_values +1 to
> host1x_syncpt_wait should be enough, so I did not dig into this
> further since your suggestion worked.

Ah, I see. Doing this, there is still a race condition -- if the wait timeouts but the HW increments the syncpoint, next_fs_sp_value will be lagging the HW syncpoint value, so any subsequent captures will incorrectly fail.

The syncpoint wait below (mw_ack_sp) also needs the same treatment.

If we know the hardware is quiesced (not able to cause syncpoint increments) before triggering the operation that causes the syncpoint increment, and we don't need any pipelining (i.e. multiple operations queued for the syncpoint), it's also possible to read the value of the syncpoint before triggering the operation.

From a cleanliness point of view, I think it's better to immediately quiesce the hardware when an error happens, and do cleanup including reading back the syncpoint value from the hardware.

> 
> > > +
> > > +             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)
> > >  {
> > >       struct tegra_vi_channel *chan = data;
> > >       struct tegra_channel_buffer *buf;
> > > +     struct v4l2_subdev *csi_subdev = NULL;
> > > +     struct tegra_csi_channel *csi_chan = NULL;
> > >       unsigned int retries = 0;
> > >       int err = 0;
> > >
> > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > +     if (csi_subdev)
> > > +             csi_chan = to_csi_chan(csi_subdev);
> > > +
> > >       while (1) {
> > >               /*
> > >                * Source is not streaming if error is non-zero.
> > > @@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
> > >               list_del_init(&buf->queue);
> > >               spin_unlock(&chan->start_lock);
> > >
> > > -             err = tegra20_channel_capture_frame(chan, buf);
> > > +             err = tegra20_channel_capture_frame(chan, buf, csi_chan);
> > >               if (!err) {
> > >                       retries = 0;
> > >                       continue;
> > > @@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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),
> > > @@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > >       struct media_pipeline *pipe = &chan->video.pipe;
> > >       int err;
> > >
> > > +     chan->next_fs_sp_value = 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);
> > > +
> > >       chan->sequence = 0;
> > >
> > >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > @@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > >       .has_h_v_flip = true,
> > >  };
> > >
> > > +/* --------------------------------------------------------------------------
> > > + * MIPI Calibration
> > > + */
> > > +static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
> > > +{
> > > +     struct tegra_csi *csi = mipi->csi;
> > > +     unsigned int port = mipi->pads;
> > > +     u32 value;
> > > +     int ret;
> > > +
> > > +     guard(mutex)(&csi->mipi_lock);
> > > +
> > > +     ret = pm_runtime_resume_and_get(csi->dev);
> > > +     if (ret < 0) {
> > > +             dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
> > > +             return ret;
> > > +     }
> > > +
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
> > > +                        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)
> > > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > +
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > +
> > > +     tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
> > > +{
> > > +     struct tegra_csi *csi = mipi->csi;
> > > +     void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > +     unsigned int port = mipi->pads;
> > > +     u32 value, pp, cil;
> > > +     int ret;
> > > +
> > > +     /* This part is only for CSI */
> > > +     if (port > PORT_B) {
> > > +             pm_runtime_put(csi->dev);
> > > +
> > > +             return 0;
> > > +     }
> > > +
> > > +     guard(mutex)(&csi->mipi_lock);
> > > +
> > > +     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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > +     cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
> > > +     if (pp | cil) {
> > > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > +             ret = -EINVAL;
> > > +             goto exit;
> > > +     }
> > > +
> > > +exit:
> > > +     tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > +
> > > +     /* un-select to avoid interference with DSI */
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
> > > +
> > > +     pm_runtime_put(csi->dev);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static const struct tegra_mipi_ops tegra20_mipi_ops = {
> > > +     .tegra_mipi_start_calibration = tegra20_start_pad_calibration,
> > > +     .tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
> > > +};
> >
> > This patch is very long, maybe split the MIPI calibration into a separate patch to make it easier to read.
> >
> > > +
> > > +/* --------------------------------------------------------------------------
> > > + * 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;
> > > +     enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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 */
> >
> > These comments don't add much.
> >
> > Thanks,
> > Mikko
> >
> > > +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[] = {
> > > +     NULL,
> > > +};
> > > +
> > > +/* Tegra20 CSI SoC data */
> > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > +     .ops = &tegra20_csi_ops,
> > > +     .mipi_ops = &tegra20_mipi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra20_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > +};
> > > +
> > > +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,
> > > +     .mipi_ops = &tegra20_mipi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra30_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > +};
> > > +
> > >  /* --------------------------------------------------------------------------
> > >   * VIP
> > >   */
> > > @@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
> > > --- a/drivers/staging/media/tegra-video/vi.h
> > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > @@ -124,6 +124,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
> > > @@ -188,6 +189,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_value;
> > >
> > >       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 6fe8d5301b9c..9f2bddc460bf 100644
> > > --- a/drivers/staging/media/tegra-video/video.c
> > > +++ b/drivers/staging/media/tegra-video/video.c
> > > @@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
> > >       { .compatible = "nvidia,tegra20-vip", },
> > >       { .compatible = "nvidia,tegra20-vi", },
> > >  #endif
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +     { .compatible = "nvidia,tegra20-csi", },
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +     { .compatible = "nvidia,tegra30-csi", },
> > > +#endif
> > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > >       { .compatible = "nvidia,tegra210-csi", },
> > >       { .compatible = "nvidia,tegra210-vi", },
> > >
> >
> >
> >
> >





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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-22  5:15   ` Mikko Perttunen
  2025-09-22  5:19     ` Svyatoslav Ryhel
@ 2025-09-22  6:16     ` Svyatoslav Ryhel
  2025-09-22  6:36       ` Mikko Perttunen
  1 sibling, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  6:16 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 08:16 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > Add support for MIPI CSI device and calibration logic found in Tegra20 and
> > Tegra30 SoC.
>
> The patch is on the longer side. I'd add some more explanation in the commit message on the steps done in the patch.
>

Tbh, I am not sure that more to add, there was only one step -
transfer downstream code into existing kernel v4l2 framework. This is
basically creation of a new driver there were no multi-step setup or
smth like that. All steps to prepare this were made separate commits.

> >
> > 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 | 593 ++++++++++++++++++--
> >  drivers/staging/media/tegra-video/vi.h      |   2 +
> >  drivers/staging/media/tegra-video/video.c   |   6 +
> >  4 files changed, 573 insertions(+), 40 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > index 1677eb51ec21..d3f85f964ada 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
> >  #include <linux/tegra-csi.h>
> > +#include <linux/tegra-mipi-cal.h>
> >  #include <linux/v4l2-mediabus.h>
> >
> >  #include "vip.h"
> > @@ -43,6 +51,9 @@ enum tegra_vi_out {
> >  #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)
> > @@ -88,6 +99,8 @@ enum tegra_vi_out {
> >  #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
> > @@ -152,8 +165,106 @@ enum tegra_vi_out {
> >  #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_CONFIG                        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)
> > @@ -161,6 +272,35 @@ 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);
> > +}
> > +
> > +static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
> > +{
> > +     writel(val, mipi->csi->iomem + addr);
> > +}
> > +
> > +static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
> > +{
> > +     return readl(mipi->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.
> > @@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
> > @@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
> > +                                      struct tegra_csi_channel *csi_chan)
> >  {
> >       int err;
> >
> > -     chan->next_out_sp_idx++;
> > -
> >       tegra20_channel_vi_buffer_setup(chan, buf);
> >
> > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > +     if (csi_chan) {
> > +             u32 port = csi_chan->csi_port_nums[0] & 1;
> > +
> > +             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);
> > +
> > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
> > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > +             if (err) {
> > +                     if (err != -ERESTARTSYS)
> > +                             dev_err_ratelimited(&chan->video.dev,
> > +                                                 "frame start syncpt timeout: %d\n", err);
> > +             } else {
> > +                     chan->next_fs_sp_value++;
> > +             }
>
> Did you try the idea about resetting the HW and re-checking the syncpoint value to avoid race conditions?
>
> > +
> > +             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)
> >  {
> >       struct tegra_vi_channel *chan = data;
> >       struct tegra_channel_buffer *buf;
> > +     struct v4l2_subdev *csi_subdev = NULL;
> > +     struct tegra_csi_channel *csi_chan = NULL;
> >       unsigned int retries = 0;
> >       int err = 0;
> >
> > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > +     if (csi_subdev)
> > +             csi_chan = to_csi_chan(csi_subdev);
> > +
> >       while (1) {
> >               /*
> >                * Source is not streaming if error is non-zero.
> > @@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
> >               list_del_init(&buf->queue);
> >               spin_unlock(&chan->start_lock);
> >
> > -             err = tegra20_channel_capture_frame(chan, buf);
> > +             err = tegra20_channel_capture_frame(chan, buf, csi_chan);
> >               if (!err) {
> >                       retries = 0;
> >                       continue;
> > @@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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),
> > @@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> >       struct media_pipeline *pipe = &chan->video.pipe;
> >       int err;
> >
> > +     chan->next_fs_sp_value = 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);
> > +
> >       chan->sequence = 0;
> >
> >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > @@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> >       .has_h_v_flip = true,
> >  };
> >
> > +/* --------------------------------------------------------------------------
> > + * MIPI Calibration
> > + */
> > +static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
> > +{
> > +     struct tegra_csi *csi = mipi->csi;
> > +     unsigned int port = mipi->pads;
> > +     u32 value;
> > +     int ret;
> > +
> > +     guard(mutex)(&csi->mipi_lock);
> > +
> > +     ret = pm_runtime_resume_and_get(csi->dev);
> > +     if (ret < 0) {
> > +             dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
> > +             return ret;
> > +     }
> > +
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
> > +                        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)
> > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > +
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > +
> > +     tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > +
> > +     return 0;
> > +}
> > +
> > +static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
> > +{
> > +     struct tegra_csi *csi = mipi->csi;
> > +     void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > +     unsigned int port = mipi->pads;
> > +     u32 value, pp, cil;
> > +     int ret;
> > +
> > +     /* This part is only for CSI */
> > +     if (port > PORT_B) {
> > +             pm_runtime_put(csi->dev);
> > +
> > +             return 0;
> > +     }
> > +
> > +     guard(mutex)(&csi->mipi_lock);
> > +
> > +     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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > +     cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
> > +     if (pp | cil) {
> > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > +             ret = -EINVAL;
> > +             goto exit;
> > +     }
> > +
> > +exit:
> > +     tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > +
> > +     /* un-select to avoid interference with DSI */
> > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
> > +
> > +     pm_runtime_put(csi->dev);
> > +
> > +     return ret;
> > +}
> > +
> > +static const struct tegra_mipi_ops tegra20_mipi_ops = {
> > +     .tegra_mipi_start_calibration = tegra20_start_pad_calibration,
> > +     .tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
> > +};
>
> This patch is very long, maybe split the MIPI calibration into a separate patch to make it easier to read.
>

I would love to, but MIPI calibration is integrated part of CSI. I
cannot add it before CSI support since CSI soc structure includes MIPI
operations, I might try adding it after but it will look irrational
because CSI is not gonna work without MIPI calibration.

> > +
> > +/* --------------------------------------------------------------------------
> > + * 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;
> > +     enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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 */
>
> These comments don't add much.
>
> Thanks,
> Mikko
>
> > +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[] = {
> > +     NULL,
> > +};
> > +
> > +/* Tegra20 CSI SoC data */
> > +const struct tegra_csi_soc tegra20_csi_soc = {
> > +     .ops = &tegra20_csi_ops,
> > +     .mipi_ops = &tegra20_mipi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra20_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > +};
> > +
> > +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,
> > +     .mipi_ops = &tegra20_mipi_ops,
> > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > +     .clk_names = tegra30_csi_clks,
> > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > +};
> > +
> >  /* --------------------------------------------------------------------------
> >   * VIP
> >   */
> > @@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
> > --- a/drivers/staging/media/tegra-video/vi.h
> > +++ b/drivers/staging/media/tegra-video/vi.h
> > @@ -124,6 +124,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
> > @@ -188,6 +189,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_value;
> >
> >       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 6fe8d5301b9c..9f2bddc460bf 100644
> > --- a/drivers/staging/media/tegra-video/video.c
> > +++ b/drivers/staging/media/tegra-video/video.c
> > @@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
> >       { .compatible = "nvidia,tegra20-vip", },
> >       { .compatible = "nvidia,tegra20-vi", },
> >  #endif
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +     { .compatible = "nvidia,tegra20-csi", },
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +     { .compatible = "nvidia,tegra30-csi", },
> > +#endif
> >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >       { .compatible = "nvidia,tegra210-csi", },
> >       { .compatible = "nvidia,tegra210-vi", },
> >
>
>
>
>

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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  5:13     ` Svyatoslav Ryhel
@ 2025-09-22  6:23       ` Mikko Perttunen
  2025-09-22  6:30         ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  6:23 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > 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 6e0b3b728623..781c4e8ec856 100644
> > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > @@ -280,20 +280,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);
> >
> > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> >
> 
> Downstream uses soc_mbus_bytes_per_line for this calculation which was
> deprecated some time ago, here is a fragment
> 
> s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> {
>  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
>  return 0;
> 
>  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
>  return width * mf->bits_per_sample / 8;
> 
>  switch (mf->packing) {
>  case SOC_MBUS_PACKING_NONE:
>   return width * mf->bits_per_sample / 8;
>  case SOC_MBUS_PACKING_2X8_PADHI:
>  case SOC_MBUS_PACKING_2X8_PADLO:
>  case SOC_MBUS_PACKING_EXTEND16:
>   return width * 2;
>  case SOC_MBUS_PACKING_1_5X8:
>   return width * 3 / 2;
>  case SOC_MBUS_PACKING_VARIABLE:
>   return 0;
>  }
>    return -EINVAL;
> }
> 
> V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2

Googling this brings up the entry

{
	.code = V4L2_MBUS_FMT_YUYV8_1_5X8,
	.fmt = {
		.fourcc			= V4L2_PIX_FMT_YUV420,
		.name			= "YUYV 4:2:0",
		.bits_per_sample		= 8,
		.packing			= SOC_MBUS_PACKING_1_5X8,
		.order			= SOC_MBUS_ORDER_LE,
		.layout			= SOC_MBUS_LAYOUT_PACKED,
	},
}

which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED

/**
 * enum soc_mbus_layout - planes layout in memory
 * @SOC_MBUS_LAYOUT_PACKED:		color components packed
 * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:	YUV components stored in 3 planes (4:2:2)
 * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:	YUV components stored in a luma and a
 *					chroma plane (C plane is half the size
 *					of Y plane)
 * @SOC_MBUS_LAYOUT_PLANAR_Y_C:		YUV components stored in a luma and a
 *					chroma plane (C plane is the same size
 *					as Y plane)
 */
enum soc_mbus_layout {
	SOC_MBUS_LAYOUT_PACKED = 0,
	SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
	SOC_MBUS_LAYOUT_PLANAR_2Y_C,
	SOC_MBUS_LAYOUT_PLANAR_Y_C,
};

i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.

> 
> > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > >  }
> > >
> > >  /*
> > > @@ -576,20 +564,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 = {
> > >
> >
> >
> >
> >





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

* Re: [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
  2025-09-22  4:58     ` Svyatoslav Ryhel
@ 2025-09-22  6:23       ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  6:23 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 1:58 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 07:54 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > 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 e0da496bb50f..3c5bafebfcd8 100644
> > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > @@ -590,7 +590,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > >       .ops = &tegra20_vi_ops,
> > >       .hw_revision = 1,
> > >       .vi_max_channels = 2, /* TEGRA_VI_OUT_1 and TEGRA_VI_OUT_2 */
> > > -     .vi_max_clk_hz = 150000000,
> > > +     .vi_max_clk_hz = 450000000,
> > >       .has_h_v_flip = true,
> > >  };
> > >
> > >
> >
> > Where does the 450MHz come from? Instead of hardcoding this value for each SoC, could we just clk_set_rate(ULONG_MAX) like e.g. the vic driver does, or does that get a too high rate?
> >
> 
> This values comes from downstream 3.1 tegra30 sources and setting it
> higher breaks VI, I have tried. If it is set lower (150MHz as it was)
> it breaks VI for cameras with resolution higher then 2MP
> 
> >

Ok, very good.

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




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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  6:23       ` Mikko Perttunen
@ 2025-09-22  6:30         ` Svyatoslav Ryhel
  2025-09-22  7:27           ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  6:30 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > @@ -280,20 +280,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);
> > >
> > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > >
> >
> > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > deprecated some time ago, here is a fragment
> >
> > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > {
> >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> >  return 0;
> >
> >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> >  return width * mf->bits_per_sample / 8;
> >
> >  switch (mf->packing) {
> >  case SOC_MBUS_PACKING_NONE:
> >   return width * mf->bits_per_sample / 8;
> >  case SOC_MBUS_PACKING_2X8_PADHI:
> >  case SOC_MBUS_PACKING_2X8_PADLO:
> >  case SOC_MBUS_PACKING_EXTEND16:
> >   return width * 2;
> >  case SOC_MBUS_PACKING_1_5X8:
> >   return width * 3 / 2;
> >  case SOC_MBUS_PACKING_VARIABLE:
> >   return 0;
> >  }
> >    return -EINVAL;
> > }
> >
> > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
>
> Googling this brings up the entry
>
> {
>         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
>         .fmt = {
>                 .fourcc                 = V4L2_PIX_FMT_YUV420,
>                 .name                   = "YUYV 4:2:0",
>                 .bits_per_sample                = 8,
>                 .packing                        = SOC_MBUS_PACKING_1_5X8,
>                 .order                  = SOC_MBUS_ORDER_LE,
>                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
>         },
> }
>
> which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
>
> /**
>  * enum soc_mbus_layout - planes layout in memory
>  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
>  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
>  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
>  *                                      chroma plane (C plane is half the size
>  *                                      of Y plane)
>  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
>  *                                      chroma plane (C plane is the same size
>  *                                      as Y plane)
>  */
> enum soc_mbus_layout {
>         SOC_MBUS_LAYOUT_PACKED = 0,
>         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
>         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
>         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> };
>
> i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
>

I did not invent this, I have just simplified this calculation from
downstream, output values remain same. I have no cameras which can
output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
this works either. Other YUV and RAW formats were tested on real HW
and work perfectly fine.

> >
> > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > >  }
> > > >
> > > >  /*
> > > > @@ -576,20 +564,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 = {
> > > >
> > >
> > >
> > >
> > >
>
>
>
>

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

* Re: [PATCH v2 23/23] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
  2025-09-22  6:16     ` Svyatoslav Ryhel
@ 2025-09-22  6:36       ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  6:36 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 3:16 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 08:16 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > Add support for MIPI CSI device and calibration logic found in Tegra20 and
> > > Tegra30 SoC.
> >
> > The patch is on the longer side. I'd add some more explanation in the commit message on the steps done in the patch.
> >
> 
> Tbh, I am not sure that more to add, there was only one step -
> transfer downstream code into existing kernel v4l2 framework. This is
> basically creation of a new driver there were no multi-step setup or
> smth like that. All steps to prepare this were made separate commits.

I would add a brief note about things that are different from the existing VIP code, e.g. that we need to allocate another syncpoint for synchronizing the CSI operations. Also if you implement the syncpoint wait race condition fix, that would be something to mention (since it affects existing code -- unless it's done as a separate patch). Regarding the MIPI calibration code, I would note that we register as a MIPI calibration provider since DSI calibration is also done through this code. It's then a bit easier to understand those points as they come up when reading the patch.

> 
> > >
> > > 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 | 593 ++++++++++++++++++--
> > >  drivers/staging/media/tegra-video/vi.h      |   2 +
> > >  drivers/staging/media/tegra-video/video.c   |   6 +
> > >  4 files changed, 573 insertions(+), 40 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > index 1677eb51ec21..d3f85f964ada 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -863,11 +863,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 20cdcc4e01aa..f81c40b6e709 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,11 +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/pm_runtime.h>
> > >  #include <linux/tegra-csi.h>
> > > +#include <linux/tegra-mipi-cal.h>
> > >  #include <linux/v4l2-mediabus.h>
> > >
> > >  #include "vip.h"
> > > @@ -43,6 +51,9 @@ enum tegra_vi_out {
> > >  #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)
> > > @@ -88,6 +99,8 @@ enum tegra_vi_out {
> > >  #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
> > > @@ -152,8 +165,106 @@ enum tegra_vi_out {
> > >  #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_CONFIG                        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)
> > > @@ -161,6 +272,35 @@ 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);
> > > +}
> > > +
> > > +static void tegra20_mipi_write(struct tegra_mipi_device *mipi, unsigned int addr, u32 val)
> > > +{
> > > +     writel(val, mipi->csi->iomem + addr);
> > > +}
> > > +
> > > +static int __maybe_unused tegra20_mipi_read(struct tegra_mipi_device *mipi, unsigned int addr)
> > > +{
> > > +     return readl(mipi->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.
> > > @@ -283,20 +423,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, -EBUSY, "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, -EBUSY, "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)
> > > @@ -417,41 +564,68 @@ 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 tegra_channel_buffer *buf,
> > > +                                      struct tegra_csi_channel *csi_chan)
> > >  {
> > >       int err;
> > >
> > > -     chan->next_out_sp_idx++;
> > > -
> > >       tegra20_channel_vi_buffer_setup(chan, buf);
> > >
> > > -     tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > +     if (csi_chan) {
> > > +             u32 port = csi_chan->csi_port_nums[0] & 1;
> > > +
> > > +             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);
> > > +
> > > +             err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_value + 1,
> > > +                                      TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > +             if (err) {
> > > +                     if (err != -ERESTARTSYS)
> > > +                             dev_err_ratelimited(&chan->video.dev,
> > > +                                                 "frame start syncpt timeout: %d\n", err);
> > > +             } else {
> > > +                     chan->next_fs_sp_value++;
> > > +             }
> >
> > Did you try the idea about resetting the HW and re-checking the syncpoint value to avoid race conditions?
> >
> > > +
> > > +             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)
> > >  {
> > >       struct tegra_vi_channel *chan = data;
> > >       struct tegra_channel_buffer *buf;
> > > +     struct v4l2_subdev *csi_subdev = NULL;
> > > +     struct tegra_csi_channel *csi_chan = NULL;
> > >       unsigned int retries = 0;
> > >       int err = 0;
> > >
> > > +     csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > +     if (csi_subdev)
> > > +             csi_chan = to_csi_chan(csi_subdev);
> > > +
> > >       while (1) {
> > >               /*
> > >                * Source is not streaming if error is non-zero.
> > > @@ -476,7 +650,7 @@ static int tegra20_chan_capture_kthread_start(void *data)
> > >               list_del_init(&buf->queue);
> > >               spin_unlock(&chan->start_lock);
> > >
> > > -             err = tegra20_channel_capture_frame(chan, buf);
> > > +             err = tegra20_channel_capture_frame(chan, buf, csi_chan);
> > >               if (!err) {
> > >                       retries = 0;
> > >                       continue;
> > > @@ -503,28 +677,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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),
> > > @@ -555,18 +707,31 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > >       struct media_pipeline *pipe = &chan->video.pipe;
> > >       int err;
> > >
> > > +     chan->next_fs_sp_value = 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);
> > > +
> > >       chan->sequence = 0;
> > >
> > >       chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > @@ -658,6 +823,348 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > >       .has_h_v_flip = true,
> > >  };
> > >
> > > +/* --------------------------------------------------------------------------
> > > + * MIPI Calibration
> > > + */
> > > +static int tegra20_start_pad_calibration(struct tegra_mipi_device *mipi)
> > > +{
> > > +     struct tegra_csi *csi = mipi->csi;
> > > +     unsigned int port = mipi->pads;
> > > +     u32 value;
> > > +     int ret;
> > > +
> > > +     guard(mutex)(&csi->mipi_lock);
> > > +
> > > +     ret = pm_runtime_resume_and_get(csi->dev);
> > > +     if (ret < 0) {
> > > +             dev_err(csi->dev, "failed to get runtime PM: %d\n", ret);
> > > +             return ret;
> > > +     }
> > > +
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_MIPIBIAS_PAD_CONFIG,
> > > +                        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)
> > > +             value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > +
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > +
> > > +     tegra20_mipi_write(mipi, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > +
> > > +     return 0;
> > > +}
> > > +
> > > +static int tegra20_finish_pad_calibration(struct tegra_mipi_device *mipi)
> > > +{
> > > +     struct tegra_csi *csi = mipi->csi;
> > > +     void __iomem *cil_status_reg = csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > +     unsigned int port = mipi->pads;
> > > +     u32 value, pp, cil;
> > > +     int ret;
> > > +
> > > +     /* This part is only for CSI */
> > > +     if (port > PORT_B) {
> > > +             pm_runtime_put(csi->dev);
> > > +
> > > +             return 0;
> > > +     }
> > > +
> > > +     guard(mutex)(&csi->mipi_lock);
> > > +
> > > +     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_mipi_write(mipi, 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_mipi_read(mipi, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > +     cil = tegra20_mipi_read(mipi, TEGRA_CSI_CSI_CIL_STATUS);
> > > +     if (pp | cil) {
> > > +             dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > +             ret = -EINVAL;
> > > +             goto exit;
> > > +     }
> > > +
> > > +exit:
> > > +     tegra20_mipi_write(mipi, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > +
> > > +     /* un-select to avoid interference with DSI */
> > > +     tegra20_mipi_write(mipi, 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_mipi_write(mipi, 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));
> > > +
> > > +     pm_runtime_put(csi->dev);
> > > +
> > > +     return ret;
> > > +}
> > > +
> > > +static const struct tegra_mipi_ops tegra20_mipi_ops = {
> > > +     .tegra_mipi_start_calibration = tegra20_start_pad_calibration,
> > > +     .tegra_mipi_finish_calibration = tegra20_finish_pad_calibration,
> > > +};
> >
> > This patch is very long, maybe split the MIPI calibration into a separate patch to make it easier to read.
> >
> 
> I would love to, but MIPI calibration is integrated part of CSI. I
> cannot add it before CSI support since CSI soc structure includes MIPI
> operations, I might try adding it after but it will look irrational
> because CSI is not gonna work without MIPI calibration.

Ok, no problem then.

> 
> > > +
> > > +/* --------------------------------------------------------------------------
> > > + * 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;
> > > +     enum tegra_vi_out output_channel = TEGRA_VI_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 = TEGRA_VI_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 */
> >
> > These comments don't add much.
> >
> > Thanks,
> > Mikko
> >
> > > +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[] = {
> > > +     NULL,
> > > +};
> > > +
> > > +/* Tegra20 CSI SoC data */
> > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > +     .ops = &tegra20_csi_ops,
> > > +     .mipi_ops = &tegra20_mipi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra20_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > +};
> > > +
> > > +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,
> > > +     .mipi_ops = &tegra20_mipi_ops,
> > > +     .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > +     .clk_names = tegra30_csi_clks,
> > > +     .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > +};
> > > +
> > >  /* --------------------------------------------------------------------------
> > >   * VIP
> > >   */
> > > @@ -677,10 +1184,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > >       enum tegra_vi_out output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > >                                           data_type == TEGRA_IMAGE_DT_RAW10) ?
> > >                                           TEGRA_VI_OUT_2 : TEGRA_VI_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 +1221,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 367667adf745..648dde82a14b 100644
> > > --- a/drivers/staging/media/tegra-video/vi.h
> > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > @@ -124,6 +124,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
> > > @@ -188,6 +189,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_value;
> > >
> > >       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 6fe8d5301b9c..9f2bddc460bf 100644
> > > --- a/drivers/staging/media/tegra-video/video.c
> > > +++ b/drivers/staging/media/tegra-video/video.c
> > > @@ -127,6 +127,12 @@ static const struct of_device_id host1x_video_subdevs[] = {
> > >       { .compatible = "nvidia,tegra20-vip", },
> > >       { .compatible = "nvidia,tegra20-vi", },
> > >  #endif
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +     { .compatible = "nvidia,tegra20-csi", },
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +     { .compatible = "nvidia,tegra30-csi", },
> > > +#endif
> > >  #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > >       { .compatible = "nvidia,tegra210-csi", },
> > >       { .compatible = "nvidia,tegra210-vi", },
> > >
> >
> >
> >
> >





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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  6:30         ` Svyatoslav Ryhel
@ 2025-09-22  7:27           ` Mikko Perttunen
  2025-09-22  7:36             ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-22  7:27 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > >
> > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > @@ -280,20 +280,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);
> > > >
> > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > >
> > >
> > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > deprecated some time ago, here is a fragment
> > >
> > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > {
> > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > >  return 0;
> > >
> > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > >  return width * mf->bits_per_sample / 8;
> > >
> > >  switch (mf->packing) {
> > >  case SOC_MBUS_PACKING_NONE:
> > >   return width * mf->bits_per_sample / 8;
> > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > >  case SOC_MBUS_PACKING_EXTEND16:
> > >   return width * 2;
> > >  case SOC_MBUS_PACKING_1_5X8:
> > >   return width * 3 / 2;
> > >  case SOC_MBUS_PACKING_VARIABLE:
> > >   return 0;
> > >  }
> > >    return -EINVAL;
> > > }
> > >
> > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> >
> > Googling this brings up the entry
> >
> > {
> >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> >         .fmt = {
> >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> >                 .name                   = "YUYV 4:2:0",
> >                 .bits_per_sample                = 8,
> >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> >                 .order                  = SOC_MBUS_ORDER_LE,
> >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> >         },
> > }
> >
> > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> >
> > /**
> >  * enum soc_mbus_layout - planes layout in memory
> >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> >  *                                      chroma plane (C plane is half the size
> >  *                                      of Y plane)
> >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> >  *                                      chroma plane (C plane is the same size
> >  *                                      as Y plane)
> >  */
> > enum soc_mbus_layout {
> >         SOC_MBUS_LAYOUT_PACKED = 0,
> >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > };
> >
> > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> >
> 
> I did not invent this, I have just simplified this calculation from
> downstream, output values remain same. I have no cameras which can
> output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> this works either. Other YUV and RAW formats were tested on real HW
> and work perfectly fine.

My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?

It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.

> 
> > >
> > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > >  }
> > > > >
> > > > >  /*
> > > > > @@ -576,20 +564,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 = {
> > > > >
> > > >
> > > >
> > > >
> > > >
> >
> >
> >
> >





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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  7:27           ` Mikko Perttunen
@ 2025-09-22  7:36             ` Svyatoslav Ryhel
  2025-09-23  6:03               ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-22  7:36 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > >
> > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > @@ -280,20 +280,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);
> > > > >
> > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > >
> > > >
> > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > deprecated some time ago, here is a fragment
> > > >
> > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > {
> > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > >  return 0;
> > > >
> > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > >  return width * mf->bits_per_sample / 8;
> > > >
> > > >  switch (mf->packing) {
> > > >  case SOC_MBUS_PACKING_NONE:
> > > >   return width * mf->bits_per_sample / 8;
> > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > >   return width * 2;
> > > >  case SOC_MBUS_PACKING_1_5X8:
> > > >   return width * 3 / 2;
> > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > >   return 0;
> > > >  }
> > > >    return -EINVAL;
> > > > }
> > > >
> > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > >
> > > Googling this brings up the entry
> > >
> > > {
> > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > >         .fmt = {
> > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > >                 .name                   = "YUYV 4:2:0",
> > >                 .bits_per_sample                = 8,
> > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > >                 .order                  = SOC_MBUS_ORDER_LE,
> > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > >         },
> > > }
> > >
> > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > >
> > > /**
> > >  * enum soc_mbus_layout - planes layout in memory
> > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > >  *                                      chroma plane (C plane is half the size
> > >  *                                      of Y plane)
> > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > >  *                                      chroma plane (C plane is the same size
> > >  *                                      as Y plane)
> > >  */
> > > enum soc_mbus_layout {
> > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > };
> > >
> > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > >
> >
> > I did not invent this, I have just simplified this calculation from
> > downstream, output values remain same. I have no cameras which can
> > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > this works either. Other YUV and RAW formats were tested on real HW
> > and work perfectly fine.
>
> My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
>

Camera I am testing with has no YUV420 options available and from what
I can tell there is no way to force VI to output in YUV420 unless
camera supports it. Any format manipulations should requite hooking up
ISP, or am I missing smth?

> It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
>
> >
> > > >
> > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > >  }
> > > > > >
> > > > > >  /*
> > > > > > @@ -576,20 +564,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 = {
> > > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > >
> > >
> > >
> > >
>
>
>
>

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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-22  7:36             ` Svyatoslav Ryhel
@ 2025-09-23  6:03               ` Mikko Perttunen
  2025-09-23  6:11                 ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-23  6:03 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > >
> > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > >
> > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > @@ -280,20 +280,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);
> > > > > >
> > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > >
> > > > >
> > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > deprecated some time ago, here is a fragment
> > > > >
> > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > {
> > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > >  return 0;
> > > > >
> > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > >  return width * mf->bits_per_sample / 8;
> > > > >
> > > > >  switch (mf->packing) {
> > > > >  case SOC_MBUS_PACKING_NONE:
> > > > >   return width * mf->bits_per_sample / 8;
> > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > >   return width * 2;
> > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > >   return width * 3 / 2;
> > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > >   return 0;
> > > > >  }
> > > > >    return -EINVAL;
> > > > > }
> > > > >
> > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > >
> > > > Googling this brings up the entry
> > > >
> > > > {
> > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > >         .fmt = {
> > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > >                 .name                   = "YUYV 4:2:0",
> > > >                 .bits_per_sample                = 8,
> > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > >         },
> > > > }
> > > >
> > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > >
> > > > /**
> > > >  * enum soc_mbus_layout - planes layout in memory
> > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > >  *                                      chroma plane (C plane is half the size
> > > >  *                                      of Y plane)
> > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > >  *                                      chroma plane (C plane is the same size
> > > >  *                                      as Y plane)
> > > >  */
> > > > enum soc_mbus_layout {
> > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > };
> > > >
> > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > >
> > >
> > > I did not invent this, I have just simplified this calculation from
> > > downstream, output values remain same. I have no cameras which can
> > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > this works either. Other YUV and RAW formats were tested on real HW
> > > and work perfectly fine.
> >
> > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> >
> 
> Camera I am testing with has no YUV420 options available and from what
> I can tell there is no way to force VI to output in YUV420 unless
> camera supports it. Any format manipulations should requite hooking up
> ISP, or am I missing smth?

From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.

> 
> > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> >
> > >
> > > > >
> > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > >  }
> > > > > > >
> > > > > > >  /*
> > > > > > > @@ -576,20 +564,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 = {
> > > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > >
> > > >
> > > >
> > > >
> >
> >
> >
> >





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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-23  6:03               ` Mikko Perttunen
@ 2025-09-23  6:11                 ` Svyatoslav Ryhel
  2025-09-23  6:50                   ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-23  6: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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

вт, 23 вер. 2025 р. о 09:04 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> > пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > >
> > > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > >
> > > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > @@ -280,20 +280,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);
> > > > > > >
> > > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > > >
> > > > > >
> > > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > > deprecated some time ago, here is a fragment
> > > > > >
> > > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > > {
> > > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > > >  return 0;
> > > > > >
> > > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > > >  return width * mf->bits_per_sample / 8;
> > > > > >
> > > > > >  switch (mf->packing) {
> > > > > >  case SOC_MBUS_PACKING_NONE:
> > > > > >   return width * mf->bits_per_sample / 8;
> > > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > > >   return width * 2;
> > > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > > >   return width * 3 / 2;
> > > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > > >   return 0;
> > > > > >  }
> > > > > >    return -EINVAL;
> > > > > > }
> > > > > >
> > > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > > >
> > > > > Googling this brings up the entry
> > > > >
> > > > > {
> > > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > > >         .fmt = {
> > > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > > >                 .name                   = "YUYV 4:2:0",
> > > > >                 .bits_per_sample                = 8,
> > > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > > >         },
> > > > > }
> > > > >
> > > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > > >
> > > > > /**
> > > > >  * enum soc_mbus_layout - planes layout in memory
> > > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > > >  *                                      chroma plane (C plane is half the size
> > > > >  *                                      of Y plane)
> > > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > > >  *                                      chroma plane (C plane is the same size
> > > > >  *                                      as Y plane)
> > > > >  */
> > > > > enum soc_mbus_layout {
> > > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > > };
> > > > >
> > > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > > >
> > > >
> > > > I did not invent this, I have just simplified this calculation from
> > > > downstream, output values remain same. I have no cameras which can
> > > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > > this works either. Other YUV and RAW formats were tested on real HW
> > > > and work perfectly fine.
> > >
> > > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> > >
> >
> > Camera I am testing with has no YUV420 options available and from what
> > I can tell there is no way to force VI to output in YUV420 unless
> > camera supports it. Any format manipulations should requite hooking up
> > ISP, or am I missing smth?
>
> From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.
>

After additional checking you are correct, VI should be able to
perform YUV442 to YUV440. One of the reasons why VI is not exposing
YUV440 may be video-centric nature of the driver, so that it exposes
only formats supported by camera and VI. I will double check which
formats video device exposes. What should I test exactly?

> >
> > > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> > >
> > > >
> > > > > >
> > > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > > >  }
> > > > > > > >
> > > > > > > >  /*
> > > > > > > > @@ -576,20 +564,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 = {
> > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > >
> > >
> > >
> > >
>
>
>
>

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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-23  6:11                 ` Svyatoslav Ryhel
@ 2025-09-23  6:50                   ` Svyatoslav Ryhel
  2025-09-24  4:47                     ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-23  6:50 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

вт, 23 вер. 2025 р. о 09:11 Svyatoslav Ryhel <clamor95@gmail.com> пише:
>
> вт, 23 вер. 2025 р. о 09:04 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> > > пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > >
> > > > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > >
> > > > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > >
> > > > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > @@ -280,20 +280,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);
> > > > > > > >
> > > > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > > > >
> > > > > > >
> > > > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > > > deprecated some time ago, here is a fragment
> > > > > > >
> > > > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > > > {
> > > > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > > > >  return 0;
> > > > > > >
> > > > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > > > >  return width * mf->bits_per_sample / 8;
> > > > > > >
> > > > > > >  switch (mf->packing) {
> > > > > > >  case SOC_MBUS_PACKING_NONE:
> > > > > > >   return width * mf->bits_per_sample / 8;
> > > > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > > > >   return width * 2;
> > > > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > > > >   return width * 3 / 2;
> > > > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > > > >   return 0;
> > > > > > >  }
> > > > > > >    return -EINVAL;
> > > > > > > }
> > > > > > >
> > > > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > > > >
> > > > > > Googling this brings up the entry
> > > > > >
> > > > > > {
> > > > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > > > >         .fmt = {
> > > > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > > > >                 .name                   = "YUYV 4:2:0",
> > > > > >                 .bits_per_sample                = 8,
> > > > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > > > >         },
> > > > > > }
> > > > > >
> > > > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > > > >
> > > > > > /**
> > > > > >  * enum soc_mbus_layout - planes layout in memory
> > > > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > > > >  *                                      chroma plane (C plane is half the size
> > > > > >  *                                      of Y plane)
> > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > > > >  *                                      chroma plane (C plane is the same size
> > > > > >  *                                      as Y plane)
> > > > > >  */
> > > > > > enum soc_mbus_layout {
> > > > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > > > };
> > > > > >
> > > > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > > > >
> > > > >
> > > > > I did not invent this, I have just simplified this calculation from
> > > > > downstream, output values remain same. I have no cameras which can
> > > > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > > > this works either. Other YUV and RAW formats were tested on real HW
> > > > > and work perfectly fine.
> > > >
> > > > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> > > >
> > >
> > > Camera I am testing with has no YUV420 options available and from what
> > > I can tell there is no way to force VI to output in YUV420 unless
> > > camera supports it. Any format manipulations should requite hooking up
> > > ISP, or am I missing smth?
> >
> > From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.
> >
>
> After additional checking you are correct, VI should be able to
> perform YUV442 to YUV440. One of the reasons why VI is not exposing
> YUV440 may be video-centric nature of the driver, so that it exposes
> only formats supported by camera and VI. I will double check which
> formats video device exposes. What should I test exactly?
>

Alternatively, since code that I propose matches in output with one
that was before, changes can be applied and revised once there will be
such need. Especially, since YUV422 and RAW8/10 work fine and were
tested. I am not sure there will be many use cases which deliberately
target YUV420.

> > >
> > > > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> > > >
> > > > >
> > > > > > >
> > > > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > > > >  }
> > > > > > > > >
> > > > > > > > >  /*
> > > > > > > > > @@ -576,20 +564,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 = {
> > > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > > > >
> > > >
> > > >
> > > >
> > > >
> >
> >
> >
> >

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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-23  6:50                   ` Svyatoslav Ryhel
@ 2025-09-24  4:47                     ` Mikko Perttunen
  2025-09-24 10:24                       ` Svyatoslav Ryhel
  0 siblings, 1 reply; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-24  4:47 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Tuesday, September 23, 2025 3:50 PM Svyatoslav Ryhel wrote:
> вт, 23 вер. 2025 р. о 09:11 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> >
> > вт, 23 вер. 2025 р. о 09:04 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> > > > пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > >
> > > > > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > > > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > >
> > > > > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > > >
> > > > > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > @@ -280,20 +280,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);
> > > > > > > > >
> > > > > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > > > > >
> > > > > > > >
> > > > > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > > > > deprecated some time ago, here is a fragment
> > > > > > > >
> > > > > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > > > > {
> > > > > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > > > > >  return 0;
> > > > > > > >
> > > > > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > > > > >  return width * mf->bits_per_sample / 8;
> > > > > > > >
> > > > > > > >  switch (mf->packing) {
> > > > > > > >  case SOC_MBUS_PACKING_NONE:
> > > > > > > >   return width * mf->bits_per_sample / 8;
> > > > > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > > > > >   return width * 2;
> > > > > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > > > > >   return width * 3 / 2;
> > > > > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > > > > >   return 0;
> > > > > > > >  }
> > > > > > > >    return -EINVAL;
> > > > > > > > }
> > > > > > > >
> > > > > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > > > > >
> > > > > > > Googling this brings up the entry
> > > > > > >
> > > > > > > {
> > > > > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > > > > >         .fmt = {
> > > > > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > > > > >                 .name                   = "YUYV 4:2:0",
> > > > > > >                 .bits_per_sample                = 8,
> > > > > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > > > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > > > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > > > > >         },
> > > > > > > }
> > > > > > >
> > > > > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > > > > >
> > > > > > > /**
> > > > > > >  * enum soc_mbus_layout - planes layout in memory
> > > > > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > > > > >  *                                      chroma plane (C plane is half the size
> > > > > > >  *                                      of Y plane)
> > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > > > > >  *                                      chroma plane (C plane is the same size
> > > > > > >  *                                      as Y plane)
> > > > > > >  */
> > > > > > > enum soc_mbus_layout {
> > > > > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > > > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > > > > };
> > > > > > >
> > > > > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > > > > >
> > > > > >
> > > > > > I did not invent this, I have just simplified this calculation from
> > > > > > downstream, output values remain same. I have no cameras which can
> > > > > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > > > > this works either. Other YUV and RAW formats were tested on real HW
> > > > > > and work perfectly fine.
> > > > >
> > > > > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> > > > >
> > > >
> > > > Camera I am testing with has no YUV420 options available and from what
> > > > I can tell there is no way to force VI to output in YUV420 unless
> > > > camera supports it. Any format manipulations should requite hooking up
> > > > ISP, or am I missing smth?
> > >
> > > From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.
> > >
> >
> > After additional checking you are correct, VI should be able to
> > perform YUV442 to YUV440. One of the reasons why VI is not exposing
> > YUV440 may be video-centric nature of the driver, so that it exposes
> > only formats supported by camera and VI. I will double check which
> > formats video device exposes. What should I test exactly?
> >

If you are able to test, I would like to see the following (with YUV422 input camera, VI set to output YUV420)
(1) Output image is correct
(2) Check output image bytes per line (e.g. with a hex editor)
(3) If output image bytes per line is 3/2 * width, try changing it to 1 * width and repeating test

> 
> Alternatively, since code that I propose matches in output with one
> that was before, changes can be applied and revised once there will be
> such need. Especially, since YUV422 and RAW8/10 work fine and were
> tested. I am not sure there will be many use cases which deliberately
> target YUV420.
> 

Yeah, since it's a pre-existing issue, that makes sense. However, I'd still add a comment to the bytes per line calculation with a reference to the downstream code it's based on, and that it produces an unexpected 3/2 * width for YUV420.

Mikko

> > > >
> > > > > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> > > > >
> > > > > >
> > > > > > > >
> > > > > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > > > > >  }
> > > > > > > > > >
> > > > > > > > > >  /*
> > > > > > > > > > @@ -576,20 +564,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 = {
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > > > >
> > > > >
> > > > >
> > > > >
> > > > >
> > >
> > >
> > >
> > >





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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-24  4:47                     ` Mikko Perttunen
@ 2025-09-24 10:24                       ` Svyatoslav Ryhel
  2025-09-24 23:20                         ` Mikko Perttunen
  0 siblings, 1 reply; 71+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-24 10:24 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

ср, 24 вер. 2025 р. о 07:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, September 23, 2025 3:50 PM Svyatoslav Ryhel wrote:
> > вт, 23 вер. 2025 р. о 09:11 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > >
> > > вт, 23 вер. 2025 р. о 09:04 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > >
> > > > On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> > > > > пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > >
> > > > > > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > > > > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > >
> > > > > > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > > > >
> > > > > > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > > @@ -280,20 +280,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);
> > > > > > > > > >
> > > > > > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > > > > > >
> > > > > > > > >
> > > > > > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > > > > > deprecated some time ago, here is a fragment
> > > > > > > > >
> > > > > > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > > > > > {
> > > > > > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > > > > > >  return 0;
> > > > > > > > >
> > > > > > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > > > > > >  return width * mf->bits_per_sample / 8;
> > > > > > > > >
> > > > > > > > >  switch (mf->packing) {
> > > > > > > > >  case SOC_MBUS_PACKING_NONE:
> > > > > > > > >   return width * mf->bits_per_sample / 8;
> > > > > > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > > > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > > > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > > > > > >   return width * 2;
> > > > > > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > > > > > >   return width * 3 / 2;
> > > > > > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > > > > > >   return 0;
> > > > > > > > >  }
> > > > > > > > >    return -EINVAL;
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > > > > > >
> > > > > > > > Googling this brings up the entry
> > > > > > > >
> > > > > > > > {
> > > > > > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > > > > > >         .fmt = {
> > > > > > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > > > > > >                 .name                   = "YUYV 4:2:0",
> > > > > > > >                 .bits_per_sample                = 8,
> > > > > > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > > > > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > > > > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > > > > > >         },
> > > > > > > > }
> > > > > > > >
> > > > > > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > > > > > >
> > > > > > > > /**
> > > > > > > >  * enum soc_mbus_layout - planes layout in memory
> > > > > > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > > > > > >  *                                      chroma plane (C plane is half the size
> > > > > > > >  *                                      of Y plane)
> > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > > > > > >  *                                      chroma plane (C plane is the same size
> > > > > > > >  *                                      as Y plane)
> > > > > > > >  */
> > > > > > > > enum soc_mbus_layout {
> > > > > > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > > > > > };
> > > > > > > >
> > > > > > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > > > > > >
> > > > > > >
> > > > > > > I did not invent this, I have just simplified this calculation from
> > > > > > > downstream, output values remain same. I have no cameras which can
> > > > > > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > > > > > this works either. Other YUV and RAW formats were tested on real HW
> > > > > > > and work perfectly fine.
> > > > > >
> > > > > > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> > > > > >
> > > > >
> > > > > Camera I am testing with has no YUV420 options available and from what
> > > > > I can tell there is no way to force VI to output in YUV420 unless
> > > > > camera supports it. Any format manipulations should requite hooking up
> > > > > ISP, or am I missing smth?
> > > >
> > > > From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.
> > > >
> > >
> > > After additional checking you are correct, VI should be able to
> > > perform YUV442 to YUV440. One of the reasons why VI is not exposing
> > > YUV440 may be video-centric nature of the driver, so that it exposes
> > > only formats supported by camera and VI. I will double check which
> > > formats video device exposes. What should I test exactly?
> > >
>
> If you are able to test, I would like to see the following (with YUV422 input camera, VI set to output YUV420)
> (1) Output image is correct
> (2) Check output image bytes per line (e.g. with a hex editor)
> (3) If output image bytes per line is 3/2 * width, try changing it to 1 * width and repeating test
>

1 * width is enough, 3/2 * width has just end of memory dump filled
with zeroes. I assume downstream is wrong in this aspect. Additionally
I was able to address YUV422 > YUV420 conversion. Existing YUV entries
have YUV 2X8 media bus formats which are not used by my camera, my
camera uses only YUV 1X16 media bus formats. So by adding those YU12
format appeared.

>
> > Alternatively, since code that I propose matches in output with one
> > that was before, changes can be applied and revised once there will be
> > such need. Especially, since YUV422 and RAW8/10 work fine and were
> > tested. I am not sure there will be many use cases which deliberately
> > target YUV420.
> >
>
> Yeah, since it's a pre-existing issue, that makes sense. However, I'd still add a comment to the bytes per line calculation with a reference to the downstream code it's based on, and that it produces an unexpected 3/2 * width for YUV420.
>

I assume since I am applying expected and correct value, no additional
comments would be required within code, but I will add a note to
commit description.

> Mikko
>
> > > > >
> > > > > > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> > > > > >
> > > > > > >
> > > > > > > > >
> > > > > > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > > > > > >  }
> > > > > > > > > > >
> > > > > > > > > > >  /*
> > > > > > > > > > > @@ -576,20 +564,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 = {
> > > > > > > > > > >

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

* Re: [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations
  2025-09-24 10:24                       ` Svyatoslav Ryhel
@ 2025-09-24 23:20                         ` Mikko Perttunen
  0 siblings, 0 replies; 71+ messages in thread
From: Mikko Perttunen @ 2025-09-24 23:20 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, Prashant Gaikwad,
	Michael Turquette, Stephen Boyd, Mauro Carvalho Chehab,
	Greg Kroah-Hartman, Dmitry Osipenko, Jonas Schwöbel,
	Charan Pedumuru, dri-devel, devicetree, linux-tegra, linux-kernel,
	linux-media, linux-clk, linux-staging

On Wednesday, September 24, 2025 7:24 PM Svyatoslav Ryhel wrote:
> ср, 24 вер. 2025 р. о 07:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Tuesday, September 23, 2025 3:50 PM Svyatoslav Ryhel wrote:
> > > вт, 23 вер. 2025 р. о 09:11 Svyatoslav Ryhel <clamor95@gmail.com> пише:
> > > >
> > > > вт, 23 вер. 2025 р. о 09:04 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > >
> > > > > On Monday, September 22, 2025 4:36 PM Svyatoslav Ryhel wrote:
> > > > > > пн, 22 вер. 2025 р. о 10:27 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > >
> > > > > > > On Monday, September 22, 2025 3:30 PM Svyatoslav Ryhel wrote:
> > > > > > > > пн, 22 вер. 2025 р. о 09:23 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > > >
> > > > > > > > > On Monday, September 22, 2025 2:13 PM Svyatoslav Ryhel wrote:
> > > > > > > > > > пн, 22 вер. 2025 р. о 07:44 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > > > > > > > > >
> > > > > > > > > > > On Saturday, September 6, 2025 10:53 PM Svyatoslav Ryhel wrote:
> > > > > > > > > > > > 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 6e0b3b728623..781c4e8ec856 100644
> > > > > > > > > > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > > > > > > > > > @@ -280,20 +280,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);
> > > > > > > > > > >
> > > > > > > > > > > Assuming the bpp is coming from the format table below, this changes the value of bytesperline for planar formats. With this it'll be (width * 12) / 8 i.e. width * 3/2, which doesn't sound right.
> > > > > > > > > > >
> > > > > > > > > >
> > > > > > > > > > Downstream uses soc_mbus_bytes_per_line for this calculation which was
> > > > > > > > > > deprecated some time ago, here is a fragment
> > > > > > > > > >
> > > > > > > > > > s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf)
> > > > > > > > > > {
> > > > > > > > > >  if (mf->fourcc == V4L2_PIX_FMT_JPEG)
> > > > > > > > > >  return 0;
> > > > > > > > > >
> > > > > > > > > >  if (mf->layout != SOC_MBUS_LAYOUT_PACKED)
> > > > > > > > > >  return width * mf->bits_per_sample / 8;
> > > > > > > > > >
> > > > > > > > > >  switch (mf->packing) {
> > > > > > > > > >  case SOC_MBUS_PACKING_NONE:
> > > > > > > > > >   return width * mf->bits_per_sample / 8;
> > > > > > > > > >  case SOC_MBUS_PACKING_2X8_PADHI:
> > > > > > > > > >  case SOC_MBUS_PACKING_2X8_PADLO:
> > > > > > > > > >  case SOC_MBUS_PACKING_EXTEND16:
> > > > > > > > > >   return width * 2;
> > > > > > > > > >  case SOC_MBUS_PACKING_1_5X8:
> > > > > > > > > >   return width * 3 / 2;
> > > > > > > > > >  case SOC_MBUS_PACKING_VARIABLE:
> > > > > > > > > >   return 0;
> > > > > > > > > >  }
> > > > > > > > > >    return -EINVAL;
> > > > > > > > > > }
> > > > > > > > > >
> > > > > > > > > > V4L2_PIX_FMT_YUV420 and V4L2_PIX_FMT_YVU420 are classified as
> > > > > > > > > > SOC_MBUS_PACKING_1_5X8 hence we get width * 3/2
> > > > > > > > >
> > > > > > > > > Googling this brings up the entry
> > > > > > > > >
> > > > > > > > > {
> > > > > > > > >         .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
> > > > > > > > >         .fmt = {
> > > > > > > > >                 .fourcc                 = V4L2_PIX_FMT_YUV420,
> > > > > > > > >                 .name                   = "YUYV 4:2:0",
> > > > > > > > >                 .bits_per_sample                = 8,
> > > > > > > > >                 .packing                        = SOC_MBUS_PACKING_1_5X8,
> > > > > > > > >                 .order                  = SOC_MBUS_ORDER_LE,
> > > > > > > > >                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
> > > > > > > > >         },
> > > > > > > > > }
> > > > > > > > >
> > > > > > > > > which matches that you're describing. It doesn't make sense to me, since it at the same time specifies PIX_FMT_YUV420 (which is planar with 3 planes, as documented by include/uapi/linux/videodev2.h), and LAYOUT_PACKED
> > > > > > > > >
> > > > > > > > > /**
> > > > > > > > >  * enum soc_mbus_layout - planes layout in memory
> > > > > > > > >  * @SOC_MBUS_LAYOUT_PACKED:             color components packed
> > > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_U_V:      YUV components stored in 3 planes (4:2:2)
> > > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_2Y_C:        YUV components stored in a luma and a
> > > > > > > > >  *                                      chroma plane (C plane is half the size
> > > > > > > > >  *                                      of Y plane)
> > > > > > > > >  * @SOC_MBUS_LAYOUT_PLANAR_Y_C:         YUV components stored in a luma and a
> > > > > > > > >  *                                      chroma plane (C plane is the same size
> > > > > > > > >  *                                      as Y plane)
> > > > > > > > >  */
> > > > > > > > > enum soc_mbus_layout {
> > > > > > > > >         SOC_MBUS_LAYOUT_PACKED = 0,
> > > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_U_V,
> > > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_2Y_C,
> > > > > > > > >         SOC_MBUS_LAYOUT_PLANAR_Y_C,
> > > > > > > > > };
> > > > > > > > >
> > > > > > > > > i.e. non-planar. The code in the driver is handling it as three planes as well, with addresses VB0_BASE_ADDRESS/VB0_BASE_ADDRESS_U/VB0_BASE_ADDRESS_V. Since the planes are separate, there should be no need to have more than 'width' samples per line.
> > > > > > > > >
> > > > > > > >
> > > > > > > > I did not invent this, I have just simplified this calculation from
> > > > > > > > downstream, output values remain same. I have no cameras which can
> > > > > > > > output V4L2_PIX_FMT_YUV420 or V4L2_PIX_FMT_YVU420 so I cannot test if
> > > > > > > > this works either. Other YUV and RAW formats were tested on real HW
> > > > > > > > and work perfectly fine.
> > > > > > >
> > > > > > > My understanding from the code was, that the MEDIA_BUS_FMT_ formats listed in the video format table refer to the input formats from the camera, and the V4L2_PIX_FMT_ formats to output formats from VI. Hence VI could input UYVY8_2X8 and write to memory in YUV420. The code dealing with V4L2_PIX_FMT_ values seems to be related to the output to memory. Is it possible to test this (your camera -> VI converts to YUV420) or am I mistaken?
> > > > > > >
> > > > > >
> > > > > > Camera I am testing with has no YUV420 options available and from what
> > > > > > I can tell there is no way to force VI to output in YUV420 unless
> > > > > > camera supports it. Any format manipulations should requite hooking up
> > > > > > ISP, or am I missing smth?
> > > > >
> > > > > From a quick look at the spec it looks to me like for YUV422 packed input formats specifically, VI should be able to convert to YUV420. If that were not the case, e.g. 'TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),' would not make sense anyway as it's talking about both YUV422 packed input data and then also YUV420.
> > > > >
> > > >
> > > > After additional checking you are correct, VI should be able to
> > > > perform YUV442 to YUV440. One of the reasons why VI is not exposing
> > > > YUV440 may be video-centric nature of the driver, so that it exposes
> > > > only formats supported by camera and VI. I will double check which
> > > > formats video device exposes. What should I test exactly?
> > > >
> >
> > If you are able to test, I would like to see the following (with YUV422 input camera, VI set to output YUV420)
> > (1) Output image is correct
> > (2) Check output image bytes per line (e.g. with a hex editor)
> > (3) If output image bytes per line is 3/2 * width, try changing it to 1 * width and repeating test
> >
> 
> 1 * width is enough, 3/2 * width has just end of memory dump filled
> with zeroes. I assume downstream is wrong in this aspect. Additionally
> I was able to address YUV422 > YUV420 conversion. Existing YUV entries
> have YUV 2X8 media bus formats which are not used by my camera, my
> camera uses only YUV 1X16 media bus formats. So by adding those YU12
> format appeared.

Excellent! I suppose we have a better driver than downstream now :)

> 
> >
> > > Alternatively, since code that I propose matches in output with one
> > > that was before, changes can be applied and revised once there will be
> > > such need. Especially, since YUV422 and RAW8/10 work fine and were
> > > tested. I am not sure there will be many use cases which deliberately
> > > target YUV420.
> > >
> >
> > Yeah, since it's a pre-existing issue, that makes sense. However, I'd still add a comment to the bytes per line calculation with a reference to the downstream code it's based on, and that it produces an unexpected 3/2 * width for YUV420.
> >
> 
> I assume since I am applying expected and correct value, no additional
> comments would be required within code, but I will add a note to
> commit description.

Indeed.

Thanks!
Mikko

> 
> > Mikko
> >
> > > > > >
> > > > > > > It's certainly possible that the current code is functional -- if bytesperline is set to a too large value and that information flows to userspace, it could still read the buffer. It would just waste memory.
> > > > > > >
> > > > > > > >
> > > > > > > > > >
> > > > > > > > > > > > +     pix->sizeimage = pix->bytesperline * pix->height;
> > > > > > > > > > > >  }
> > > > > > > > > > > >
> > > > > > > > > > > >  /*
> > > > > > > > > > > > @@ -576,20 +564,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 = {
> > > > > > > > > > > >





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

end of thread, other threads:[~2025-09-24 23:20 UTC | newest]

Thread overview: 71+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-09-06 13:53 [PATCH v2 00/23] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 01/23] clk: tegra: set CSUS as vi_sensors gate for Tegra20, Tegra30 and Tegra114 Svyatoslav Ryhel
2025-09-19  6:29   ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 02/23] dt-bindings: clock: tegra30: Add IDs for CSI pad clocks Svyatoslav Ryhel
2025-09-07  9:34   ` Krzysztof Kozlowski
2025-09-07  9:43     ` Svyatoslav Ryhel
2025-09-07 18:25       ` Krzysztof Kozlowski
2025-09-06 13:53 ` [PATCH v2 03/23] clk: tegra30: add CSI pad clock gates Svyatoslav Ryhel
2025-09-19  6:33   ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 04/23] dt-bindings: display: tegra: document Tegra30 VI and VIP Svyatoslav Ryhel
2025-09-06 19:17   ` Rob Herring (Arm)
2025-09-06 13:53 ` [PATCH v2 05/23] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
2025-09-17  7:52   ` Luca Ceresoli
2025-09-06 13:53 ` [PATCH v2 06/23] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 07/23] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 08/23] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 09/23] gpu: host1x: convert MIPI to use operations Svyatoslav Ryhel
2025-09-19  6:47   ` Mikko Perttunen
2025-09-19  7:58     ` Svyatoslav Ryhel
2025-09-19  8:56       ` Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 10/23] staging: media: tegra-video: csi: add support for SoCs with integrated MIPI calibration Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 11/23] staging: media: tegra-video: csi: add a check to tegra_channel_get_remote_csi_subdev Svyatoslav Ryhel
2025-09-16 16:04   ` Luca Ceresoli
2025-09-16 16:24     ` Svyatoslav Ryhel
2025-09-17  7:25       ` Luca Ceresoli
2025-09-17  7:49         ` Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 12/23] dt-bindings: display: tegra: move avdd-dsi-csi-supply from VI to CSI Svyatoslav Ryhel
2025-09-09  0:49   ` Rob Herring (Arm)
2025-09-09  0:57   ` Rob Herring
2025-09-09  5:00     ` Svyatoslav Ryhel
2025-09-09 16:03       ` Rob Herring
2025-09-06 13:53 ` [PATCH v2 13/23] staging: media: tegra-video: csi: " Svyatoslav Ryhel
2025-09-17  7:52   ` Luca Ceresoli
2025-09-22  4:11   ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 14/23] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 15/23] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
2025-09-22  4:29   ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 16/23] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
2025-09-22  4:44   ` Mikko Perttunen
2025-09-22  5:13     ` Svyatoslav Ryhel
2025-09-22  6:23       ` Mikko Perttunen
2025-09-22  6:30         ` Svyatoslav Ryhel
2025-09-22  7:27           ` Mikko Perttunen
2025-09-22  7:36             ` Svyatoslav Ryhel
2025-09-23  6:03               ` Mikko Perttunen
2025-09-23  6:11                 ` Svyatoslav Ryhel
2025-09-23  6:50                   ` Svyatoslav Ryhel
2025-09-24  4:47                     ` Mikko Perttunen
2025-09-24 10:24                       ` Svyatoslav Ryhel
2025-09-24 23:20                         ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 17/23] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 18/23] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
2025-09-22  4:54   ` Mikko Perttunen
2025-09-22  4:58     ` Svyatoslav Ryhel
2025-09-22  6:23       ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 19/23] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
2025-09-22  5:00   ` Mikko Perttunen
2025-09-06 13:53 ` [PATCH v2 20/23] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 21/23] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
2025-09-09 16:26   ` Rob Herring
2025-09-09 16:39     ` Svyatoslav Ryhel
2025-09-10  2:13       ` Rob Herring
2025-09-06 13:53 ` [PATCH v2 22/23] ARM: tegra: add CSI nodes for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-09-06 13:53 ` [PATCH v2 23/23] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
2025-09-15  5:46   ` kernel test robot
2025-09-22  5:15   ` Mikko Perttunen
2025-09-22  5:19     ` Svyatoslav Ryhel
2025-09-22  5:38       ` Mikko Perttunen
2025-09-22  6:16     ` Svyatoslav Ryhel
2025-09-22  6:36       ` Mikko Perttunen
2025-09-11 16:03 ` (subset) [PATCH v2 00/23] " Thierry Reding

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).