* [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30
@ 2025-08-19 12:16 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
` (18 more replies)
0 siblings, 19 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC along
with a set of changes required for that.
Svyatoslav Ryhel (19):
clk: tegra: init CSUS clock for Tegra20 and Tegra30
dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
clk: tegra30: add CSI PAD clock gates
dt-bindings: display: tegra: document Tegra30 VIP
staging: media: tegra-video: expand VI and VIP support to Tegra30
staging: media: tegra-video: csi: move CSI helpers to header
staging: media: tegra-video: csi: parametrize MIPI calibration device
presence
staging: media: tegra-video: vi: adjust get_selection op check
staging: media: tegra-video: vi: add flip controls only if no source
controls are provided
staging: media: tegra-video: tegra20: set correct maximum width and
height
staging: media: tegra-video: tegra20: add support for second output of
VI
staging: media: tegra-video: tegra20: simplify format align
calculations
staging: media: tegra-video: tegra20: set VI HW revision
staging: media: tegra-video: tegra20: increase maximum VI clock
frequency
staging: media: tegra-video: tegra20: expand format support with
RAW8/10 and YUV422 1X16
staging: media: tegra-video: tegra20: adjust luma buffer stride
dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
ARM: tegra: add CSI binding for Tegra20 and Tegra30
staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
.../display/tegra/nvidia,tegra20-vip.yaml | 1 +
.../display/tegra/nvidia,tegra210-csi.yaml | 78 +-
arch/arm/boot/dts/nvidia/tegra20.dtsi | 17 +-
arch/arm/boot/dts/nvidia/tegra30.dtsi | 19 +-
drivers/clk/tegra/clk-tegra20.c | 1 +
drivers/clk/tegra/clk-tegra30.c | 16 +-
drivers/staging/media/tegra-video/Makefile | 1 +
drivers/staging/media/tegra-video/csi.c | 35 +-
drivers/staging/media/tegra-video/csi.h | 11 +
drivers/staging/media/tegra-video/tegra20.c | 771 +++++++++++++++---
drivers/staging/media/tegra-video/tegra210.c | 1 +
drivers/staging/media/tegra-video/vi.c | 20 +-
drivers/staging/media/tegra-video/vi.h | 4 +-
drivers/staging/media/tegra-video/video.c | 6 +
drivers/staging/media/tegra-video/vip.c | 5 +-
include/dt-bindings/clock/tegra30-car.h | 4 +-
16 files changed, 842 insertions(+), 148 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 59+ messages in thread
* [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-27 4:09 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
` (17 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
CSUS clock is required to be enabled on camera device configuration or
else camera module refuses to initiate properly.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/clk/tegra/clk-tegra20.c | 1 +
drivers/clk/tegra/clk-tegra30.c | 1 +
2 files changed, 2 insertions(+)
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index 551ef0cf0c9a..42f8150c6110 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
{ TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
{ TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
{ TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
+ { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
/* must be the last entry */
{ TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
};
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 82a8cb9545eb..70e85e2949e0 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
{ TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
{ TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
{ TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
+ { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
/* must be the last entry */
{ TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
};
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-22 13:59 ` Rob Herring
2025-08-27 4:19 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
` (16 subsequent siblings)
18 siblings, 2 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
Add ids for these clocks.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
include/dt-bindings/clock/tegra30-car.h | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
index f193663e6f28..14b83e90a0fc 100644
--- a/include/dt-bindings/clock/tegra30-car.h
+++ b/include/dt-bindings/clock/tegra30-car.h
@@ -271,6 +271,8 @@
#define TEGRA30_CLK_AUDIO3_MUX 306
#define TEGRA30_CLK_AUDIO4_MUX 307
#define TEGRA30_CLK_SPDIF_MUX 308
-#define TEGRA30_CLK_CLK_MAX 309
+#define TEGRA30_CLK_CSIA_PAD 309
+#define TEGRA30_CLK_CSIB_PAD 310
+#define TEGRA30_CLK_CLK_MAX 311
#endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-27 4:26 ` Mikko Perttunen
2025-08-29 0:44 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
` (15 subsequent siblings)
18 siblings, 2 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
for correct work of CSI block.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 70e85e2949e0..f033eb1ac26a 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -153,6 +153,7 @@ static unsigned long input_freq;
static DEFINE_SPINLOCK(cml_lock);
static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(pll_d2_lock);
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
_clk_num, _gate_flags, _clk_id) \
@@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
/* PLLD2 */
clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base, 0,
- &pll_d2_params, NULL);
+ &pll_d2_params, &pll_d2_lock);
clks[TEGRA30_CLK_PLL_D2] = clk;
/* PLLD2_OUT0 */
@@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
0, 48, periph_clk_enb_refcnt);
clks[TEGRA30_CLK_DSIA] = clk;
+ /* csia_pad */
+ clk = clk_register_gate(NULL, "csia_pad", "pll_d", CLK_SET_RATE_PARENT,
+ clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
+ clk_register_clkdev(clk, "csia_pad", NULL);
+ clks[TEGRA30_CLK_CSIA_PAD] = clk;
+
+ /* csib_pad */
+ clk = clk_register_gate(NULL, "csib_pad", "pll_d2", CLK_SET_RATE_PARENT,
+ clk_base + PLLD2_BASE, 26, 0, &pll_d2_lock);
+ clk_register_clkdev(clk, "csib_pad", NULL);
+ clks[TEGRA30_CLK_CSIB_PAD] = clk;
+
/* pcie */
clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
70, periph_clk_enb_refcnt);
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (2 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 20:27 ` Rob Herring
2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
` (14 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
index 14294edb8d8c..39e9b3297dbd 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
@@ -13,6 +13,7 @@ properties:
compatible:
enum:
- nvidia,tegra20-vip
+ - nvidia,tegra30-vip
ports:
$ref: /schemas/graph.yaml#/properties/ports
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (3 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-27 4:29 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
` (13 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Exisitng VI and VIP implementation for Tegra20 is fully compatible with
Tegra30.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/Makefile | 1 +
drivers/staging/media/tegra-video/vi.c | 3 +++
drivers/staging/media/tegra-video/vi.h | 2 +-
drivers/staging/media/tegra-video/video.c | 4 ++++
drivers/staging/media/tegra-video/vip.c | 5 ++++-
5 files changed, 13 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/tegra-video/Makefile b/drivers/staging/media/tegra-video/Makefile
index 6c7552e05109..96380b5dbd8b 100644
--- a/drivers/staging/media/tegra-video/Makefile
+++ b/drivers/staging/media/tegra-video/Makefile
@@ -6,5 +6,6 @@ tegra-video-objs := \
csi.o
tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o
+tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra20.o
tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index c9276ff76157..71be205cacb5 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -1959,6 +1959,9 @@ static const struct of_device_id tegra_vi_of_id_table[] = {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
{ .compatible = "nvidia,tegra20-vi", .data = &tegra20_vi_soc },
#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ { .compatible = "nvidia,tegra30-vi", .data = &tegra20_vi_soc },
+#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
{ .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
#endif
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index 1e6a5caa7082..cac0c0d0e225 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -296,7 +296,7 @@ struct tegra_video_format {
u32 fourcc;
};
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
extern const struct tegra_vi_soc tegra20_vi_soc;
#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
index 074ad0dc56ca..a25885f93cd7 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[] = {
{ .compatible = "nvidia,tegra20-vip", },
{ .compatible = "nvidia,tegra20-vi", },
#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ { .compatible = "nvidia,tegra30-vip", },
+ { .compatible = "nvidia,tegra30-vi", },
+#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
{ .compatible = "nvidia,tegra210-csi", },
{ .compatible = "nvidia,tegra210-vi", },
diff --git a/drivers/staging/media/tegra-video/vip.c b/drivers/staging/media/tegra-video/vip.c
index 5ec717f3afd5..00e08a9971d5 100644
--- a/drivers/staging/media/tegra-video/vip.c
+++ b/drivers/staging/media/tegra-video/vip.c
@@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
-#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
extern const struct tegra_vip_soc tegra20_vip_soc;
#endif
static const struct of_device_id tegra_vip_of_id_table[] = {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
{ .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ { .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
#endif
{ }
};
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (4 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
` (12 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Move CSI helpers into the header for easier access from SoC-specific video
driver parts.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/csi.c | 11 -----------
drivers/staging/media/tegra-video/csi.h | 10 ++++++++++
2 files changed, 10 insertions(+), 11 deletions(-)
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 604185c00a1a..74c92db1032f 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -20,17 +20,6 @@
#define MHZ 1000000
-static inline struct tegra_csi *
-host1x_client_to_csi(struct host1x_client *client)
-{
- return container_of(client, struct tegra_csi, client);
-}
-
-static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev)
-{
- return container_of(subdev, struct tegra_csi_channel, subdev);
-}
-
/*
* CSI is a separate subdevice which has 6 source pads to generate
* test pattern. CSI subdevice pad ops are used only for TPG and
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 3e6e5ee1bb1e..3ed2dbc73ce9 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -151,6 +151,16 @@ struct tegra_csi {
struct list_head csi_chans;
};
+static inline struct tegra_csi *host1x_client_to_csi(struct host1x_client *client)
+{
+ return container_of(client, struct tegra_csi, client);
+}
+
+static inline struct tegra_csi_channel *to_csi_chan(struct v4l2_subdev *subdev)
+{
+ return container_of(subdev, struct tegra_csi_channel, subdev);
+}
+
void tegra_csi_error_recover(struct v4l2_subdev *subdev);
void tegra_csi_calc_settle_time(struct tegra_csi_channel *csi_chan,
u8 csi_port_num,
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (5 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 0:46 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
` (11 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
all MIPI calibration pads were part of VI block.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/csi.c | 12 +++++++-----
drivers/staging/media/tegra-video/csi.h | 1 +
drivers/staging/media/tegra-video/tegra210.c | 1 +
3 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 74c92db1032f..2f9907a20db1 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi *csi,
if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
return 0;
- chan->mipi = tegra_mipi_request(csi->dev, node);
- if (IS_ERR(chan->mipi)) {
- ret = PTR_ERR(chan->mipi);
- chan->mipi = NULL;
- dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
+ if (csi->soc->has_mipi_calibration) {
+ chan->mipi = tegra_mipi_request(csi->dev, node);
+ if (IS_ERR(chan->mipi)) {
+ ret = PTR_ERR(chan->mipi);
+ chan->mipi = NULL;
+ dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
+ }
}
return ret;
diff --git a/drivers/staging/media/tegra-video/csi.h b/drivers/staging/media/tegra-video/csi.h
index 3ed2dbc73ce9..400b913bb1cb 100644
--- a/drivers/staging/media/tegra-video/csi.h
+++ b/drivers/staging/media/tegra-video/csi.h
@@ -128,6 +128,7 @@ struct tegra_csi_soc {
unsigned int num_clks;
const struct tpg_framerate *tpg_frmrate_table;
unsigned int tpg_frmrate_table_size;
+ bool has_mipi_calibration;
};
/**
diff --git a/drivers/staging/media/tegra-video/tegra210.c b/drivers/staging/media/tegra-video/tegra210.c
index da99f19a39e7..305472e94af4 100644
--- a/drivers/staging/media/tegra-video/tegra210.c
+++ b/drivers/staging/media/tegra-video/tegra210.c
@@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
.num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
.tpg_frmrate_table = tegra210_tpg_frmrate_table,
.tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
+ .has_mipi_calibration = true,
};
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (6 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
` (10 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Get_selection operation may be implemented only for sink pad and may
return error code. Set try_crop to 0 instead of returning error.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/vi.c | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 71be205cacb5..4f67adc395ac 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -476,15 +476,11 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
fse.code = fmtinfo->code;
ret = v4l2_subdev_call(subdev, pad, enum_frame_size, sd_state, &fse);
if (ret) {
- if (!v4l2_subdev_has_op(subdev, pad, get_selection)) {
+ if (!v4l2_subdev_has_op(subdev, pad, get_selection) ||
+ v4l2_subdev_call(subdev, pad, get_selection, NULL, &sdsel)) {
try_crop->width = 0;
try_crop->height = 0;
} else {
- ret = v4l2_subdev_call(subdev, pad, get_selection,
- NULL, &sdsel);
- if (ret)
- return -EINVAL;
-
try_crop->width = sdsel.r.width;
try_crop->height = sdsel.r.height;
}
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (7 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
` (9 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Add HFLIP and VFLIP from SoC only if camera sensor does not provide those
controls.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/vi.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index 4f67adc395ac..61b65a2c1436 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -961,6 +961,7 @@ static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
}
#else
struct v4l2_subdev *subdev;
+ struct v4l2_ctrl *hflip, *vflip;
/* custom control */
v4l2_ctrl_new_custom(&chan->ctrl_handler, &syncpt_timeout_ctrl, NULL);
@@ -986,11 +987,13 @@ static int tegra_channel_setup_ctrl_handler(struct tegra_vi_channel *chan)
return ret;
}
- if (chan->vi->soc->has_h_v_flip) {
+ hflip = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_HFLIP);
+ if (chan->vi->soc->has_h_v_flip && !hflip)
v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
- }
+ vflip = v4l2_ctrl_find(subdev->ctrl_handler, V4L2_CID_VFLIP);
+ if (chan->vi->soc->has_h_v_flip && !vflip)
+ v4l2_ctrl_new_std(&chan->ctrl_handler, &vi_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
#endif
/* setup the controls */
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (8 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 0:51 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
` (8 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Maximum width and height for Tegra20 and Tegra30 is determined by
respective register field, rounded down to factor of 2, which is 8191U
rounded down to 8190U.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 7b8f8f810b35..3e2d746638b6 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -23,11 +23,10 @@
#define TEGRA_VI_SYNCPT_WAIT_TIMEOUT msecs_to_jiffies(200)
-/* This are just good-sense numbers. The actual min/max is not documented. */
#define TEGRA20_MIN_WIDTH 32U
+#define TEGRA20_MAX_WIDTH 8190U
#define TEGRA20_MIN_HEIGHT 32U
-#define TEGRA20_MAX_WIDTH 2048U
-#define TEGRA20_MAX_HEIGHT 2048U
+#define TEGRA20_MAX_HEIGHT 8190U
/* --------------------------------------------------------------------------
* Registers
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (9 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 1:00 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
` (7 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
VI in Tegra20/Tegra30 has 2 VI outputs with different set of supported
formats. Convert output registers to macros for simpler work with both
outputs since apart formats their layout matches.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 80 ++++++++++++---------
1 file changed, 45 insertions(+), 35 deletions(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 3e2d746638b6..54512d1ecf83 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -28,13 +28,19 @@
#define TEGRA20_MIN_HEIGHT 32U
#define TEGRA20_MAX_HEIGHT 8190U
+/* Tegra20/Tegra30 has 2 outputs in VI */
+enum {
+ OUT_1,
+ OUT_2,
+};
+
/* --------------------------------------------------------------------------
* Registers
*/
-#define TEGRA_VI_CONT_SYNCPT_OUT_1 0x0060
-#define VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT BIT(8)
-#define VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT 0
+#define TEGRA_VI_CONT_SYNCPT_OUT(n) (0x0060 + (n) * 4)
+#define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
+#define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
#define TEGRA_VI_VI_INPUT_CONTROL 0x0088
#define VI_INPUT_FIELD_DETECT BIT(27)
@@ -46,6 +52,7 @@
#define VI_INPUT_YUV_INPUT_FORMAT_YVYU (3 << VI_INPUT_YUV_INPUT_FORMAT_SFT)
#define VI_INPUT_INPUT_FORMAT_SFT 2 /* bits [5:2] */
#define VI_INPUT_INPUT_FORMAT_YUV422 (0 << VI_INPUT_INPUT_FORMAT_SFT)
+#define VI_INPUT_INPUT_FORMAT_BAYER (2 << VI_INPUT_INPUT_FORMAT_SFT)
#define VI_INPUT_VIP_INPUT_ENABLE BIT(1)
#define TEGRA_VI_VI_CORE_CONTROL 0x008c
@@ -66,7 +73,7 @@
#define VI_VI_CORE_CONTROL_OUTPUT_TO_EPP_SFT 2
#define VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_SFT 0
-#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x0090
+#define TEGRA_VI_VI_OUTPUT_CONTROL(n) (0x0090 + (n) * 4)
#define VI_OUTPUT_FORMAT_EXT BIT(22)
#define VI_OUTPUT_V_DIRECTION BIT(20)
#define VI_OUTPUT_H_DIRECTION BIT(19)
@@ -80,6 +87,7 @@
#define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
#define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
#define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
#define TEGRA_VI_VIP_H_ACTIVE 0x00a4
#define VI_VIP_H_ACTIVE_PERIOD_SFT 16 /* active pixels/line, must be even */
@@ -89,26 +97,26 @@
#define VI_VIP_V_ACTIVE_PERIOD_SFT 16 /* active lines */
#define VI_VIP_V_ACTIVE_START_SFT 0
-#define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x00c4
-#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x00c8
+#define TEGRA_VI_VB0_START_ADDRESS(n) (0x00c4 + (n) * 44)
+#define TEGRA_VI_VB0_BASE_ADDRESS(n) (0x00c8 + (n) * 44)
#define TEGRA_VI_VB0_START_ADDRESS_U 0x00cc
#define TEGRA_VI_VB0_BASE_ADDRESS_U 0x00d0
#define TEGRA_VI_VB0_START_ADDRESS_V 0x00d4
#define TEGRA_VI_VB0_BASE_ADDRESS_V 0x00d8
-#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x00e0
-#define VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT 16
-#define VI_FIRST_OUTPUT_FRAME_WIDTH_SFT 0
+#define TEGRA_VI_OUTPUT_FRAME_SIZE(n) (0x00e0 + (n) * 24)
+#define VI_OUTPUT_FRAME_HEIGHT_SFT 16
+#define VI_OUTPUT_FRAME_WIDTH_SFT 0
-#define TEGRA_VI_VB0_COUNT_FIRST 0x00e4
+#define TEGRA_VI_VB0_COUNT(n) (0x00e4 + (n) * 24)
-#define TEGRA_VI_VB0_SIZE_FIRST 0x00e8
-#define VI_VB0_SIZE_FIRST_V_SFT 16
-#define VI_VB0_SIZE_FIRST_H_SFT 0
+#define TEGRA_VI_VB0_SIZE(n) (0x00e8 + (n) * 24)
+#define VI_VB0_SIZE_V_SFT 16
+#define VI_VB0_SIZE_H_SFT 0
-#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x00ec
-#define VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT 30
-#define VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT 0
+#define TEGRA_VI_VB0_BUFFER_STRIDE(n) (0x00ec + (n) * 24)
+#define VI_VB0_BUFFER_STRIDE_CHROMA_SFT 30
+#define VI_VB0_BUFFER_STRIDE_LUMA_SFT 0
#define TEGRA_VI_H_LPF_CONTROL 0x0108
#define VI_H_LPF_CONTROL_CHROMA_SFT 16
@@ -136,7 +144,7 @@
#define VI_CAMERA_CONTROL_TEST_MODE BIT(1)
#define VI_CAMERA_CONTROL_VIP_ENABLE BIT(0)
-#define TEGRA_VI_VI_ENABLE 0x01a4
+#define TEGRA_VI_VI_ENABLE(n) (0x01a4 + (n) * 4)
#define VI_VI_ENABLE_SW_FLOW_CONTROL_OUT1 BIT(1)
#define VI_VI_ENABLE_FIRST_OUTPUT_TO_MEM_DISABLE BIT(0)
@@ -366,8 +374,8 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
- tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_FIRST, base);
- tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_FIRST, base + chan->start_offset);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_1), base);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset);
break;
}
}
@@ -455,6 +463,7 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
int stride_l = chan->format.bytesperline;
int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
+ int output_channel = OUT_1;
int main_output_format;
int yuv_output_format;
@@ -472,33 +481,33 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
/* Set up raise-on-edge, so we get an interrupt on end of frame. */
tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
- tegra20_vi_write(chan, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
+ tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
(chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
(chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
/* Set up frame size */
- tegra20_vi_write(chan, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
- height << VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT |
- width << VI_FIRST_OUTPUT_FRAME_WIDTH_SFT);
+ tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
+ height << VI_OUTPUT_FRAME_HEIGHT_SFT |
+ width << VI_OUTPUT_FRAME_WIDTH_SFT);
/* First output memory enabled */
- tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
+ tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
/* Set the number of frames in the buffer */
- tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT_FIRST, 1);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT(output_channel), 1);
/* Set up buffer frame size */
- tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE_FIRST,
- height << VI_VB0_SIZE_FIRST_V_SFT |
- width << VI_VB0_SIZE_FIRST_H_SFT);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE(output_channel),
+ height << VI_VB0_SIZE_V_SFT |
+ width << VI_VB0_SIZE_H_SFT);
- tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
- stride_l << VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT |
- stride_c << VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE(output_channel),
+ stride_l << VI_VB0_BUFFER_STRIDE_LUMA_SFT |
+ stride_c << VI_VB0_BUFFER_STRIDE_CHROMA_SFT);
- tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
+ tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
}
static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
@@ -607,6 +616,7 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&vip_chan->subdev);
int width = vi_chan->format.width;
int height = vi_chan->format.height;
+ int output_channel = OUT_1;
unsigned int main_input_format;
unsigned int yuv_input_format;
@@ -637,10 +647,10 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
GENMASK(9, 2) << VI_DATA_INPUT_SFT);
tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INVERSION, 0);
- tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT_1,
- VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT |
+ tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
+ VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
host1x_syncpt_id(vi_chan->mw_ack_sp[0])
- << VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT);
+ << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (10 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
` (6 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Simplify format align calculations by slightly modifying supported formats
structure.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 41 ++++++++-------------
1 file changed, 16 insertions(+), 25 deletions(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 54512d1ecf83..735611c3c47d 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -279,20 +279,8 @@ static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
pix->width = clamp(pix->width, TEGRA20_MIN_WIDTH, TEGRA20_MAX_WIDTH);
pix->height = clamp(pix->height, TEGRA20_MIN_HEIGHT, TEGRA20_MAX_HEIGHT);
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_UYVY:
- case V4L2_PIX_FMT_VYUY:
- case V4L2_PIX_FMT_YUYV:
- case V4L2_PIX_FMT_YVYU:
- pix->bytesperline = roundup(pix->width, 2) * 2;
- pix->sizeimage = roundup(pix->width, 2) * 2 * pix->height;
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- pix->bytesperline = roundup(pix->width, 8);
- pix->sizeimage = roundup(pix->width, 8) * pix->height * 3 / 2;
- break;
- }
+ pix->bytesperline = DIV_ROUND_UP(pix->width * bpp, 8);
+ pix->sizeimage = pix->bytesperline * pix->height;
}
/*
@@ -575,20 +563,23 @@ static const struct tegra_vi_ops tegra20_vi_ops = {
.vi_stop_streaming = tegra20_vi_stop_streaming,
};
-#define TEGRA20_VIDEO_FMT(MBUS_CODE, BPP, FOURCC) \
-{ \
- .code = MEDIA_BUS_FMT_##MBUS_CODE, \
- .bpp = BPP, \
- .fourcc = V4L2_PIX_FMT_##FOURCC, \
+#define TEGRA20_VIDEO_FMT(DATA_TYPE, BIT_WIDTH, MBUS_CODE, BPP, FOURCC) \
+{ \
+ .img_dt = TEGRA_IMAGE_DT_##DATA_TYPE, \
+ .bit_width = BIT_WIDTH, \
+ .code = MEDIA_BUS_FMT_##MBUS_CODE, \
+ .bpp = BPP, \
+ .fourcc = V4L2_PIX_FMT_##FOURCC, \
}
static const struct tegra_video_format tegra20_video_formats[] = {
- TEGRA20_VIDEO_FMT(UYVY8_2X8, 2, UYVY),
- TEGRA20_VIDEO_FMT(VYUY8_2X8, 2, VYUY),
- TEGRA20_VIDEO_FMT(YUYV8_2X8, 2, YUYV),
- TEGRA20_VIDEO_FMT(YVYU8_2X8, 2, YVYU),
- TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YUV420),
- TEGRA20_VIDEO_FMT(UYVY8_2X8, 1, YVU420),
+ /* YUV422 */
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 16, UYVY),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_2X8, 16, VYUY),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_2X8, 16, YUYV),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16, YVYU),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
};
const struct tegra_vi_soc tegra20_vi_soc = {
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (11 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
` (5 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Tegra20, Tegra30 and Tegra114 have VI revision 1.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 735611c3c47d..71dcb982c97b 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -587,6 +587,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
.nformats = ARRAY_SIZE(tegra20_video_formats),
.default_video_format = &tegra20_video_formats[0],
.ops = &tegra20_vi_ops,
+ .hw_revision = 1,
.vi_max_channels = 1, /* parallel input (VIP) */
.vi_max_clk_hz = 150000000,
.has_h_v_flip = true,
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (12 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
` (4 subsequent siblings)
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Increase maximum VI clock frequency to 450MHz to allow correct work with
high resolution camera sensors.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 71dcb982c97b..67631e0c9ffc 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -589,7 +589,7 @@ const struct tegra_vi_soc tegra20_vi_soc = {
.ops = &tegra20_vi_ops,
.hw_revision = 1,
.vi_max_channels = 1, /* parallel input (VIP) */
- .vi_max_clk_hz = 150000000,
+ .vi_max_clk_hz = 450000000,
.has_h_v_flip = true,
};
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (13 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 1:09 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
` (3 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
of existing YUV422_8 2X8.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
1 file changed, 69 insertions(+), 2 deletions(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index 67631e0c9ffc..b466fe7f4504 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct tegra_vi_channel *chan,
case MEDIA_BUS_FMT_YVYU8_2X8:
(*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
break;
+ /* RAW8 */
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
+ /* RAW10 */
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ (*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
+ break;
}
}
@@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct tegra_vi_channel *chan,
case V4L2_PIX_FMT_YVU420:
(*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
break;
+ /* RAW8 */
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
+ /* RAW10 */
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ (*main_output_format) = VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
+ break;
}
}
@@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct tegra_vi_channel *chan)
case V4L2_PIX_FMT_VYUY:
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_YVYU:
+ /* RAW8 */
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ /* RAW10 */
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SBGGR10:
if (chan->vflip)
chan->start_offset += stride * (height - 1);
if (chan->hflip)
@@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_1), base);
tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset);
break;
+ /* RAW8 */
+ case V4L2_PIX_FMT_SRGGB8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SBGGR8:
+ /* RAW10 */
+ case V4L2_PIX_FMT_SRGGB10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SBGGR10:
+ tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2), base);
+ tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2), base + chan->start_offset);
+ break;
}
}
@@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void *data)
static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
{
u32 output_fourcc = chan->format.pixelformat;
+ u32 data_type = chan->fmtinfo->img_dt;
int width = chan->format.width;
int height = chan->format.height;
int stride_l = chan->format.bytesperline;
int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
- int output_channel = OUT_1;
+ int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+ data_type == TEGRA_IMAGE_DT_RAW10) ?
+ OUT_2 : OUT_1;
int main_output_format;
int yuv_output_format;
@@ -580,6 +630,20 @@ static const struct tegra_video_format tegra20_video_formats[] = {
TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16, YVYU),
TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
+ TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
+ /* RAW 8 */
+ TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
+ TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
+ TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
+ TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
+ /* RAW 10 */
+ TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
+ TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
+ TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
+ TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
};
const struct tegra_vi_soc tegra20_vi_soc = {
@@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
{
struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&vip_chan->subdev);
+ u32 data_type = vi_chan->fmtinfo->img_dt;
int width = vi_chan->format.width;
int height = vi_chan->format.height;
- int output_channel = OUT_1;
+ int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
+ data_type == TEGRA_IMAGE_DT_RAW10) ?
+ OUT_2 : OUT_1;
unsigned int main_input_format;
unsigned int yuv_input_format;
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (14 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 1:16 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
` (2 subsequent siblings)
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Luma buffer stride is calculated by multiplying height in pixels of image
by bytes per line. Adjust that value accordingly.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/tegra20.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index b466fe7f4504..a06afe91d2de 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -496,7 +496,7 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
u32 data_type = chan->fmtinfo->img_dt;
int width = chan->format.width;
int height = chan->format.height;
- int stride_l = chan->format.bytesperline;
+ int stride_l = chan->format.bytesperline * height;
int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (15 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 20:30 ` Rob Herring
2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Document CSI hw block found in Tegra20 and Tegra30 SoC.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../display/tegra/nvidia,tegra210-csi.yaml | 78 +++++++++++++++----
1 file changed, 63 insertions(+), 15 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
index fa07a40d1004..a5669447a33b 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
@@ -16,30 +16,78 @@ properties:
compatible:
enum:
+ - nvidia,tegra20-csi
+ - nvidia,tegra30-csi
- nvidia,tegra210-csi
reg:
maxItems: 1
- clocks:
- items:
- - description: module clock
- - description: A/B lanes clock
- - description: C/D lanes clock
- - description: E lane clock
- - description: test pattern generator clock
-
- clock-names:
- items:
- - const: csi
- - const: cilab
- - const: cilcd
- - const: cile
- - const: csi_tpg
+ clocks: true
+ clock-names: true
power-domains:
maxItems: 1
+allOf:
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra20-csi
+ then:
+ properties:
+ clocks:
+ items:
+ - description: module clock
+
+ clock-names:
+ items:
+ - const: csi
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra30-csi
+ then:
+ properties:
+ clocks:
+ items:
+ - description: module clock
+ - description: PAD A clock
+ - description: PAD B clock
+
+ clock-names:
+ items:
+ - const: csi
+ - const: csia_pad
+ - const: csib_pad
+ - if:
+ properties:
+ compatible:
+ contains:
+ enum:
+ - nvidia,tegra210-csi
+ then:
+ properties:
+ clocks:
+ items:
+ - description: module clock
+ - description: A/B lanes clock
+ - description: C/D lanes clock
+ - description: E lane clock
+ - description: test pattern generator clock
+
+ clock-names:
+ items:
+ - const: csi
+ - const: cilab
+ - const: cilcd
+ - const: cile
+ - const: csi_tpg
+
additionalProperties: false
required:
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (16 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
18 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Add CSI node to Tegra20 and Tegra30 device trees.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
arch/arm/boot/dts/nvidia/tegra20.dtsi | 17 ++++++++++++++++-
arch/arm/boot/dts/nvidia/tegra30.dtsi | 19 ++++++++++++++++++-
2 files changed, 34 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/nvidia/tegra20.dtsi b/arch/arm/boot/dts/nvidia/tegra20.dtsi
index 606839fd40bb..d00786368115 100644
--- a/arch/arm/boot/dts/nvidia/tegra20.dtsi
+++ b/arch/arm/boot/dts/nvidia/tegra20.dtsi
@@ -64,7 +64,7 @@ mpe@54040000 {
vi@54080000 {
compatible = "nvidia,tegra20-vi";
- reg = <0x54080000 0x00040000>;
+ reg = <0x54080000 0x00000800>;
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA20_CLK_VI>;
resets = <&tegra_car 20>;
@@ -72,6 +72,21 @@ vi@54080000 {
power-domains = <&pd_venc>;
operating-points-v2 = <&vi_dvfs_opp_table>;
status = "disabled";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0x0 0x54080000 0x4000>;
+
+ csi@800 {
+ compatible = "nvidia,tegra20-csi";
+ reg = <0x800 0x200>;
+ clocks = <&tegra_car TEGRA20_CLK_CSI>;
+ clock-names = "csi";
+ power-domains = <&pd_venc>;
+
+ status = "disabled";
+ };
};
/* DSI MIPI calibration logic is a part of VI/CSI */
diff --git a/arch/arm/boot/dts/nvidia/tegra30.dtsi b/arch/arm/boot/dts/nvidia/tegra30.dtsi
index d9223bd7cf3b..c3e9212d5edf 100644
--- a/arch/arm/boot/dts/nvidia/tegra30.dtsi
+++ b/arch/arm/boot/dts/nvidia/tegra30.dtsi
@@ -151,7 +151,7 @@ mpe@54040000 {
vi@54080000 {
compatible = "nvidia,tegra30-vi";
- reg = <0x54080000 0x00040000>;
+ reg = <0x54080000 0x00000800>;
interrupts = <GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&tegra_car TEGRA30_CLK_VI>;
resets = <&tegra_car 20>;
@@ -162,6 +162,23 @@ vi@54080000 {
iommus = <&mc TEGRA_SWGROUP_VI>;
status = "disabled";
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ ranges = <0x0 0x54080000 0x4000>;
+
+ csi@800 {
+ compatible = "nvidia,tegra30-csi";
+ reg = <0x800 0x200>;
+ clocks = <&tegra_car TEGRA30_CLK_CSI>,
+ <&tegra_car TEGRA30_CLK_CSIA_PAD>,
+ <&tegra_car TEGRA30_CLK_CSIB_PAD>;
+ clock-names = "csi", "csia_pad", "csib_pad";
+ power-domains = <&pd_venc>;
+
+ status = "disabled";
+ };
};
/* DSI MIPI calibration logic is a part of VI/CSI */
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
` (17 preceding siblings ...)
2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
@ 2025-08-19 12:16 ` Svyatoslav Ryhel
2025-09-02 2:38 ` Mikko Perttunen
18 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-19 12:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/staging/media/tegra-video/csi.c | 12 +
drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
drivers/staging/media/tegra-video/vi.h | 2 +
drivers/staging/media/tegra-video/video.c | 2 +
4 files changed, 553 insertions(+), 38 deletions(-)
diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
index 2f9907a20db1..714ce52a793c 100644
--- a/drivers/staging/media/tegra-video/csi.c
+++ b/drivers/staging/media/tegra-video/csi.c
@@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
}
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+extern const struct tegra_csi_soc tegra20_csi_soc;
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+extern const struct tegra_csi_soc tegra30_csi_soc;
+#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
extern const struct tegra_csi_soc tegra210_csi_soc;
#endif
static const struct of_device_id tegra_csi_of_id_table[] = {
+#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
+#endif
+#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
+#endif
#if defined(CONFIG_ARCH_TEGRA_210_SOC)
{ .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
#endif
diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
index a06afe91d2de..e528ba280ae4 100644
--- a/drivers/staging/media/tegra-video/tegra20.c
+++ b/drivers/staging/media/tegra-video/tegra20.c
@@ -4,6 +4,9 @@
*
* Copyright (C) 2023 SKIDATA GmbH
* Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
+ *
+ * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
+ * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
*/
/*
@@ -12,12 +15,16 @@
*/
#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk/tegra.h>
#include <linux/delay.h>
#include <linux/host1x.h>
+#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/kthread.h>
#include <linux/v4l2-mediabus.h>
+#include "csi.h"
#include "vip.h"
#include "vi.h"
@@ -42,6 +49,9 @@ enum {
#define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
#define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
+#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n) (0x0070 + (n) * 8)
+#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n) (0x0074 + (n) * 8)
+
#define TEGRA_VI_VI_INPUT_CONTROL 0x0088
#define VI_INPUT_FIELD_DETECT BIT(27)
#define VI_INPUT_BT656 BIT(25)
@@ -87,6 +97,8 @@ enum {
#define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
#define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
#define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
+#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
#define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
#define TEGRA_VI_VIP_H_ACTIVE 0x00a4
@@ -151,8 +163,106 @@ enum {
#define TEGRA_VI_VI_RAISE 0x01ac
#define VI_VI_RAISE_ON_EDGE BIT(0)
+#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n) (0x01d8 + (n) * 8)
+#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n) (0x01dc + (n) * 8)
+#define TEGRA_VI_CSI_PP_H_ACTIVE(n) (0x01e8 + (n) * 8)
+#define TEGRA_VI_CSI_PP_V_ACTIVE(n) (0x01ec + (n) * 8)
+
+/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
+#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0000
+#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0008
+#define TEGRA_CSI_INPUT_STREAM_CONTROL(n) (0x0010 + (n) * 0x2c)
+#define CSI_SKIP_PACKET_THRESHOLD(n) (((n) & 0xff) << 16)
+#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n) (0x0018 + (n) * 0x2c)
+#define CSI_PP_PAD_FRAME_PAD0S (0 << 28)
+#define CSI_PP_PAD_FRAME_PAD1S (1 << 28)
+#define CSI_PP_PAD_FRAME_NOPAD (2 << 28)
+#define CSI_PP_HEADER_EC_ENABLE BIT(27)
+#define CSI_PP_PAD_SHORT_LINE_PAD0S (0 << 24)
+#define CSI_PP_PAD_SHORT_LINE_PAD1S (1 << 24)
+#define CSI_PP_PAD_SHORT_LINE_NOPAD (2 << 24)
+#define CSI_PP_EMBEDDED_DATA_EMBEDDED BIT(20)
+#define CSI_PP_OUTPUT_FORMAT_ARBITRARY (0 << 16)
+#define CSI_PP_OUTPUT_FORMAT_PIXEL (1 << 16)
+#define CSI_PP_OUTPUT_FORMAT_PIXEL_REP (2 << 16)
+#define CSI_PP_OUTPUT_FORMAT_STORE (3 << 16)
+#define CSI_PP_VIRTUAL_CHANNEL_ID(n) (((n) - 1) << 14)
+#define CSI_PP_DATA_TYPE(n) ((n) << 8)
+#define CSI_PP_CRC_CHECK_ENABLE BIT(7)
+#define CSI_PP_WORD_COUNT_HEADER BIT(6)
+#define CSI_PP_DATA_IDENTIFIER_ENABLE BIT(5)
+#define CSI_PP_PACKET_HEADER_SENT BIT(4)
+#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n) (0x001c + (n) * 0x2c)
+#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n) (0x0020 + (n) * 0x2c)
+#define TEGRA_CSI_PIXEL_STREAM_GAP(n) (0x0024 + (n) * 0x2c)
+#define CSI_PP_FRAME_MIN_GAP(n) (((n) & 0xffff) << 16)
+#define CSI_PP_LINE_MIN_GAP(n) (((n) & 0xffff))
+#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n) (0x0028 + (n) * 0x2c)
+#define CSI_PP_START_MARKER_FRAME_MAX(n) (((n) & 0xf) << 12)
+#define CSI_PP_START_MARKER_FRAME_MIN(n) (((n) & 0xf) << 8)
+#define CSI_PP_VSYNC_START_MARKER BIT(4)
+#define CSI_PP_SINGLE_SHOT BIT(2)
+#define CSI_PP_NOP 0
+#define CSI_PP_ENABLE 1
+#define CSI_PP_DISABLE 2
+#define CSI_PP_RST 3
+#define TEGRA_CSI_PHY_CIL_COMMAND 0x0068
+#define CSI_A_PHY_CIL_NOP 0x0
+#define CSI_A_PHY_CIL_ENABLE 0x1
+#define CSI_A_PHY_CIL_DISABLE 0x2
+#define CSI_A_PHY_CIL_ENABLE_MASK 0x3
+#define CSI_B_PHY_CIL_NOP (0x0 << 16)
+#define CSI_B_PHY_CIL_ENABLE (0x1 << 16)
+#define CSI_B_PHY_CIL_DISABLE (0x2 << 16)
+#define CSI_B_PHY_CIL_ENABLE_MASK (0x3 << 16)
+#define TEGRA_CSI_PHY_CIL_CONTROL0(n) (0x006c + (n) * 4)
+#define CSI_CONTINUOUS_CLOCK_MODE_ENABLE BIT(5)
+#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0078
+#define TEGRA_CSI_CSI_CIL_STATUS 0x007c
+#define CSI_MIPI_AUTO_CAL_DONE BIT(15)
+#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0080
+#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0084
+#define TEGRA_CSI_CSI_READONLY_STATUS 0x0088
+#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x008c
+#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0090
+#define TEGRA_CSI_CIL_PAD_CONFIG0(n) (0x0094 + (n) * 8)
+#define TEGRA_CSI_CIL_PAD_CONFIG1(n) (0x0098 + (n) * 8)
+#define TEGRA_CSI_CIL_PAD_CONFIG 0x00a4
+#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x00a8
+#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x00ac
+#define CSI_CIL_MIPI_CAL_STARTCAL BIT(31)
+#define CSI_CIL_MIPI_CAL_OVERIDE_A BIT(30)
+#define CSI_CIL_MIPI_CAL_OVERIDE_B BIT(30)
+#define CSI_CIL_MIPI_CAL_NOISE_FLT(n) (((n) & 0xf) << 26)
+#define CSI_CIL_MIPI_CAL_PRESCALE(n) (((n) & 0x3) << 24)
+#define CSI_CIL_MIPI_CAL_SEL_A BIT(21)
+#define CSI_CIL_MIPI_CAL_SEL_B BIT(21)
+#define CSI_CIL_MIPI_CAL_HSPDOS(n) (((n) & 0x1f) << 16)
+#define CSI_CIL_MIPI_CAL_HSPUOS(n) (((n) & 0x1f) << 8)
+#define CSI_CIL_MIPI_CAL_TERMOS(n) (((n) & 0x1f))
+#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x00b0
+#define TEGRA_CSI_CLKEN_OVERRIDE 0x00b4
+#define TEGRA_CSI_DEBUG_CONTROL 0x00b8
+#define CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED BIT(0)
+#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 BIT(4)
+#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 BIT(5)
+#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_2 BIT(6)
+#define CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v) ((v) << (8 + 8 * (n)))
+#define TEGRA_CSI_DEBUG_COUNTER(n) (0x00bc + (n) * 4)
+#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n) (0x00c8 + (n) * 4)
+#define CSI_PP_EXP_FRAME_HEIGHT(n) (((n) & 0x1fff) << 16)
+#define CSI_PP_MAX_CLOCKS(n) (((n) & 0xfff) << 4)
+#define CSI_PP_LINE_TIMEOUT_ENABLE BIT(0)
+#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x00d0
+#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x00d4
+#define CSI_PAD_DRIV_DN_REF(n) (((n) & 0x7) << 16)
+#define CSI_PAD_DRIV_UP_REF(n) (((n) & 0x7) << 8)
+#define CSI_PAD_TERM_REF(n) (((n) & 0x7) << 0)
+#define TEGRA_CSI_CSI_CILA_STATUS 0x00d8
+#define TEGRA_CSI_CSI_CILB_STATUS 0x00dc
+
/* --------------------------------------------------------------------------
- * VI
+ * Read and Write helpers
*/
static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
@@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
writel(val, chan->vi->iomem + addr);
}
+static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
+{
+ return readl(chan->vi->iomem + addr);
+}
+
+static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
+{
+ writel(val, csi_chan->csi->iomem + addr);
+}
+
+static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
+{
+ return readl(csi_chan->csi->iomem + addr);
+}
+
+/* --------------------------------------------------------------------------
+ * VI
+ */
+
/*
* Get the main input format (YUV/RGB...) and the YUV variant as values to
* be written into registers for the current VI input mbus code.
@@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
{
struct tegra_vi *vi = chan->vi;
- struct host1x_syncpt *out_sp;
+ struct host1x_syncpt *out_sp, *fs_sp;
out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
if (!out_sp)
- return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
+ return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
chan->mw_ack_sp[0] = out_sp;
+ fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
+ if (!fs_sp)
+ return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
+
+ chan->frame_start_sp[0] = fs_sp;
+
return 0;
}
static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
{
host1x_syncpt_put(chan->mw_ack_sp[0]);
+ host1x_syncpt_put(chan->frame_start_sp[0]);
}
static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
@@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
struct tegra_channel_buffer *buf)
{
+ struct v4l2_subdev *csi_subdev = NULL;
+ struct tegra_csi_channel *csi_chan = NULL;
+ u32 port;
int err;
- chan->next_out_sp_idx++;
+ csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
+ if (csi_subdev) {
+ /* CSI subdevs are named after nodes, channel@0 or channel@1 */
+ if (!strncmp(csi_subdev->name, "channel", 7)) {
+ csi_chan = to_csi_chan(csi_subdev);
+ port = csi_chan->csi_port_nums[0] & 1;
+ }
+ }
tegra20_channel_vi_buffer_setup(chan, buf);
- tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
+ if (csi_chan) {
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+ CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+ CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
+
+ chan->next_fs_sp_idx++;
+ err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
+ TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
+ if (err) {
+ host1x_syncpt_incr(chan->frame_start_sp[0]);
+ if (err != -ERESTARTSYS)
+ dev_err_ratelimited(&chan->video.dev,
+ "frame start syncpt timeout: %d\n", err);
+ }
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+ CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+ CSI_PP_DISABLE);
+ } else {
+ tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
+ }
- /* Wait for syncpt counter to reach frame start event threshold */
+ chan->next_out_sp_idx++;
err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
if (err) {
host1x_syncpt_incr(chan->mw_ack_sp[0]);
- dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
- release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
- return err;
+ if (err != -ERESTARTSYS)
+ dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
}
- tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
- VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
+ if (!csi_chan)
+ tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
+ VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
release_buffer(chan, buf, VB2_BUF_STATE_DONE);
- return 0;
+ return err;
}
static int tegra20_chan_capture_kthread_start(void *data)
@@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
data_type == TEGRA_IMAGE_DT_RAW10) ?
OUT_2 : OUT_1;
- int main_output_format;
- int yuv_output_format;
-
- tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
-
- /*
- * Set up low pass filter. Use 0x240 for chromaticity and 0x240
- * for luminance, which is the default and means not to touch
- * anything.
- */
- tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
- 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
- 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
-
- /* Set up raise-on-edge, so we get an interrupt on end of frame. */
- tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
-
- tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
- (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
- (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
- yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
- main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
/* Set up frame size */
tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
@@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
}
+static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
+{
+ struct tegra_csi *csi = csi_chan->csi;
+ void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
+ unsigned int port = csi_chan->csi_port_nums[0] & 1;
+ u32 value, pp, cil;
+ int ret;
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
+ CSI_CIL_MIPI_CAL_HSPDOS(4) |
+ CSI_CIL_MIPI_CAL_HSPUOS(3) |
+ CSI_CIL_MIPI_CAL_TERMOS(0));
+ tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
+ CSI_PAD_DRIV_DN_REF(5) |
+ CSI_PAD_DRIV_UP_REF(7) |
+ CSI_PAD_TERM_REF(0));
+
+ /* CSI B */
+ value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
+ CSI_CIL_MIPI_CAL_HSPUOS(0) |
+ CSI_CIL_MIPI_CAL_TERMOS(4);
+
+ if (port == PORT_B || csi_chan->numlanes == 4)
+ value |= CSI_CIL_MIPI_CAL_SEL_B;
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
+
+ /* CSI A */
+ value = CSI_CIL_MIPI_CAL_STARTCAL |
+ CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
+ CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
+ CSI_CIL_MIPI_CAL_HSPDOS(0) |
+ CSI_CIL_MIPI_CAL_HSPUOS(0) |
+ CSI_CIL_MIPI_CAL_TERMOS(4);
+
+ if (port == PORT_A)
+ value |= CSI_CIL_MIPI_CAL_SEL_A;
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
+
+ ret = readl_relaxed_poll_timeout(cil_status_reg, value,
+ value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
+ if (ret < 0) {
+ dev_warn(csi->dev, "MIPI calibration timeout!\n");
+ goto exit;
+ }
+
+ /* clear status */
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
+ ret = readl_relaxed_poll_timeout(cil_status_reg, value,
+ !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
+ if (ret < 0) {
+ dev_warn(csi->dev, "MIPI calibration status timeout!\n");
+ goto exit;
+ }
+
+ pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+ cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
+ if (pp | cil) {
+ dev_warn(csi->dev, "Calibration status not been cleared!\n");
+ ret = -EINVAL;
+ goto exit;
+ }
+
+exit:
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
+
+ /* un-select to avoid interference with DSI */
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
+ CSI_CIL_MIPI_CAL_HSPDOS(0) |
+ CSI_CIL_MIPI_CAL_HSPUOS(0) |
+ CSI_CIL_MIPI_CAL_TERMOS(4));
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
+ CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
+ CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
+ CSI_CIL_MIPI_CAL_HSPDOS(0) |
+ CSI_CIL_MIPI_CAL_HSPUOS(0) |
+ CSI_CIL_MIPI_CAL_TERMOS(4));
+
+ return ret;
+}
+
static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
{
struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
struct media_pipeline *pipe = &chan->video.pipe;
+ struct v4l2_subdev *csi_subdev, *src_subdev;
+ struct tegra_csi_channel *csi_chan = NULL;
int err;
+ csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
+ if (csi_subdev) {
+ if (!strncmp(csi_subdev->name, "channel", 7))
+ csi_chan = to_csi_chan(csi_subdev);
+ }
+
+ chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
err = video_device_pipeline_start(&chan->video, pipe);
if (err)
goto error_pipeline_start;
- tegra20_camera_capture_setup(chan);
+ /*
+ * Set up low pass filter. Use 0x240 for chromaticity and 0x240
+ * for luminance, which is the default and means not to touch
+ * anything.
+ */
+ tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
+ 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
+ 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
+
+ /* Set up raise-on-edge, so we get an interrupt on end of frame. */
+ tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
err = tegra_channel_set_stream(chan, true);
if (err)
goto error_set_stream;
+ tegra20_camera_capture_setup(chan);
+
+ if (csi_chan) {
+ /*
+ * TRM has incorrectly documented to wait for done status from
+ * calibration logic after CSI interface power on.
+ * As per the design, calibration results are latched and applied
+ * to the pads only when the link is in LP11 state which will happen
+ * during the sensor stream-on.
+ * CSI subdev stream-on triggers start of MIPI pads calibration.
+ * Wait for calibration to finish here after sensor subdev stream-on.
+ */
+ src_subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (!src_subdev->s_stream_enabled) {
+ err = v4l2_subdev_call(src_subdev, video, s_stream, true);
+ if (err < 0 && err != -ENOIOCTLCMD)
+ goto error_set_stream;
+ }
+
+ tegra20_csi_pad_calibration(csi_chan);
+ }
+
chan->sequence = 0;
chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
@@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
{
struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
+ struct v4l2_subdev *src_subdev;
if (chan->kthread_start_capture) {
kthread_stop(chan->kthread_start_capture);
chan->kthread_start_capture = NULL;
}
+ src_subdev = tegra_channel_get_remote_source_subdev(chan);
+ if (src_subdev->s_stream_enabled)
+ v4l2_subdev_call(src_subdev, video, s_stream, false);
+
tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
tegra_channel_set_stream(chan, false);
video_device_pipeline_stop(&chan->video);
@@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
.default_video_format = &tegra20_video_formats[0],
.ops = &tegra20_vi_ops,
.hw_revision = 1,
- .vi_max_channels = 1, /* parallel input (VIP) */
+ .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
.vi_max_clk_hz = 450000000,
.has_h_v_flip = true,
};
+/* --------------------------------------------------------------------------
+ * CSI
+ */
+static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
+{
+ tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
+ CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
+ CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
+ CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
+}
+
+static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
+ u8 portno)
+{
+ struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
+ int width = vi_chan->format.width;
+ int height = vi_chan->format.height;
+ u32 data_type = vi_chan->fmtinfo->img_dt;
+ u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
+ int output_channel = OUT_1;
+
+ unsigned int main_output_format, yuv_output_format;
+ unsigned int port = portno & 1;
+ u32 value;
+
+ tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
+
+ switch (data_type) {
+ case TEGRA_IMAGE_DT_RAW8:
+ case TEGRA_IMAGE_DT_RAW10:
+ output_channel = OUT_2;
+ if (port == PORT_A)
+ main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
+ else
+ main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
+ break;
+ }
+
+ tegra20_csi_capture_clean(csi_chan);
+
+ /* CSI port cleanup */
+ tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
+ tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
+ tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
+ CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
+ CSI_PP_EXP_FRAME_HEIGHT(height) |
+ CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
+ CSI_PP_LINE_TIMEOUT_ENABLE);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
+ CSI_PP_OUTPUT_FORMAT_PIXEL |
+ CSI_PP_DATA_TYPE(data_type) |
+ CSI_PP_CRC_CHECK_ENABLE |
+ CSI_PP_WORD_COUNT_HEADER |
+ CSI_PP_DATA_IDENTIFIER_ENABLE |
+ CSI_PP_PACKET_HEADER_SENT |
+ port);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
+ CSI_SKIP_PACKET_THRESHOLD(0x3f) |
+ (csi_chan->numlanes - 1));
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
+ CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
+ 0x5); /* Clock settle time */
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
+ VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
+ host1x_syncpt_id(vi_chan->frame_start_sp[0])
+ << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
+ VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
+ host1x_syncpt_id(vi_chan->mw_ack_sp[0])
+ << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
+
+ value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
+ CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+ CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+ CSI_PP_DISABLE);
+
+ tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
+ (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
+ (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
+ yuv_output_format | main_output_format);
+
+ return 0;
+};
+
+static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
+{
+ struct tegra_csi *csi = csi_chan->csi;
+ unsigned int port = portno & 1;
+ u32 value;
+
+ value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+ dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
+
+ value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
+ dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
+ tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
+
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
+ CSI_PP_START_MARKER_FRAME_MAX(0xf) |
+ CSI_PP_DISABLE);
+
+ if (csi_chan->numlanes == 4) {
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
+ CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
+ } else {
+ value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
+ CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
+ tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
+ }
+}
+
+static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
+{
+ u8 *portnos = csi_chan->csi_port_nums;
+ int ret, i;
+
+ for (i = 0; i < csi_chan->numgangports; i++) {
+ ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
+ if (ret)
+ goto stream_start_fail;
+ }
+
+ return 0;
+
+stream_start_fail:
+ for (i = i - 1; i >= 0; i--)
+ tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
+
+ return ret;
+}
+
+static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
+{
+ u8 *portnos = csi_chan->csi_port_nums;
+ int i;
+
+ for (i = 0; i < csi_chan->numgangports; i++)
+ tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
+}
+
+/* Tegra20 CSI operations */
+static const struct tegra_csi_ops tegra20_csi_ops = {
+ .csi_start_streaming = tegra20_csi_start_streaming,
+ .csi_stop_streaming = tegra20_csi_stop_streaming,
+};
+
+static const char * const tegra20_csi_clks[] = {
+ "csi",
+};
+
+/* Tegra20 CSI SoC data */
+const struct tegra_csi_soc tegra20_csi_soc = {
+ .ops = &tegra20_csi_ops,
+ .csi_max_channels = 2, /* CSI-A and CSI-B */
+ .clk_names = tegra20_csi_clks,
+ .num_clks = ARRAY_SIZE(tegra20_csi_clks),
+ .has_mipi_calibration = false,
+};
+
+static const char * const tegra30_csi_clks[] = {
+ "csi",
+ "csia_pad",
+ "csib_pad",
+};
+
+/* Tegra30 CSI SoC data */
+const struct tegra_csi_soc tegra30_csi_soc = {
+ .ops = &tegra20_csi_ops,
+ .csi_max_channels = 2, /* CSI-A and CSI-B */
+ .clk_names = tegra30_csi_clks,
+ .num_clks = ARRAY_SIZE(tegra30_csi_clks),
+ .has_mipi_calibration = false,
+};
+
/* --------------------------------------------------------------------------
* VIP
*/
@@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
data_type == TEGRA_IMAGE_DT_RAW10) ?
OUT_2 : OUT_1;
- unsigned int main_input_format;
- unsigned int yuv_input_format;
+ unsigned int main_input_format, yuv_input_format;
+ unsigned int main_output_format, yuv_output_format;
tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
+ tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
@@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
+ tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
+ (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
+ (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
+ yuv_output_format | main_output_format);
+
return 0;
}
diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
index cac0c0d0e225..c02517c9e09b 100644
--- a/drivers/staging/media/tegra-video/vi.h
+++ b/drivers/staging/media/tegra-video/vi.h
@@ -127,6 +127,7 @@ struct tegra_vi {
* frame through host1x syncpoint counters (On Tegra20 used for the
* OUT_1 syncpt)
* @sp_incr_lock: protects cpu syncpoint increment.
+ * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
* @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
*
* @kthread_start_capture: kthread to start capture of single frame when
@@ -191,6 +192,7 @@ struct tegra_vi_channel {
/* protects the cpu syncpoint increment */
spinlock_t sp_incr_lock[GANG_PORTS_MAX];
u32 next_out_sp_idx;
+ u32 next_fs_sp_idx;
struct task_struct *kthread_start_capture;
wait_queue_head_t start_wait;
diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
index a25885f93cd7..8fa660431eb0 100644
--- a/drivers/staging/media/tegra-video/video.c
+++ b/drivers/staging/media/tegra-video/video.c
@@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
static const struct of_device_id host1x_video_subdevs[] = {
#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
+ { .compatible = "nvidia,tegra20-csi", },
{ .compatible = "nvidia,tegra20-vip", },
{ .compatible = "nvidia,tegra20-vi", },
#endif
#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
+ { .compatible = "nvidia,tegra30-csi", },
{ .compatible = "nvidia,tegra30-vip", },
{ .compatible = "nvidia,tegra30-vi", },
#endif
--
2.48.1
^ permalink raw reply related [flat|nested] 59+ messages in thread
* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
@ 2025-08-19 20:27 ` Rob Herring
2025-08-20 5:36 ` Svyatoslav Ryhel
2025-08-29 6:42 ` Svyatoslav Ryhel
0 siblings, 2 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-19 20:27 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
That's not what the compatible schema says. 'exactly the same' implies a
fallback to whatever it is exactly the same as.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> .../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> index 14294edb8d8c..39e9b3297dbd 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> @@ -13,6 +13,7 @@ properties:
> compatible:
> enum:
> - nvidia,tegra20-vip
> + - nvidia,tegra30-vip
>
> ports:
> $ref: /schemas/graph.yaml#/properties/ports
> --
> 2.48.1
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
@ 2025-08-19 20:30 ` Rob Herring
2025-08-20 5:39 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Rob Herring @ 2025-08-19 20:30 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> Document CSI hw block found in Tegra20 and Tegra30 SoC.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> .../display/tegra/nvidia,tegra210-csi.yaml | 78 +++++++++++++++----
> 1 file changed, 63 insertions(+), 15 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> index fa07a40d1004..a5669447a33b 100644
> --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> @@ -16,30 +16,78 @@ properties:
>
> compatible:
> enum:
> + - nvidia,tegra20-csi
> + - nvidia,tegra30-csi
> - nvidia,tegra210-csi
>
> reg:
> maxItems: 1
>
> - clocks:
> - items:
> - - description: module clock
> - - description: A/B lanes clock
> - - description: C/D lanes clock
> - - description: E lane clock
> - - description: test pattern generator clock
> -
> - clock-names:
> - items:
> - - const: csi
> - - const: cilab
> - - const: cilcd
> - - const: cile
> - - const: csi_tpg
> + clocks: true
> + clock-names: true
>
> power-domains:
> maxItems: 1
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - nvidia,tegra20-csi
> + then:
> + properties:
> + clocks:
> + items:
> + - description: module clock
> +
> + clock-names:
> + items:
> + - const: csi
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - nvidia,tegra30-csi
> + then:
> + properties:
> + clocks:
> + items:
> + - description: module clock
> + - description: PAD A clock
> + - description: PAD B clock
> +
> + clock-names:
> + items:
> + - const: csi
> + - const: csia_pad
> + - const: csib_pad
> + - if:
> + properties:
> + compatible:
> + contains:
> + enum:
> + - nvidia,tegra210-csi
> + then:
> + properties:
> + clocks:
> + items:
> + - description: module clock
> + - description: A/B lanes clock
> + - description: C/D lanes clock
> + - description: E lane clock
> + - description: test pattern generator clock
> +
> + clock-names:
> + items:
> + - const: csi
> + - const: cilab
> + - const: cilcd
> + - const: cile
> + - const: csi_tpg
> +
This is longer that what's the same. I think this should be a separate
schema doc.
Rob
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
2025-08-19 20:27 ` Rob Herring
@ 2025-08-20 5:36 ` Svyatoslav Ryhel
2025-08-29 6:42 ` Svyatoslav Ryhel
1 sibling, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-20 5:36 UTC (permalink / raw)
To: Rob Herring
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 19 серп. 2025 р. о 23:27 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> > Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
>
> That's not what the compatible schema says. 'exactly the same' implies a
> fallback to whatever it is exactly the same as.
>
I will reword commit message. Thank you.
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
2025-08-19 20:30 ` Rob Herring
@ 2025-08-20 5:39 ` Svyatoslav Ryhel
2025-08-22 14:06 ` Rob Herring
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-20 5:39 UTC (permalink / raw)
To: Rob Herring
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 19 серп. 2025 р. о 23:30 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> > Document CSI hw block found in Tegra20 and Tegra30 SoC.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> > .../display/tegra/nvidia,tegra210-csi.yaml | 78 +++++++++++++++----
> > 1 file changed, 63 insertions(+), 15 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > index fa07a40d1004..a5669447a33b 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > @@ -16,30 +16,78 @@ properties:
> >
> > compatible:
> > enum:
> > + - nvidia,tegra20-csi
> > + - nvidia,tegra30-csi
> > - nvidia,tegra210-csi
> >
> > reg:
> > maxItems: 1
> >
> > - clocks:
> > - items:
> > - - description: module clock
> > - - description: A/B lanes clock
> > - - description: C/D lanes clock
> > - - description: E lane clock
> > - - description: test pattern generator clock
> > -
> > - clock-names:
> > - items:
> > - - const: csi
> > - - const: cilab
> > - - const: cilcd
> > - - const: cile
> > - - const: csi_tpg
> > + clocks: true
> > + clock-names: true
> >
> > power-domains:
> > maxItems: 1
> >
> > +allOf:
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - nvidia,tegra20-csi
> > + then:
> > + properties:
> > + clocks:
> > + items:
> > + - description: module clock
> > +
> > + clock-names:
> > + items:
> > + - const: csi
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - nvidia,tegra30-csi
> > + then:
> > + properties:
> > + clocks:
> > + items:
> > + - description: module clock
> > + - description: PAD A clock
> > + - description: PAD B clock
> > +
> > + clock-names:
> > + items:
> > + - const: csi
> > + - const: csia_pad
> > + - const: csib_pad
> > + - if:
> > + properties:
> > + compatible:
> > + contains:
> > + enum:
> > + - nvidia,tegra210-csi
> > + then:
> > + properties:
> > + clocks:
> > + items:
> > + - description: module clock
> > + - description: A/B lanes clock
> > + - description: C/D lanes clock
> > + - description: E lane clock
> > + - description: test pattern generator clock
> > +
> > + clock-names:
> > + items:
> > + - const: csi
> > + - const: cilab
> > + - const: cilcd
> > + - const: cile
> > + - const: csi_tpg
> > +
>
> This is longer that what's the same. I think this should be a separate
> schema doc.
>
CSI hw block configuration is similar between generations, the main
difference is the amount of clocks routed. Not sure if it is worth it
to create duplicates with sole difference in number of clocks used.
> Rob
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
@ 2025-08-22 13:59 ` Rob Herring
2025-08-27 4:19 ` Mikko Perttunen
1 sibling, 0 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-22 13:59 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Tue, Aug 19, 2025 at 03:16:14PM +0300, Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> Add ids for these clocks.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> include/dt-bindings/clock/tegra30-car.h | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/include/dt-bindings/clock/tegra30-car.h b/include/dt-bindings/clock/tegra30-car.h
> index f193663e6f28..14b83e90a0fc 100644
> --- a/include/dt-bindings/clock/tegra30-car.h
> +++ b/include/dt-bindings/clock/tegra30-car.h
> @@ -271,6 +271,8 @@
> #define TEGRA30_CLK_AUDIO3_MUX 306
> #define TEGRA30_CLK_AUDIO4_MUX 307
> #define TEGRA30_CLK_SPDIF_MUX 308
> -#define TEGRA30_CLK_CLK_MAX 309
> +#define TEGRA30_CLK_CSIA_PAD 309
> +#define TEGRA30_CLK_CSIB_PAD 310
> +#define TEGRA30_CLK_CLK_MAX 311
Please drop the MAX. This header is ABI and if a define can change, then
it's not ABI.
Rob
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI
2025-08-20 5:39 ` Svyatoslav Ryhel
@ 2025-08-22 14:06 ` Rob Herring
0 siblings, 0 replies; 59+ messages in thread
From: Rob Herring @ 2025-08-22 14:06 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Wed, Aug 20, 2025 at 08:39:36AM +0300, Svyatoslav Ryhel wrote:
> вт, 19 серп. 2025 р. о 23:30 Rob Herring <robh@kernel.org> пише:
> >
> > On Tue, Aug 19, 2025 at 03:16:29PM +0300, Svyatoslav Ryhel wrote:
> > > Document CSI hw block found in Tegra20 and Tegra30 SoC.
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > > .../display/tegra/nvidia,tegra210-csi.yaml | 78 +++++++++++++++----
> > > 1 file changed, 63 insertions(+), 15 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > index fa07a40d1004..a5669447a33b 100644
> > > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra210-csi.yaml
> > > @@ -16,30 +16,78 @@ properties:
> > >
> > > compatible:
> > > enum:
> > > + - nvidia,tegra20-csi
> > > + - nvidia,tegra30-csi
> > > - nvidia,tegra210-csi
> > >
> > > reg:
> > > maxItems: 1
> > >
> > > - clocks:
> > > - items:
> > > - - description: module clock
> > > - - description: A/B lanes clock
> > > - - description: C/D lanes clock
> > > - - description: E lane clock
> > > - - description: test pattern generator clock
> > > -
> > > - clock-names:
> > > - items:
> > > - - const: csi
> > > - - const: cilab
> > > - - const: cilcd
> > > - - const: cile
> > > - - const: csi_tpg
> > > + clocks: true
> > > + clock-names: true
> > >
> > > power-domains:
> > > maxItems: 1
> > >
> > > +allOf:
> > > + - if:
> > > + properties:
> > > + compatible:
> > > + contains:
> > > + enum:
> > > + - nvidia,tegra20-csi
> > > + then:
> > > + properties:
> > > + clocks:
> > > + items:
> > > + - description: module clock
> > > +
> > > + clock-names:
> > > + items:
> > > + - const: csi
> > > + - if:
> > > + properties:
> > > + compatible:
> > > + contains:
> > > + enum:
> > > + - nvidia,tegra30-csi
> > > + then:
> > > + properties:
> > > + clocks:
> > > + items:
> > > + - description: module clock
> > > + - description: PAD A clock
> > > + - description: PAD B clock
> > > +
> > > + clock-names:
> > > + items:
> > > + - const: csi
> > > + - const: csia_pad
> > > + - const: csib_pad
> > > + - if:
> > > + properties:
> > > + compatible:
> > > + contains:
> > > + enum:
> > > + - nvidia,tegra210-csi
> > > + then:
> > > + properties:
> > > + clocks:
> > > + items:
> > > + - description: module clock
> > > + - description: A/B lanes clock
> > > + - description: C/D lanes clock
> > > + - description: E lane clock
> > > + - description: test pattern generator clock
> > > +
> > > + clock-names:
> > > + items:
> > > + - const: csi
> > > + - const: cilab
> > > + - const: cilcd
> > > + - const: cile
> > > + - const: csi_tpg
> > > +
> >
> > This is longer that what's the same. I think this should be a separate
> > schema doc.
> >
>
> CSI hw block configuration is similar between generations, the main
> difference is the amount of clocks routed. Not sure if it is worth it
> to create duplicates with sole difference in number of clocks used.
If the clock names were at least the same I might agree, but the only
common one is 'csi'. How similar the h/w is doesn't matter, how similar
the binding is is what matters.
Rob
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
@ 2025-08-27 4:09 ` Mikko Perttunen
2025-08-27 4:32 ` Svyatoslav
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 4:09 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> CSUS clock is required to be enabled on camera device configuration or
> else camera module refuses to initiate properly.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/clk/tegra/clk-tegra20.c | 1 +
> drivers/clk/tegra/clk-tegra30.c | 1 +
> 2 files changed, 2 insertions(+)
>
> diff --git a/drivers/clk/tegra/clk-tegra20.c
> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> --- a/drivers/clk/tegra/clk-tegra20.c
> +++ b/drivers/clk/tegra/clk-tegra20.c
> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> /* must be the last entry */
> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> };
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> /* must be the last entry */
> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> };
I looked into what this clock does and it seems to be a gate for the CSUS pin,
which provides an output clock for camera sensors (VI MCLK). Default source
seems to be PLLC_OUT1. It would be good to note that on the commit message, as
I can't find any documentation about the CSUS clock elsewhere.
What is the 6MHz rate based on?
Since this seems to be a clock consumed by the sensor, it seems to me that
rather than making it always on, we could point to it in the sensor's device
tree entry.
Cheers,
Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
2025-08-22 13:59 ` Rob Herring
@ 2025-08-27 4:19 ` Mikko Perttunen
2025-08-27 4:28 ` Svyatoslav
1 sibling, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 4:19 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> Add ids for these clocks.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> include/dt-bindings/clock/tegra30-car.h | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/include/dt-bindings/clock/tegra30-car.h
> b/include/dt-bindings/clock/tegra30-car.h index f193663e6f28..14b83e90a0fc
> 100644
> --- a/include/dt-bindings/clock/tegra30-car.h
> +++ b/include/dt-bindings/clock/tegra30-car.h
> @@ -271,6 +271,8 @@
> #define TEGRA30_CLK_AUDIO3_MUX 306
> #define TEGRA30_CLK_AUDIO4_MUX 307
> #define TEGRA30_CLK_SPDIF_MUX 308
> -#define TEGRA30_CLK_CLK_MAX 309
> +#define TEGRA30_CLK_CSIA_PAD 309
> +#define TEGRA30_CLK_CSIB_PAD 310
> +#define TEGRA30_CLK_CLK_MAX 311
>
> #endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
The commit message refers to tegra20, but contents are tegra30.
Regarding the CLK_MAX define, I agree that it would be better to get rid of
it. Perhaps you can check if it would be reasonable to calculate it
dynamically in the driver, but a define and sanity check in the driver would
work too, I think.
Cheers,
Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
@ 2025-08-27 4:26 ` Mikko Perttunen
2025-08-29 0:44 ` Mikko Perttunen
1 sibling, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 4:26 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
> for correct work of CSI block.
'pad' is just an english word, so please write it in lowercase. Same applies
to the previous patch.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 70e85e2949e0..f033eb1ac26a 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -153,6 +153,7 @@ static unsigned long input_freq;
>
> static DEFINE_SPINLOCK(cml_lock);
> static DEFINE_SPINLOCK(pll_d_lock);
> +static DEFINE_SPINLOCK(pll_d2_lock);
>
> #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
> _clk_num, _gate_flags, _clk_id) \
> @@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
>
> /* PLLD2 */
> clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base,
0,
> - &pll_d2_params, NULL);
> + &pll_d2_params, &pll_d2_lock);
Please mention adding this lock in the commit message.
> clks[TEGRA30_CLK_PLL_D2] = clk;
>
> /* PLLD2_OUT0 */
> @@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
> 0, 48, periph_clk_enb_refcnt);
> clks[TEGRA30_CLK_DSIA] = clk;
>
> + /* csia_pad */
> + clk = clk_register_gate(NULL, "csia_pad", "pll_d",
CLK_SET_RATE_PARENT,
> + clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
> + clk_register_clkdev(clk, "csia_pad", NULL);
> + clks[TEGRA30_CLK_CSIA_PAD] = clk;
> +
> + /* csib_pad */
> + clk = clk_register_gate(NULL, "csib_pad", "pll_d2",
CLK_SET_RATE_PARENT,
> + clk_base + PLLD2_BASE, 26, 0,
&pll_d2_lock);
> + clk_register_clkdev(clk, "csib_pad", NULL);
> + clks[TEGRA30_CLK_CSIB_PAD] = clk;
> +
> /* pcie */
> clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
> 70, periph_clk_enb_refcnt);
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-27 4:19 ` Mikko Perttunen
@ 2025-08-27 4:28 ` Svyatoslav
2025-08-27 10:27 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27 4:28 UTC (permalink / raw)
To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
>> Add ids for these clocks.
>>
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>> include/dt-bindings/clock/tegra30-car.h | 4 +++-
>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/include/dt-bindings/clock/tegra30-car.h
>> b/include/dt-bindings/clock/tegra30-car.h index f193663e6f28..14b83e90a0fc
>> 100644
>> --- a/include/dt-bindings/clock/tegra30-car.h
>> +++ b/include/dt-bindings/clock/tegra30-car.h
>> @@ -271,6 +271,8 @@
>> #define TEGRA30_CLK_AUDIO3_MUX 306
>> #define TEGRA30_CLK_AUDIO4_MUX 307
>> #define TEGRA30_CLK_SPDIF_MUX 308
>> -#define TEGRA30_CLK_CLK_MAX 309
>> +#define TEGRA30_CLK_CSIA_PAD 309
>> +#define TEGRA30_CLK_CSIB_PAD 310
>> +#define TEGRA30_CLK_CLK_MAX 311
>>
>> #endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
>
>The commit message refers to tegra20, but contents are tegra30.
>
My, bad, it should be tegra30
>Regarding the CLK_MAX define, I agree that it would be better to get rid of
>it. Perhaps you can check if it would be reasonable to calculate it
>dynamically in the driver, but a define and sanity check in the driver would
>work too, I think.
>
It is not unreasonable, but moving this elsewhere may cause issues with adding new clocks. Addind new clocks would require updating not only header but also a place where max clocks are moved to and ai am not sure how can I dinamically calculate amount of clocks in the driver without updating both header and driver with each new clock added. Maybe you can propose a method?
>Cheers,
>Mikko
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
@ 2025-08-27 4:29 ` Mikko Perttunen
2025-08-27 4:47 ` Svyatoslav
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 4:29 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
> Tegra30.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/Makefile | 1 +
> drivers/staging/media/tegra-video/vi.c | 3 +++
> drivers/staging/media/tegra-video/vi.h | 2 +-
> drivers/staging/media/tegra-video/video.c | 4 ++++
> drivers/staging/media/tegra-video/vip.c | 5 ++++-
> 5 files changed, 13 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/Makefile
> b/drivers/staging/media/tegra-video/Makefile index
> 6c7552e05109..96380b5dbd8b 100644
> --- a/drivers/staging/media/tegra-video/Makefile
> +++ b/drivers/staging/media/tegra-video/Makefile
> @@ -6,5 +6,6 @@ tegra-video-objs := \
> csi.o
>
> tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o
> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra20.o
> tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
> obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
> diff --git a/drivers/staging/media/tegra-video/vi.c
> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
> 100644
> --- a/drivers/staging/media/tegra-video/vi.c
> +++ b/drivers/staging/media/tegra-video/vi.c
> @@ -1959,6 +1959,9 @@ static const struct of_device_id
> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> { .compatible = "nvidia,tegra20-vi", .data = &tegra20_vi_soc },
> #endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> + { .compatible = "nvidia,tegra30-vi", .data = &tegra20_vi_soc },
> +#endif
> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> { .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
> #endif
> diff --git a/drivers/staging/media/tegra-video/vi.h
> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
> 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -296,7 +296,7 @@ struct tegra_video_format {
> u32 fourcc;
> };
>
> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
> extern const struct tegra_vi_soc tegra20_vi_soc;
> #endif
> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> diff --git a/drivers/staging/media/tegra-video/video.c
> b/drivers/staging/media/tegra-video/video.c index
> 074ad0dc56ca..a25885f93cd7 100644
> --- a/drivers/staging/media/tegra-video/video.c
> +++ b/drivers/staging/media/tegra-video/video.c
> @@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[]
> = { { .compatible = "nvidia,tegra20-vip", },
> { .compatible = "nvidia,tegra20-vi", },
> #endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> + { .compatible = "nvidia,tegra30-vip", },
> + { .compatible = "nvidia,tegra30-vi", },
> +#endif
> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> { .compatible = "nvidia,tegra210-csi", },
> { .compatible = "nvidia,tegra210-vi", },
> diff --git a/drivers/staging/media/tegra-video/vip.c
> b/drivers/staging/media/tegra-video/vip.c index 5ec717f3afd5..00e08a9971d5
> 100644
> --- a/drivers/staging/media/tegra-video/vip.c
> +++ b/drivers/staging/media/tegra-video/vip.c
> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
> *pdev) pm_runtime_disable(&pdev->dev);
> }
>
> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
> extern const struct tegra_vip_soc tegra20_vip_soc;
> #endif
>
> static const struct of_device_id tegra_vip_of_id_table[] = {
> #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> { .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> + { .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
> #endif
> { }
> };
If tegra30-vip is compatible with tegra20-vip, we don't need to add the
compatible string into the driver. Just mark it as 'compatible =
"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob
alluded, have this compat string pair as an option in the device tree schema).
Cheers,
Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-27 4:09 ` Mikko Perttunen
@ 2025-08-27 4:32 ` Svyatoslav
2025-08-27 10:36 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27 4:32 UTC (permalink / raw)
To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> CSUS clock is required to be enabled on camera device configuration or
>> else camera module refuses to initiate properly.
>>
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>> drivers/clk/tegra/clk-tegra20.c | 1 +
>> drivers/clk/tegra/clk-tegra30.c | 1 +
>> 2 files changed, 2 insertions(+)
>>
>> diff --git a/drivers/clk/tegra/clk-tegra20.c
>> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
>> --- a/drivers/clk/tegra/clk-tegra20.c
>> +++ b/drivers/clk/tegra/clk-tegra20.c
>> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
>> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
>> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
>> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
>> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
>> /* must be the last entry */
>> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
>> };
>> diff --git a/drivers/clk/tegra/clk-tegra30.c
>> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
>> --- a/drivers/clk/tegra/clk-tegra30.c
>> +++ b/drivers/clk/tegra/clk-tegra30.c
>> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
>> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
>> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
>> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
>> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
>> /* must be the last entry */
>> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
>> };
>
>I looked into what this clock does and it seems to be a gate for the CSUS pin,
>which provides an output clock for camera sensors (VI MCLK). Default source
>seems to be PLLC_OUT1. It would be good to note that on the commit message, as
>I can't find any documentation about the CSUS clock elsewhere.
>
>What is the 6MHz rate based on?
>
6mhz is the statistic value which I was not able to alter while testing. I have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
>Since this seems to be a clock consumed by the sensor, it seems to me that
>rather than making it always on, we could point to it in the sensor's device
>tree entry.
>
Sensor device tree uses vi_sensor as clocks source and sensor drivers don't support multiple linked clocks.
>Cheers,
>Mikko
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
2025-08-27 4:29 ` Mikko Perttunen
@ 2025-08-27 4:47 ` Svyatoslav
2025-08-29 0:56 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav @ 2025-08-27 4:47 UTC (permalink / raw)
To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
27 серпня 2025 р. 07:29:40 GMT+03:00, Mikko Perttunen <mperttunen@nvidia.com> пише:
>On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
>> Tegra30.
>>
>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>> ---
>> drivers/staging/media/tegra-video/Makefile | 1 +
>> drivers/staging/media/tegra-video/vi.c | 3 +++
>> drivers/staging/media/tegra-video/vi.h | 2 +-
>> drivers/staging/media/tegra-video/video.c | 4 ++++
>> drivers/staging/media/tegra-video/vip.c | 5 ++++-
>> 5 files changed, 13 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/staging/media/tegra-video/Makefile
>> b/drivers/staging/media/tegra-video/Makefile index
>> 6c7552e05109..96380b5dbd8b 100644
>> --- a/drivers/staging/media/tegra-video/Makefile
>> +++ b/drivers/staging/media/tegra-video/Makefile
>> @@ -6,5 +6,6 @@ tegra-video-objs := \
>> csi.o
>>
>> tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o
>> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra20.o
>> tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
>> obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
>> diff --git a/drivers/staging/media/tegra-video/vi.c
>> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
>> 100644
>> --- a/drivers/staging/media/tegra-video/vi.c
>> +++ b/drivers/staging/media/tegra-video/vi.c
>> @@ -1959,6 +1959,9 @@ static const struct of_device_id
>> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> { .compatible = "nvidia,tegra20-vi", .data = &tegra20_vi_soc },
>> #endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> + { .compatible = "nvidia,tegra30-vi", .data = &tegra20_vi_soc },
>> +#endif
>> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>> { .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
>> #endif
>> diff --git a/drivers/staging/media/tegra-video/vi.h
>> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
>> 100644
>> --- a/drivers/staging/media/tegra-video/vi.h
>> +++ b/drivers/staging/media/tegra-video/vi.h
>> @@ -296,7 +296,7 @@ struct tegra_video_format {
>> u32 fourcc;
>> };
>>
>> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> extern const struct tegra_vi_soc tegra20_vi_soc;
>> #endif
>> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>> diff --git a/drivers/staging/media/tegra-video/video.c
>> b/drivers/staging/media/tegra-video/video.c index
>> 074ad0dc56ca..a25885f93cd7 100644
>> --- a/drivers/staging/media/tegra-video/video.c
>> +++ b/drivers/staging/media/tegra-video/video.c
>> @@ -127,6 +127,10 @@ static const struct of_device_id host1x_video_subdevs[]
>> = { { .compatible = "nvidia,tegra20-vip", },
>> { .compatible = "nvidia,tegra20-vi", },
>> #endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> + { .compatible = "nvidia,tegra30-vip", },
>> + { .compatible = "nvidia,tegra30-vi", },
>> +#endif
>> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
>> { .compatible = "nvidia,tegra210-csi", },
>> { .compatible = "nvidia,tegra210-vi", },
>> diff --git a/drivers/staging/media/tegra-video/vip.c
>> b/drivers/staging/media/tegra-video/vip.c index 5ec717f3afd5..00e08a9971d5
>> 100644
>> --- a/drivers/staging/media/tegra-video/vip.c
>> +++ b/drivers/staging/media/tegra-video/vip.c
>> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
>> *pdev) pm_runtime_disable(&pdev->dev);
>> }
>>
>> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) || defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> extern const struct tegra_vip_soc tegra20_vip_soc;
>> #endif
>>
>> static const struct of_device_id tegra_vip_of_id_table[] = {
>> #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
>> { .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
>> +#endif
>> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
>> + { .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
>> #endif
>> { }
>> };
>
>If tegra30-vip is compatible with tegra20-vip, we don't need to add the
>compatible string into the driver. Just mark it as 'compatible =
>"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob
>alluded, have this compat string pair as an option in the device tree schema).
>
While I am fine with using fallback but it may be a good idea to have a separate compatible so in case tegra30 would need a specific set of ops (tegra20 and tegra30 VIs are not exact match) no additional changes into schema would be required.
>Cheers,
>Mikko
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-27 4:28 ` Svyatoslav
@ 2025-08-27 10:27 ` Mikko Perttunen
2025-08-29 6:54 ` Krzysztof Kozlowski
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 10:27 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, Svyatoslav
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Wednesday, August 27, 2025 1:28 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
> >> Add ids for these clocks.
> >>
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >>
> >> include/dt-bindings/clock/tegra30-car.h | 4 +++-
> >> 1 file changed, 3 insertions(+), 1 deletion(-)
> >>
> >> diff --git a/include/dt-bindings/clock/tegra30-car.h
> >> b/include/dt-bindings/clock/tegra30-car.h index
> >> f193663e6f28..14b83e90a0fc
> >> 100644
> >> --- a/include/dt-bindings/clock/tegra30-car.h
> >> +++ b/include/dt-bindings/clock/tegra30-car.h
> >> @@ -271,6 +271,8 @@
> >>
> >> #define TEGRA30_CLK_AUDIO3_MUX 306
> >> #define TEGRA30_CLK_AUDIO4_MUX 307
> >> #define TEGRA30_CLK_SPDIF_MUX 308
> >>
> >> -#define TEGRA30_CLK_CLK_MAX 309
> >> +#define TEGRA30_CLK_CSIA_PAD 309
> >> +#define TEGRA30_CLK_CSIB_PAD 310
> >> +#define TEGRA30_CLK_CLK_MAX 311
> >>
> >> #endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
> >
> >The commit message refers to tegra20, but contents are tegra30.
>
> My, bad, it should be tegra30
>
> >Regarding the CLK_MAX define, I agree that it would be better to get rid of
> >it. Perhaps you can check if it would be reasonable to calculate it
> >dynamically in the driver, but a define and sanity check in the driver
> >would work too, I think.
>
> It is not unreasonable, but moving this elsewhere may cause issues with
> adding new clocks. Addind new clocks would require updating not only header
> but also a place where max clocks are moved to and ai am not sure how can I
> dinamically calculate amount of clocks in the driver without updating both
> header and driver with each new clock added. Maybe you can propose a
> method?
Looking at the code, it's probably better to just move the CLK_MAX define into
the source code. We can leave a comment here as reminder to update the define
in the code if any new clocks are added. This happens so rarely that I don't
think it should be a problem.
> >Cheers,
> >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-27 4:32 ` Svyatoslav
@ 2025-08-27 10:36 ` Mikko Perttunen
2025-08-27 10:45 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-27 10:36 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, Svyatoslav
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> CSUS clock is required to be enabled on camera device configuration or
> >> else camera module refuses to initiate properly.
> >>
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >>
> >> drivers/clk/tegra/clk-tegra20.c | 1 +
> >> drivers/clk/tegra/clk-tegra30.c | 1 +
> >> 2 files changed, 2 insertions(+)
> >>
> >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> >> --- a/drivers/clk/tegra/clk-tegra20.c
> >> +++ b/drivers/clk/tegra/clk-tegra20.c
> >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
> >>
> >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> >>
> >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> >>
> >> /* must be the last entry */
> >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> >>
> >> };
> >>
> >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> >> --- a/drivers/clk/tegra/clk-tegra30.c
> >> +++ b/drivers/clk/tegra/clk-tegra30.c
> >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
> >>
> >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> >>
> >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> >>
> >> /* must be the last entry */
> >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> >>
> >> };
> >
> >I looked into what this clock does and it seems to be a gate for the CSUS
> >pin, which provides an output clock for camera sensors (VI MCLK). Default
> >source seems to be PLLC_OUT1. It would be good to note that on the commit
> >message, as I can't find any documentation about the CSUS clock elsewhere.
> >
> >What is the 6MHz rate based on?
>
> 6mhz is the statistic value which I was not able to alter while testing. I
> have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> >Since this seems to be a clock consumed by the sensor, it seems to me that
> >rather than making it always on, we could point to it in the sensor's
> >device tree entry.
>
> Sensor device tree uses vi_sensor as clocks source and sensor drivers don't
> support multiple linked clocks.
AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
directly. Perhaps the sensor is actually connected to csus, and the reason we
need to enable it is to allow the vi_sensor clock to pass through the csus
gate?
That leaves the question of why the csus pad would be muxed to vi_sensor by
default, but perhaps there's an explanation for that.
> >Cheers,
> >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-27 10:36 ` Mikko Perttunen
@ 2025-08-27 10:45 ` Svyatoslav Ryhel
2025-08-28 8:13 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-27 10:45 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> <mperttunen@nvidia.com> пише:
> > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > >> CSUS clock is required to be enabled on camera device configuration or
> > >> else camera module refuses to initiate properly.
> > >>
> > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > >> ---
> > >>
> > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > >> 2 files changed, 2 insertions(+)
> > >>
> > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110 100644
> > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[] = {
> > >>
> > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > >>
> > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > >>
> > >> /* must be the last entry */
> > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > >>
> > >> };
> > >>
> > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0 100644
> > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[] = {
> > >>
> > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > >>
> > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > >>
> > >> /* must be the last entry */
> > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > >>
> > >> };
> > >
> > >I looked into what this clock does and it seems to be a gate for the CSUS
> > >pin, which provides an output clock for camera sensors (VI MCLK). Default
> > >source seems to be PLLC_OUT1. It would be good to note that on the commit
> > >message, as I can't find any documentation about the CSUS clock elsewhere.
> > >
> > >What is the 6MHz rate based on?
> >
> > 6mhz is the statistic value which I was not able to alter while testing. I
> > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > >Since this seems to be a clock consumed by the sensor, it seems to me that
> > >rather than making it always on, we could point to it in the sensor's
> > >device tree entry.
> >
> > Sensor device tree uses vi_sensor as clocks source and sensor drivers don't
> > support multiple linked clocks.
>
> AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> directly. Perhaps the sensor is actually connected to csus, and the reason we
> need to enable it is to allow the vi_sensor clock to pass through the csus
> gate?
>
> That leaves the question of why the csus pad would be muxed to vi_sensor by
> default, but perhaps there's an explanation for that.
>
From downstream T30 sources csus and vi_sensor are always called in
pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
latter is used as camera reference clock since most sensors has
reference clock around 24 MHz
> > >Cheers,
> > >Mikko
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-27 10:45 ` Svyatoslav Ryhel
@ 2025-08-28 8:13 ` Mikko Perttunen
2025-08-28 8:28 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-28 8:13 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> >
> > <mperttunen@nvidia.com> пише:
> > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > >> CSUS clock is required to be enabled on camera device configuration
> > > >> or
> > > >> else camera module refuses to initiate properly.
> > > >>
> > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > >> ---
> > > >>
> > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > >> 2 files changed, 2 insertions(+)
> > > >>
> > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110
> > > >> 100644
> > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[]
> > > >> = {
> > > >>
> > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > >>
> > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > >>
> > > >> /* must be the last entry */
> > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > >>
> > > >> };
> > > >>
> > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0
> > > >> 100644
> > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[]
> > > >> = {
> > > >>
> > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > >>
> > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > >>
> > > >> /* must be the last entry */
> > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > >>
> > > >> };
> > > >
> > > >I looked into what this clock does and it seems to be a gate for the
> > > >CSUS
> > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > >Default
> > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > >commit
> > > >message, as I can't find any documentation about the CSUS clock
> > > >elsewhere.
> > > >
> > > >What is the 6MHz rate based on?
> > >
> > > 6mhz is the statistic value which I was not able to alter while testing.
> > > I
> > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > >
> > > >Since this seems to be a clock consumed by the sensor, it seems to me
> > > >that
> > > >rather than making it always on, we could point to it in the sensor's
> > > >device tree entry.
> > >
> > > Sensor device tree uses vi_sensor as clocks source and sensor drivers
> > > don't
> > > support multiple linked clocks.
> >
> > AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> > directly. Perhaps the sensor is actually connected to csus, and the reason
> > we need to enable it is to allow the vi_sensor clock to pass through the
> > csus gate?
> >
> > That leaves the question of why the csus pad would be muxed to vi_sensor
> > by
> > default, but perhaps there's an explanation for that.
>
> From downstream T30 sources csus and vi_sensor are always called in
> pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> latter is used as camera reference clock since most sensors has
> reference clock around 24 MHz
It's possible that the csus pad is still outputting 24MHz. The pinmux options
for the csus pad are various clocks, so it would seem logical that the clock
source for the pad is one of those clocks. However, on the clock framework
side, the csus clock is just a gate. What I'm confused about is that since on
the clock framework side the parent of csus is currently set to clk_m, I don't
know why setting the rate of csus would affect the output of the pad, given
clk_m is not one of the options for the pinmux.
It's be good to verify the register value for the csus pinmux to see where it
thinks the clock is coming from, and then check how that matches with what we
are seeing.
>
> > > >Cheers,
> > > >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-28 8:13 ` Mikko Perttunen
@ 2025-08-28 8:28 ` Svyatoslav Ryhel
2025-08-28 10:15 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-28 8:28 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > >
> > > <mperttunen@nvidia.com> пише:
> > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > >> CSUS clock is required to be enabled on camera device configuration
> > > > >> or
> > > > >> else camera module refuses to initiate properly.
> > > > >>
> > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > >> ---
> > > > >>
> > > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > >> 2 files changed, 2 insertions(+)
> > > > >>
> > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > >> b/drivers/clk/tegra/clk-tegra20.c index 551ef0cf0c9a..42f8150c6110
> > > > >> 100644
> > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table init_table[]
> > > > >> = {
> > > > >>
> > > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > >>
> > > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > >>
> > > > >> /* must be the last entry */
> > > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > >>
> > > > >> };
> > > > >>
> > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > >> b/drivers/clk/tegra/clk-tegra30.c index 82a8cb9545eb..70e85e2949e0
> > > > >> 100644
> > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table init_table[]
> > > > >> = {
> > > > >>
> > > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > >>
> > > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > >>
> > > > >> /* must be the last entry */
> > > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > >>
> > > > >> };
> > > > >
> > > > >I looked into what this clock does and it seems to be a gate for the
> > > > >CSUS
> > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > >Default
> > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > >commit
> > > > >message, as I can't find any documentation about the CSUS clock
> > > > >elsewhere.
> > > > >
> > > > >What is the 6MHz rate based on?
> > > >
> > > > 6mhz is the statistic value which I was not able to alter while testing.
> > > > I
> > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it 6mhz.
> > > >
> > > > >Since this seems to be a clock consumed by the sensor, it seems to me
> > > > >that
> > > > >rather than making it always on, we could point to it in the sensor's
> > > > >device tree entry.
> > > >
> > > > Sensor device tree uses vi_sensor as clocks source and sensor drivers
> > > > don't
> > > > support multiple linked clocks.
> > >
> > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving it
> > > directly. Perhaps the sensor is actually connected to csus, and the reason
> > > we need to enable it is to allow the vi_sensor clock to pass through the
> > > csus gate?
> > >
> > > That leaves the question of why the csus pad would be muxed to vi_sensor
> > > by
> > > default, but perhaps there's an explanation for that.
> >
> > From downstream T30 sources csus and vi_sensor are always called in
> > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > latter is used as camera reference clock since most sensors has
> > reference clock around 24 MHz
>
> It's possible that the csus pad is still outputting 24MHz. The pinmux options
> for the csus pad are various clocks, so it would seem logical that the clock
> source for the pad is one of those clocks. However, on the clock framework
> side, the csus clock is just a gate. What I'm confused about is that since on
> the clock framework side the parent of csus is currently set to clk_m, I don't
> know why setting the rate of csus would affect the output of the pad, given
> clk_m is not one of the options for the pinmux.
>
> It's be good to verify the register value for the csus pinmux to see where it
> thinks the clock is coming from, and then check how that matches with what we
> are seeing.
>
TRM does not provide such data, it has only register address with
layout for it as a plain pad control, that register has only DRVDN,
DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
parent or anything similar. If you give me a method I will calculate
those values.
Another theory is that maybe csus is used for VIP cameras only and
vi_sensor is used for CSI cameras, but they both have to be on in
order to work correctly. Csus was removed from Tegra114 along with
VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
camera mclk source.
Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
pll_p on 13 x34 408000000
vi_sensor2 $ off 0 3.0 136000000
mclk2 $ off 0 136000000
vi_sensor $ off 0 3.0 136000000
mclk $ off 0 136000000
> >
> > > > >Cheers,
> > > > >Mikko
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-28 8:28 ` Svyatoslav Ryhel
@ 2025-08-28 10:15 ` Mikko Perttunen
2025-08-28 10:23 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-28 10:15 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
пише:
> > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > >
> > > > <mperttunen@nvidia.com> пише:
> > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > >> CSUS clock is required to be enabled on camera device
> > > > > >> configuration
> > > > > >> or
> > > > > >> else camera module refuses to initiate properly.
> > > > > >>
> > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > >> ---
> > > > > >>
> > > > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > >> 2 files changed, 2 insertions(+)
> > > > > >>
> > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > >> 100644
> > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > >> init_table[]
> > > > > >> = {
> > > > > >>
> > > > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > >>
> > > > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > >>
> > > > > >> /* must be the last entry */
> > > > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > >>
> > > > > >> };
> > > > > >>
> > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > >> 100644
> > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > >> init_table[]
> > > > > >> = {
> > > > > >>
> > > > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > >>
> > > > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > >>
> > > > > >> /* must be the last entry */
> > > > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > >>
> > > > > >> };
> > > > > >
> > > > > >I looked into what this clock does and it seems to be a gate for
> > > > > >the
> > > > > >CSUS
> > > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > > >Default
> > > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > > >commit
> > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > >elsewhere.
> > > > > >
> > > > > >What is the 6MHz rate based on?
> > > > >
> > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > testing.
> > > > > I
> > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it
> > > > > 6mhz.
> > > > >
> > > > > >Since this seems to be a clock consumed by the sensor, it seems to
> > > > > >me
> > > > > >that
> > > > > >rather than making it always on, we could point to it in the
> > > > > >sensor's
> > > > > >device tree entry.
> > > > >
> > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > drivers
> > > > > don't
> > > > > support multiple linked clocks.
> > > >
> > > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving
> > > > it
> > > > directly. Perhaps the sensor is actually connected to csus, and the
> > > > reason
> > > > we need to enable it is to allow the vi_sensor clock to pass through
> > > > the
> > > > csus gate?
> > > >
> > > > That leaves the question of why the csus pad would be muxed to
> > > > vi_sensor
> > > > by
> > > > default, but perhaps there's an explanation for that.
> > >
> > > From downstream T30 sources csus and vi_sensor are always called in
> > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > latter is used as camera reference clock since most sensors has
> > > reference clock around 24 MHz
> >
> > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > options for the csus pad are various clocks, so it would seem logical
> > that the clock source for the pad is one of those clocks. However, on the
> > clock framework side, the csus clock is just a gate. What I'm confused
> > about is that since on the clock framework side the parent of csus is
> > currently set to clk_m, I don't know why setting the rate of csus would
> > affect the output of the pad, given clk_m is not one of the options for
> > the pinmux.
> >
> > It's be good to verify the register value for the csus pinmux to see where
> > it thinks the clock is coming from, and then check how that matches with
> > what we are seeing.
>
> TRM does not provide such data, it has only register address with
> layout for it as a plain pad control, that register has only DRVDN,
> DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> parent or anything similar. If you give me a method I will calculate
> those values.
I notice that on Tegra20, there is a mux pingroup called 'csus', which has the
mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based on
upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS pad.'
about the CSUS (or SUS) clock.
On Tegra30, however, which I guess you refer to, I guess mux pingroups are
gone and each pin has its own mux (again looking at upstream pinctrl-
tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
that name it only has the drive settings as you mention.
Are you testing on Tegra20, Tegra30, or both?
I've looked at some Tegra30 schematics, and they show a signal called VI_MCLK
being routed to CSI cameras.
>
> Another theory is that maybe csus is used for VIP cameras only and
> vi_sensor is used for CSI cameras, but they both have to be on in
> order to work correctly. Csus was removed from Tegra114 along with
> VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> camera mclk source.
I see the CSUS clock still on Tegra124 based on the upstream kernel. There is
also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK pins,
which both can output the clock. After Tegra30 there is only CAM_MCLK.
Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and mclk2.
There is a comment on mclk saying:
.clk_num = 92, /* csus */
whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
All of that wasn't very coherently written, but to summarize my thoughts:
On Tegra30, we have
- Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which also
goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
parent.
On Tegra114 and later,
- Same situation, but vi_mclk is gone, so instead we have cam_mclk (possibly
multiple with associated mclkN and vi_sensorN clocks)
On Tegra20,
- The vi_mclk pin has a variety of mux options, one of which is VI_SENSOR_CLK.
I expect this to correspond to the same behavior as later chips, i.e. sources
from the csus(/mclk) clock, which sources from vi_sensor.
>
> Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
>
> pll_p on 13 x34 408000000
> vi_sensor2 $ off 0 3.0 136000000 mclk2
> $ off 0 136000000 vi_sensor
> $ off 0 3.0 136000000 mclk $ off
> 0 136000000
> > > > > >Cheers,
> > > > > >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-28 10:15 ` Mikko Perttunen
@ 2025-08-28 10:23 ` Svyatoslav Ryhel
2025-08-29 0:29 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-28 10:23 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> пише:
> > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > >
> > > > > <mperttunen@nvidia.com> пише:
> > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > >> configuration
> > > > > > >> or
> > > > > > >> else camera module refuses to initiate properly.
> > > > > > >>
> > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > >> ---
> > > > > > >>
> > > > > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > >> 2 files changed, 2 insertions(+)
> > > > > > >>
> > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > >> 100644
> > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > >> init_table[]
> > > > > > >> = {
> > > > > > >>
> > > > > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > >>
> > > > > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > >>
> > > > > > >> /* must be the last entry */
> > > > > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > >>
> > > > > > >> };
> > > > > > >>
> > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > >> 100644
> > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > >> init_table[]
> > > > > > >> = {
> > > > > > >>
> > > > > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > >>
> > > > > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > >>
> > > > > > >> /* must be the last entry */
> > > > > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > >>
> > > > > > >> };
> > > > > > >
> > > > > > >I looked into what this clock does and it seems to be a gate for
> > > > > > >the
> > > > > > >CSUS
> > > > > > >pin, which provides an output clock for camera sensors (VI MCLK).
> > > > > > >Default
> > > > > > >source seems to be PLLC_OUT1. It would be good to note that on the
> > > > > > >commit
> > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > >elsewhere.
> > > > > > >
> > > > > > >What is the 6MHz rate based on?
> > > > > >
> > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > testing.
> > > > > > I
> > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left it
> > > > > > 6mhz.
> > > > > >
> > > > > > >Since this seems to be a clock consumed by the sensor, it seems to
> > > > > > >me
> > > > > > >that
> > > > > > >rather than making it always on, we could point to it in the
> > > > > > >sensor's
> > > > > > >device tree entry.
> > > > > >
> > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > drivers
> > > > > > don't
> > > > > > support multiple linked clocks.
> > > > >
> > > > > AIUI vi_sensor is an internal clock so the sensor cannot be receiving
> > > > > it
> > > > > directly. Perhaps the sensor is actually connected to csus, and the
> > > > > reason
> > > > > we need to enable it is to allow the vi_sensor clock to pass through
> > > > > the
> > > > > csus gate?
> > > > >
> > > > > That leaves the question of why the csus pad would be muxed to
> > > > > vi_sensor
> > > > > by
> > > > > default, but perhaps there's an explanation for that.
> > > >
> > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > latter is used as camera reference clock since most sensors has
> > > > reference clock around 24 MHz
> > >
> > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > options for the csus pad are various clocks, so it would seem logical
> > > that the clock source for the pad is one of those clocks. However, on the
> > > clock framework side, the csus clock is just a gate. What I'm confused
> > > about is that since on the clock framework side the parent of csus is
> > > currently set to clk_m, I don't know why setting the rate of csus would
> > > affect the output of the pad, given clk_m is not one of the options for
> > > the pinmux.
> > >
> > > It's be good to verify the register value for the csus pinmux to see where
> > > it thinks the clock is coming from, and then check how that matches with
> > > what we are seeing.
> >
> > TRM does not provide such data, it has only register address with
> > layout for it as a plain pad control, that register has only DRVDN,
> > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > parent or anything similar. If you give me a method I will calculate
> > those values.
>
> I notice that on Tegra20, there is a mux pingroup called 'csus', which has the
> mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based on
> upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS pad.'
> about the CSUS (or SUS) clock.
>
> On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> gone and each pin has its own mux (again looking at upstream pinctrl-
> tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> that name it only has the drive settings as you mention.
>
> Are you testing on Tegra20, Tegra30, or both?
>
I am testing on Tegra30 since I did not have compatible Tegra20 device
(with supported camera).
> I've looked at some Tegra30 schematics, and they show a signal called VI_MCLK
> being routed to CSI cameras.
>
> >
> > Another theory is that maybe csus is used for VIP cameras only and
> > vi_sensor is used for CSI cameras, but they both have to be on in
> > order to work correctly. Csus was removed from Tegra114 along with
> > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > camera mclk source.
>
> I see the CSUS clock still on Tegra124 based on the upstream kernel. There is
> also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK pins,
> which both can output the clock. After Tegra30 there is only CAM_MCLK.
>
> Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and mclk2.
> There is a comment on mclk saying:
>
> .clk_num = 92, /* csus */
>
> whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
>
> All of that wasn't very coherently written, but to summarize my thoughts:
>
> On Tegra30, we have
> - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which also
> goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> parent.
> On Tegra114 and later,
> - Same situation, but vi_mclk is gone, so instead we have cam_mclk (possibly
> multiple with associated mclkN and vi_sensorN clocks)
> On Tegra20,
> - The vi_mclk pin has a variety of mux options, one of which is VI_SENSOR_CLK.
> I expect this to correspond to the same behavior as later chips, i.e. sources
> from the csus(/mclk) clock, which sources from vi_sensor.
>
While this is all quite interesting, how to configure this properly?
> >
> > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> >
> > pll_p on 13 x34 408000000
> > vi_sensor2 $ off 0 3.0 136000000 mclk2
> > $ off 0 136000000 vi_sensor
> > $ off 0 3.0 136000000 mclk $ off
> > 0 136000000
> > > > > > >Cheers,
> > > > > > >Mikko
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-28 10:23 ` Svyatoslav Ryhel
@ 2025-08-29 0:29 ` Mikko Perttunen
2025-08-29 7:05 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29 0:29 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Thursday, August 28, 2025 7:23 PM Svyatoslav Ryhel wrote:
> чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com>
пише:
> > > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> >
> > пише:
> > > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > > >
> > > > > > <mperttunen@nvidia.com> пише:
> > > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > > >> configuration
> > > > > > > >> or
> > > > > > > >> else camera module refuses to initiate properly.
> > > > > > > >>
> > > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > > >> ---
> > > > > > > >>
> > > > > > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > > >> 2 files changed, 2 insertions(+)
> > > > > > > >>
> > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > > >> 100644
> > > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > > >> init_table[]
> > > > > > > >> = {
> > > > > > > >>
> > > > > > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > > >>
> > > > > > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > >>
> > > > > > > >> /* must be the last entry */
> > > > > > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > > >>
> > > > > > > >> };
> > > > > > > >>
> > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > > >> 100644
> > > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > > >> init_table[]
> > > > > > > >> = {
> > > > > > > >>
> > > > > > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0
> > > > > > > >> },
> > > > > > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > > >>
> > > > > > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > >>
> > > > > > > >> /* must be the last entry */
> > > > > > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > > >>
> > > > > > > >> };
> > > > > > > >
> > > > > > > >I looked into what this clock does and it seems to be a gate
> > > > > > > >for
> > > > > > > >the
> > > > > > > >CSUS
> > > > > > > >pin, which provides an output clock for camera sensors (VI
> > > > > > > >MCLK).
> > > > > > > >Default
> > > > > > > >source seems to be PLLC_OUT1. It would be good to note that on
> > > > > > > >the
> > > > > > > >commit
> > > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > > >elsewhere.
> > > > > > > >
> > > > > > > >What is the 6MHz rate based on?
> > > > > > >
> > > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > > testing.
> > > > > > > I
> > > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left
> > > > > > > it
> > > > > > > 6mhz.
> > > > > > >
> > > > > > > >Since this seems to be a clock consumed by the sensor, it seems
> > > > > > > >to
> > > > > > > >me
> > > > > > > >that
> > > > > > > >rather than making it always on, we could point to it in the
> > > > > > > >sensor's
> > > > > > > >device tree entry.
> > > > > > >
> > > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > > drivers
> > > > > > > don't
> > > > > > > support multiple linked clocks.
> > > > > >
> > > > > > AIUI vi_sensor is an internal clock so the sensor cannot be
> > > > > > receiving
> > > > > > it
> > > > > > directly. Perhaps the sensor is actually connected to csus, and
> > > > > > the
> > > > > > reason
> > > > > > we need to enable it is to allow the vi_sensor clock to pass
> > > > > > through
> > > > > > the
> > > > > > csus gate?
> > > > > >
> > > > > > That leaves the question of why the csus pad would be muxed to
> > > > > > vi_sensor
> > > > > > by
> > > > > > default, but perhaps there's an explanation for that.
> > > > >
> > > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > > latter is used as camera reference clock since most sensors has
> > > > > reference clock around 24 MHz
> > > >
> > > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > > options for the csus pad are various clocks, so it would seem logical
> > > > that the clock source for the pad is one of those clocks. However, on
> > > > the
> > > > clock framework side, the csus clock is just a gate. What I'm confused
> > > > about is that since on the clock framework side the parent of csus is
> > > > currently set to clk_m, I don't know why setting the rate of csus
> > > > would
> > > > affect the output of the pad, given clk_m is not one of the options
> > > > for
> > > > the pinmux.
> > > >
> > > > It's be good to verify the register value for the csus pinmux to see
> > > > where
> > > > it thinks the clock is coming from, and then check how that matches
> > > > with
> > > > what we are seeing.
> > >
> > > TRM does not provide such data, it has only register address with
> > > layout for it as a plain pad control, that register has only DRVDN,
> > > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > > parent or anything similar. If you give me a method I will calculate
> > > those values.
> >
> > I notice that on Tegra20, there is a mux pingroup called 'csus', which has
> > the mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based
> > on upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS
> > pad.' about the CSUS (or SUS) clock.
> >
> > On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> > gone and each pin has its own mux (again looking at upstream pinctrl-
> > tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> > VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> > that name it only has the drive settings as you mention.
> >
> > Are you testing on Tegra20, Tegra30, or both?
>
> I am testing on Tegra30 since I did not have compatible Tegra20 device
> (with supported camera).
>
> > I've looked at some Tegra30 schematics, and they show a signal called
> > VI_MCLK being routed to CSI cameras.
> >
> > > Another theory is that maybe csus is used for VIP cameras only and
> > > vi_sensor is used for CSI cameras, but they both have to be on in
> > > order to work correctly. Csus was removed from Tegra114 along with
> > > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > > camera mclk source.
> >
> > I see the CSUS clock still on Tegra124 based on the upstream kernel. There
> > is also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK
> > pins, which both can output the clock. After Tegra30 there is only
> > CAM_MCLK.
> >
> > Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and
> > mclk2.>
> > There is a comment on mclk saying:
> > .clk_num = 92, /* csus */
> >
> > whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> > vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
> >
> > All of that wasn't very coherently written, but to summarize my thoughts:
> >
> > On Tegra30, we have
> > - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which
> > also
> > goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> > parent.
> > On Tegra114 and later,
> > - Same situation, but vi_mclk is gone, so instead we have cam_mclk
> > (possibly multiple with associated mclkN and vi_sensorN clocks)
> > On Tegra20,
> > - The vi_mclk pin has a variety of mux options, one of which is
> > VI_SENSOR_CLK. I expect this to correspond to the same behavior as later
> > chips, i.e. sources from the csus(/mclk) clock, which sources from
> > vi_sensor.
>
> While this is all quite interesting, how to configure this properly?
Fix the csus clock's parent to be vi_sensor. Point the sensor's device tree
clock entry to csus. The sensor's clk_enable should then ungate csus and
clk_set_rate should flow to vi_sensor to set the rate appropriately. In the
board device tree pinctrl section, set the vi_mclk pin's function to VI
(should be default on Tegra30, but best to be explicit).
I think that should do it, but it's all theoretical of course :)
>
> > > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> > >
> > > pll_p on 13 x34
> > > 408000000
> > >
> > > vi_sensor2 $ off 0 3.0 136000000 mclk2
> > >
> > > $ off 0 136000000 vi_sensor
> > >
> > > $ off 0 3.0 136000000 mclk $
> > > off
> > >
> > > 0 136000000
> > >
> > > > > > > >Cheers,
> > > > > > > >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
2025-08-27 4:26 ` Mikko Perttunen
@ 2025-08-29 0:44 ` Mikko Perttunen
1 sibling, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29 0:44 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Tegra30 has CSI PAD bits in both PLLD and PLLD2 clocks, that are required
> for correct work of CSI block.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/clk/tegra/clk-tegra30.c | 15 ++++++++++++++-
> 1 file changed, 14 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/tegra/clk-tegra30.c
> b/drivers/clk/tegra/clk-tegra30.c index 70e85e2949e0..f033eb1ac26a 100644
> --- a/drivers/clk/tegra/clk-tegra30.c
> +++ b/drivers/clk/tegra/clk-tegra30.c
> @@ -153,6 +153,7 @@ static unsigned long input_freq;
>
> static DEFINE_SPINLOCK(cml_lock);
> static DEFINE_SPINLOCK(pll_d_lock);
> +static DEFINE_SPINLOCK(pll_d2_lock);
>
> #define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
> _clk_num, _gate_flags, _clk_id) \
> @@ -859,7 +860,7 @@ static void __init tegra30_pll_init(void)
>
> /* PLLD2 */
> clk = tegra_clk_register_pll("pll_d2", "pll_ref", clk_base, pmc_base,
0,
> - &pll_d2_params, NULL);
> + &pll_d2_params, &pll_d2_lock);
> clks[TEGRA30_CLK_PLL_D2] = clk;
>
> /* PLLD2_OUT0 */
> @@ -1008,6 +1009,18 @@ static void __init tegra30_periph_clk_init(void)
> 0, 48, periph_clk_enb_refcnt);
> clks[TEGRA30_CLK_DSIA] = clk;
>
> + /* csia_pad */
> + clk = clk_register_gate(NULL, "csia_pad", "pll_d",
CLK_SET_RATE_PARENT,
> + clk_base + PLLD_BASE, 26, 0, &pll_d_lock);
> + clk_register_clkdev(clk, "csia_pad", NULL);
I believe clkdevs are obsolete, so we can drop the clkdev registrations.
> + clks[TEGRA30_CLK_CSIA_PAD] = clk;
> +
> + /* csib_pad */
> + clk = clk_register_gate(NULL, "csib_pad", "pll_d2",
CLK_SET_RATE_PARENT,
> + clk_base + PLLD2_BASE, 26, 0,
&pll_d2_lock);
> + clk_register_clkdev(clk, "csib_pad", NULL);
> + clks[TEGRA30_CLK_CSIB_PAD] = clk;
> +
> /* pcie */
> clk = tegra_clk_register_periph_gate("pcie", "clk_m", 0, clk_base, 0,
> 70, periph_clk_enb_refcnt);
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30
2025-08-27 4:47 ` Svyatoslav
@ 2025-08-29 0:56 ` Mikko Perttunen
0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-08-29 0:56 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, Svyatoslav
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Wednesday, August 27, 2025 1:47 PM Svyatoslav wrote:
> 27 серпня 2025 р. 07:29:40 GMT+03:00, Mikko Perttunen
<mperttunen@nvidia.com> пише:
> >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> >> Exisitng VI and VIP implementation for Tegra20 is fully compatible with
> >> Tegra30.
> >>
> >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> >> ---
> >>
> >> drivers/staging/media/tegra-video/Makefile | 1 +
> >> drivers/staging/media/tegra-video/vi.c | 3 +++
> >> drivers/staging/media/tegra-video/vi.h | 2 +-
> >> drivers/staging/media/tegra-video/video.c | 4 ++++
> >> drivers/staging/media/tegra-video/vip.c | 5 ++++-
> >> 5 files changed, 13 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/drivers/staging/media/tegra-video/Makefile
> >> b/drivers/staging/media/tegra-video/Makefile index
> >> 6c7552e05109..96380b5dbd8b 100644
> >> --- a/drivers/staging/media/tegra-video/Makefile
> >> +++ b/drivers/staging/media/tegra-video/Makefile
> >> @@ -6,5 +6,6 @@ tegra-video-objs := \
> >>
> >> csi.o
> >>
> >> tegra-video-$(CONFIG_ARCH_TEGRA_2x_SOC) += tegra20.o
> >>
> >> +tegra-video-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra20.o
> >>
> >> tegra-video-$(CONFIG_ARCH_TEGRA_210_SOC) += tegra210.o
> >> obj-$(CONFIG_VIDEO_TEGRA) += tegra-video.o
> >>
> >> diff --git a/drivers/staging/media/tegra-video/vi.c
> >> b/drivers/staging/media/tegra-video/vi.c index c9276ff76157..71be205cacb5
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vi.c
> >> +++ b/drivers/staging/media/tegra-video/vi.c
> >> @@ -1959,6 +1959,9 @@ static const struct of_device_id
> >> tegra_vi_of_id_table[] = { #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >>
> >> { .compatible = "nvidia,tegra20-vi", .data = &tegra20_vi_soc },
> >>
> >> #endif
> >>
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> + { .compatible = "nvidia,tegra30-vi", .data = &tegra20_vi_soc },
> >> +#endif
> >>
> >> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >>
> >> { .compatible = "nvidia,tegra210-vi", .data = &tegra210_vi_soc },
> >>
> >> #endif
> >>
> >> diff --git a/drivers/staging/media/tegra-video/vi.h
> >> b/drivers/staging/media/tegra-video/vi.h index 1e6a5caa7082..cac0c0d0e225
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vi.h
> >> +++ b/drivers/staging/media/tegra-video/vi.h
> >> @@ -296,7 +296,7 @@ struct tegra_video_format {
> >>
> >> u32 fourcc;
> >>
> >> };
> >>
> >> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) ||
> >> defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >>
> >> extern const struct tegra_vi_soc tegra20_vi_soc;
> >> #endif
> >> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >>
> >> diff --git a/drivers/staging/media/tegra-video/video.c
> >> b/drivers/staging/media/tegra-video/video.c index
> >> 074ad0dc56ca..a25885f93cd7 100644
> >> --- a/drivers/staging/media/tegra-video/video.c
> >> +++ b/drivers/staging/media/tegra-video/video.c
> >> @@ -127,6 +127,10 @@ static const struct of_device_id
> >> host1x_video_subdevs[] = { { .compatible = "nvidia,tegra20-vip", },
> >>
> >> { .compatible = "nvidia,tegra20-vi", },
> >>
> >> #endif
> >>
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> + { .compatible = "nvidia,tegra30-vip", },
> >> + { .compatible = "nvidia,tegra30-vi", },
> >> +#endif
> >>
> >> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> >>
> >> { .compatible = "nvidia,tegra210-csi", },
> >> { .compatible = "nvidia,tegra210-vi", },
> >>
> >> diff --git a/drivers/staging/media/tegra-video/vip.c
> >> b/drivers/staging/media/tegra-video/vip.c index
> >> 5ec717f3afd5..00e08a9971d5
> >> 100644
> >> --- a/drivers/staging/media/tegra-video/vip.c
> >> +++ b/drivers/staging/media/tegra-video/vip.c
> >> @@ -263,13 +263,16 @@ static void tegra_vip_remove(struct platform_device
> >> *pdev) pm_runtime_disable(&pdev->dev);
> >>
> >> }
> >>
> >> -#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC) ||
> >> defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >>
> >> extern const struct tegra_vip_soc tegra20_vip_soc;
> >> #endif
> >>
> >> static const struct of_device_id tegra_vip_of_id_table[] = {
> >> #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> >>
> >> { .compatible = "nvidia,tegra20-vip", .data = &tegra20_vip_soc },
> >>
> >> +#endif
> >> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> >> + { .compatible = "nvidia,tegra30-vip", .data = &tegra20_vip_soc },
> >>
> >> #endif
> >>
> >> { }
> >>
> >> };
> >
> >If tegra30-vip is compatible with tegra20-vip, we don't need to add the
> >compatible string into the driver. Just mark it as 'compatible =
> >"nvidia,tegra30-vip", "nvidia,tegra20-vip";' in the device tree (and as Rob
> >alluded, have this compat string pair as an option in the device tree
> >schema).
> While I am fine with using fallback but it may be a good idea to have a
> separate compatible so in case tegra30 would need a specific set of ops
> (tegra20 and tegra30 VIs are not exact match) no additional changes into
> schema would be required.
The standard practice is to use the compatible string fallback in device tree
when we believe the hardware to be compatible. If that later turns out not to
be the case (which should be unlikely), the schema can be adjusted along with
the source code changes.
> >Cheers,
> >Mikko
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP
2025-08-19 20:27 ` Rob Herring
2025-08-20 5:36 ` Svyatoslav Ryhel
@ 2025-08-29 6:42 ` Svyatoslav Ryhel
1 sibling, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-29 6:42 UTC (permalink / raw)
To: Rob Herring
Cc: Thierry Reding, Thierry Reding, Mikko Perttunen, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 19 серп. 2025 р. о 23:27 Rob Herring <robh@kernel.org> пише:
>
> On Tue, Aug 19, 2025 at 03:16:16PM +0300, Svyatoslav Ryhel wrote:
> > Parallel VI interface found in Tegra30 is exactly the same as Tegra20 has.
>
> That's not what the compatible schema says. 'exactly the same' implies a
> fallback to whatever it is exactly the same as.
>
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> > .../devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml | 1 +
> > 1 file changed, 1 insertion(+)
> >
> > diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > index 14294edb8d8c..39e9b3297dbd 100644
> > --- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > +++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-vip.yaml
> > @@ -13,6 +13,7 @@ properties:
> > compatible:
> > enum:
> > - nvidia,tegra20-vip
> > + - nvidia,tegra30-vip
> >
Rob, may I use this:
properties:
compatible:
one0f:
- const: nvidia,tegra20-vip
- items:
- const: nvidia,tegra30-vip
- const: nvidia,tegra20-vip
Among all Tegra SoC only 2 have VIP support Tegra20 and Tegra30.
Tegra30 is backwards compatible with Tegra20 so we can use fallback.
There should be no new generation added to this schema.
OR should I use enum?
properties:
compatible:
one0f:
- enum:
- nvidia,tegra20-vip
- items:
- const: nvidia,tegra30-vip
- const: nvidia,tegra20-vip
> > ports:
> > $ref: /schemas/graph.yaml#/properties/ports
> > --
> > 2.48.1
> >
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks
2025-08-27 10:27 ` Mikko Perttunen
@ 2025-08-29 6:54 ` Krzysztof Kozlowski
0 siblings, 0 replies; 59+ messages in thread
From: Krzysztof Kozlowski @ 2025-08-29 6:54 UTC (permalink / raw)
To: Mikko Perttunen, Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, Svyatoslav
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On 27/08/2025 12:27, Mikko Perttunen wrote:
> On Wednesday, August 27, 2025 1:28 PM Svyatoslav wrote:
>> 27 серпня 2025 р. 07:19:39 GMT+03:00, Mikko Perttunen
> <mperttunen@nvidia.com> пише:
>>> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
>>>> Tegra30 has CSI PAD clock enable bits embedded into PLLD/PLLD2 registers.
>>>> Add ids for these clocks.
>>>>
>>>> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
>>>> ---
>>>>
>>>> include/dt-bindings/clock/tegra30-car.h | 4 +++-
>>>> 1 file changed, 3 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/include/dt-bindings/clock/tegra30-car.h
>>>> b/include/dt-bindings/clock/tegra30-car.h index
>>>> f193663e6f28..14b83e90a0fc
>>>> 100644
>>>> --- a/include/dt-bindings/clock/tegra30-car.h
>>>> +++ b/include/dt-bindings/clock/tegra30-car.h
>>>> @@ -271,6 +271,8 @@
>>>>
>>>> #define TEGRA30_CLK_AUDIO3_MUX 306
>>>> #define TEGRA30_CLK_AUDIO4_MUX 307
>>>> #define TEGRA30_CLK_SPDIF_MUX 308
>>>>
>>>> -#define TEGRA30_CLK_CLK_MAX 309
>>>> +#define TEGRA30_CLK_CSIA_PAD 309
>>>> +#define TEGRA30_CLK_CSIB_PAD 310
>>>> +#define TEGRA30_CLK_CLK_MAX 311
>>>>
>>>> #endif /* _DT_BINDINGS_CLOCK_TEGRA30_CAR_H */
>>>
>>> The commit message refers to tegra20, but contents are tegra30.
>>
>> My, bad, it should be tegra30
>>
>>> Regarding the CLK_MAX define, I agree that it would be better to get rid of
>>> it. Perhaps you can check if it would be reasonable to calculate it
>>> dynamically in the driver, but a define and sanity check in the driver
>>> would work too, I think.
>>
>> It is not unreasonable, but moving this elsewhere may cause issues with
>> adding new clocks. Addind new clocks would require updating not only header
No, there are no such issues.
>> but also a place where max clocks are moved to and ai am not sure how can I
>> dinamically calculate amount of clocks in the driver without updating both
>> header and driver with each new clock added. Maybe you can propose a
>> method?
>
> Looking at the code, it's probably better to just move the CLK_MAX define into
Just like every other driver.
> the source code. We can leave a comment here as reminder to update the define
> in the code if any new clocks are added. This happens so rarely that I don't
> think it should be a problem.
No, don't leave comments here. There is no single risk of breakage,
there is no issue to fix with that comment.
If you add clock to the driver WITHOUT binding, nothing, absolutely
nothing bad will happen. You will just not have a way to use that clock
in DTS.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 01/19] clk: tegra: init CSUS clock for Tegra20 and Tegra30
2025-08-29 0:29 ` Mikko Perttunen
@ 2025-08-29 7:05 ` Svyatoslav Ryhel
0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-08-29 7:05 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
пт, 29 серп. 2025 р. о 03:30 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Thursday, August 28, 2025 7:23 PM Svyatoslav Ryhel wrote:
> > чт, 28 серп. 2025 р. о 13:15 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > > On Thursday, August 28, 2025 5:28 PM Svyatoslav Ryhel wrote:
> > > > чт, 28 серп. 2025 р. о 11:13 Mikko Perttunen <mperttunen@nvidia.com>
> пише:
> > > > > On Wednesday, August 27, 2025 7:45 PM Svyatoslav Ryhel wrote:
> > > > > > ср, 27 серп. 2025 р. о 13:36 Mikko Perttunen <mperttunen@nvidia.com>
> > >
> > > пише:
> > > > > > > On Wednesday, August 27, 2025 1:32 PM Svyatoslav wrote:
> > > > > > > > 27 серпня 2025 р. 07:09:45 GMT+03:00, Mikko Perttunen
> > > > > > >
> > > > > > > <mperttunen@nvidia.com> пише:
> > > > > > > > >On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > > > > > >> CSUS clock is required to be enabled on camera device
> > > > > > > > >> configuration
> > > > > > > > >> or
> > > > > > > > >> else camera module refuses to initiate properly.
> > > > > > > > >>
> > > > > > > > >> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > > > > > >> ---
> > > > > > > > >>
> > > > > > > > >> drivers/clk/tegra/clk-tegra20.c | 1 +
> > > > > > > > >> drivers/clk/tegra/clk-tegra30.c | 1 +
> > > > > > > > >> 2 files changed, 2 insertions(+)
> > > > > > > > >>
> > > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> b/drivers/clk/tegra/clk-tegra20.c index
> > > > > > > > >> 551ef0cf0c9a..42f8150c6110
> > > > > > > > >> 100644
> > > > > > > > >> --- a/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra20.c
> > > > > > > > >> @@ -1043,6 +1043,7 @@ static struct tegra_clk_init_table
> > > > > > > > >> init_table[]
> > > > > > > > >> = {
> > > > > > > > >>
> > > > > > > > >> { TEGRA20_CLK_GR3D, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > > >> { TEGRA20_CLK_VDE, TEGRA20_CLK_PLL_C, 300000000, 0 },
> > > > > > > > >> { TEGRA20_CLK_PWM, TEGRA20_CLK_PLL_P, 48000000, 0 },
> > > > > > > > >>
> > > > > > > > >> + { TEGRA20_CLK_CSUS, TEGRA20_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > > >>
> > > > > > > > >> /* must be the last entry */
> > > > > > > > >> { TEGRA20_CLK_CLK_MAX, TEGRA20_CLK_CLK_MAX, 0, 0 },
> > > > > > > > >>
> > > > > > > > >> };
> > > > > > > > >>
> > > > > > > > >> diff --git a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> b/drivers/clk/tegra/clk-tegra30.c index
> > > > > > > > >> 82a8cb9545eb..70e85e2949e0
> > > > > > > > >> 100644
> > > > > > > > >> --- a/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> +++ b/drivers/clk/tegra/clk-tegra30.c
> > > > > > > > >> @@ -1237,6 +1237,7 @@ static struct tegra_clk_init_table
> > > > > > > > >> init_table[]
> > > > > > > > >> = {
> > > > > > > > >>
> > > > > > > > >> { TEGRA30_CLK_HDA, TEGRA30_CLK_PLL_P, 102000000, 0 },
> > > > > > > > >> { TEGRA30_CLK_HDA2CODEC_2X, TEGRA30_CLK_PLL_P, 48000000, 0
> > > > > > > > >> },
> > > > > > > > >> { TEGRA30_CLK_PWM, TEGRA30_CLK_PLL_P, 48000000, 0 },
> > > > > > > > >>
> > > > > > > > >> + { TEGRA30_CLK_CSUS, TEGRA30_CLK_CLK_MAX, 6000000, 1 },
> > > > > > > > >>
> > > > > > > > >> /* must be the last entry */
> > > > > > > > >> { TEGRA30_CLK_CLK_MAX, TEGRA30_CLK_CLK_MAX, 0, 0 },
> > > > > > > > >>
> > > > > > > > >> };
> > > > > > > > >
> > > > > > > > >I looked into what this clock does and it seems to be a gate
> > > > > > > > >for
> > > > > > > > >the
> > > > > > > > >CSUS
> > > > > > > > >pin, which provides an output clock for camera sensors (VI
> > > > > > > > >MCLK).
> > > > > > > > >Default
> > > > > > > > >source seems to be PLLC_OUT1. It would be good to note that on
> > > > > > > > >the
> > > > > > > > >commit
> > > > > > > > >message, as I can't find any documentation about the CSUS clock
> > > > > > > > >elsewhere.
> > > > > > > > >
> > > > > > > > >What is the 6MHz rate based on?
> > > > > > > >
> > > > > > > > 6mhz is the statistic value which I was not able to alter while
> > > > > > > > testing.
> > > > > > > > I
> > > > > > > > have tried 12mhz and 24mhz too but it remained 6mhz, so I left
> > > > > > > > it
> > > > > > > > 6mhz.
> > > > > > > >
> > > > > > > > >Since this seems to be a clock consumed by the sensor, it seems
> > > > > > > > >to
> > > > > > > > >me
> > > > > > > > >that
> > > > > > > > >rather than making it always on, we could point to it in the
> > > > > > > > >sensor's
> > > > > > > > >device tree entry.
> > > > > > > >
> > > > > > > > Sensor device tree uses vi_sensor as clocks source and sensor
> > > > > > > > drivers
> > > > > > > > don't
> > > > > > > > support multiple linked clocks.
> > > > > > >
> > > > > > > AIUI vi_sensor is an internal clock so the sensor cannot be
> > > > > > > receiving
> > > > > > > it
> > > > > > > directly. Perhaps the sensor is actually connected to csus, and
> > > > > > > the
> > > > > > > reason
> > > > > > > we need to enable it is to allow the vi_sensor clock to pass
> > > > > > > through
> > > > > > > the
> > > > > > > csus gate?
> > > > > > >
> > > > > > > That leaves the question of why the csus pad would be muxed to
> > > > > > > vi_sensor
> > > > > > > by
> > > > > > > default, but perhaps there's an explanation for that.
> > > > > >
> > > > > > From downstream T30 sources csus and vi_sensor are always called in
> > > > > > pair (6MHz csus and 24MHz for vi_sensor), naturally I assumed that
> > > > > > latter is used as camera reference clock since most sensors has
> > > > > > reference clock around 24 MHz
> > > > >
> > > > > It's possible that the csus pad is still outputting 24MHz. The pinmux
> > > > > options for the csus pad are various clocks, so it would seem logical
> > > > > that the clock source for the pad is one of those clocks. However, on
> > > > > the
> > > > > clock framework side, the csus clock is just a gate. What I'm confused
> > > > > about is that since on the clock framework side the parent of csus is
> > > > > currently set to clk_m, I don't know why setting the rate of csus
> > > > > would
> > > > > affect the output of the pad, given clk_m is not one of the options
> > > > > for
> > > > > the pinmux.
> > > > >
> > > > > It's be good to verify the register value for the csus pinmux to see
> > > > > where
> > > > > it thinks the clock is coming from, and then check how that matches
> > > > > with
> > > > > what we are seeing.
> > > >
> > > > TRM does not provide such data, it has only register address with
> > > > layout for it as a plain pad control, that register has only DRVDN,
> > > > DRVUP, SLWR and SLWF and I don't see a way to decode clock value or
> > > > parent or anything similar. If you give me a method I will calculate
> > > > those values.
> > >
> > > I notice that on Tegra20, there is a mux pingroup called 'csus', which has
> > > the mux options PLLC_OUT1, PLLP_OUT2, PLLP_OUT3, and VI_SENSOR_CLK (based
> > > on upstream pinctrl-tegra20.c). The TRM also says 'Enable clock to SUS
> > > pad.' about the CSUS (or SUS) clock.
> > >
> > > On Tegra30, however, which I guess you refer to, I guess mux pingroups are
> > > gone and each pin has its own mux (again looking at upstream pinctrl-
> > > tegra30.c). vi_mclk_pt1 is now its own mux with the options VI, VI_ALT1,
> > > VI_ALT2, VI_ALT3. The drive group for this pin is still called csus, so by
> > > that name it only has the drive settings as you mention.
> > >
> > > Are you testing on Tegra20, Tegra30, or both?
> >
> > I am testing on Tegra30 since I did not have compatible Tegra20 device
> > (with supported camera).
> >
> > > I've looked at some Tegra30 schematics, and they show a signal called
> > > VI_MCLK being routed to CSI cameras.
> > >
> > > > Another theory is that maybe csus is used for VIP cameras only and
> > > > vi_sensor is used for CSI cameras, but they both have to be on in
> > > > order to work correctly. Csus was removed from Tegra114 along with
> > > > VIP, might not be a coincidence. Moreover, T124 uses vi_sensor as
> > > > camera mclk source.
> > >
> > > I see the CSUS clock still on Tegra124 based on the upstream kernel. There
> > > is also a CAM_MCLK pin. It seems Tegra30 has both VI_MCLK and CAM_MCLK
> > > pins, which both can output the clock. After Tegra30 there is only
> > > CAM_MCLK.
> > >
> > > Looking at L4T r21, in tegra12_clocks.c, it defines the clocks mclk and
> > > mclk2.>
> > > There is a comment on mclk saying:
> > > .clk_num = 92, /* csus */
> > >
> > > whereas mclk2 is vim2_clk. These clocks are indeed defined as gates, with
> > > vi_sensor / vi_sensor2 as parent, set_rate being passed onto the parent.
> > >
> > > All of that wasn't very coherently written, but to summarize my thoughts:
> > >
> > > On Tegra30, we have
> > > - Pins vi_mclk and cam_mclk. Both can only source from (vi_)mclk which
> > > also
> > > goes by name csus. The mclk/csus clock is a clock gate with vi_sensor as
> > > parent.
> > > On Tegra114 and later,
> > > - Same situation, but vi_mclk is gone, so instead we have cam_mclk
> > > (possibly multiple with associated mclkN and vi_sensorN clocks)
> > > On Tegra20,
> > > - The vi_mclk pin has a variety of mux options, one of which is
> > > VI_SENSOR_CLK. I expect this to correspond to the same behavior as later
> > > chips, i.e. sources from the csus(/mclk) clock, which sources from
> > > vi_sensor.
> >
> > While this is all quite interesting, how to configure this properly?
>
> Fix the csus clock's parent to be vi_sensor. Point the sensor's device tree
> clock entry to csus. The sensor's clk_enable should then ungate csus and
> clk_set_rate should flow to vi_sensor to set the rate appropriately. In the
> board device tree pinctrl section, set the vi_mclk pin's function to VI
> (should be default on Tegra30, but best to be explicit).
>
> I think that should do it, but it's all theoretical of course :)
>
Ok, seems to work correctly. I will add same setup to Tegra114 since
camera is not operational without same CSUS gate if you don't mind.
> >
> > > > Here is a fragment of Tegra124 clock tree (dumped from Mi pad 1)
> > > >
> > > > pll_p on 13 x34
> > > > 408000000
> > > >
> > > > vi_sensor2 $ off 0 3.0 136000000 mclk2
> > > >
> > > > $ off 0 136000000 vi_sensor
> > > >
> > > > $ off 0 3.0 136000000 mclk $
> > > > off
> > > >
> > > > 0 136000000
> > > >
> > > > > > > > >Cheers,
> > > > > > > > >Mikko
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
@ 2025-09-02 0:46 ` Mikko Perttunen
2025-09-02 5:05 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 0:46 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> all MIPI calibration pads were part of VI block.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/csi.c | 12 +++++++-----
> drivers/staging/media/tegra-video/csi.h | 1 +
> drivers/staging/media/tegra-video/tegra210.c | 1 +
> 3 files changed, 9 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/csi.c
> b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
> return 0;
>
> - chan->mipi = tegra_mipi_request(csi->dev, node);
> - if (IS_ERR(chan->mipi)) {
> - ret = PTR_ERR(chan->mipi);
> - chan->mipi = NULL;
> - dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> + if (csi->soc->has_mipi_calibration) {
> + chan->mipi = tegra_mipi_request(csi->dev, node);
The way I would read 'soc->has_mipi_calibration' is that this device (CSI)
contains the MIPI calibration hardware. I.e. the opposite of here. I would
invert the logic and optionally call it e.g. 'internal_mipi_calib'.
A cleaner way to do this might be to always call tegra_mipi_request et al. --
on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the
callbacks registered in the MIPI driver as we discussed before. That way the
CSI driver won't need separate code paths for SoCs with internal MIPI
calibration and SoCs with the external MIPI calibration device.
Cheers,
Mikko
> + if (IS_ERR(chan->mipi)) {
> + ret = PTR_ERR(chan->mipi);
> + chan->mipi = NULL;
> + dev_err(csi->dev, "failed to get mipi device:
%d\n", ret);
> + }
> }
>
> return ret;
> diff --git a/drivers/staging/media/tegra-video/csi.h
> b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> 100644
> --- a/drivers/staging/media/tegra-video/csi.h
> +++ b/drivers/staging/media/tegra-video/csi.h
> @@ -128,6 +128,7 @@ struct tegra_csi_soc {
> unsigned int num_clks;
> const struct tpg_framerate *tpg_frmrate_table;
> unsigned int tpg_frmrate_table_size;
> + bool has_mipi_calibration;
> };
>
> /**
> diff --git a/drivers/staging/media/tegra-video/tegra210.c
> b/drivers/staging/media/tegra-video/tegra210.c index
> da99f19a39e7..305472e94af4 100644
> --- a/drivers/staging/media/tegra-video/tegra210.c
> +++ b/drivers/staging/media/tegra-video/tegra210.c
> @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
> .num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
> .tpg_frmrate_table = tegra210_tpg_frmrate_table,
> .tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> + .has_mipi_calibration = true,
> };
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height
2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
@ 2025-09-02 0:51 ` Mikko Perttunen
0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 0:51 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Maximum width and height for Tegra20 and Tegra30 is determined by
> respective register field, rounded down to factor of 2, which is 8191U
> rounded down to 8190U.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/tegra20.c | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 7b8f8f810b35..3e2d746638b6 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -23,11 +23,10 @@
>
> #define TEGRA_VI_SYNCPT_WAIT_TIMEOUT
msecs_to_jiffies(200)
>
> -/* This are just good-sense numbers. The actual min/max is not documented.
> */ #define TEGRA20_MIN_WIDTH 32U
> +#define TEGRA20_MAX_WIDTH 8190U
> #define TEGRA20_MIN_HEIGHT 32U
> -#define TEGRA20_MAX_WIDTH 2048U
> -#define TEGRA20_MAX_HEIGHT 2048U
> +#define TEGRA20_MAX_HEIGHT 8190U
>
> /*
> --------------------------------------------------------------------------
> * Registers
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI
2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
@ 2025-09-02 1:00 ` Mikko Perttunen
0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 1:00 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> VI in Tegra20/Tegra30 has 2 VI outputs with different set of supported
> formats. Convert output registers to macros for simpler work with both
> outputs since apart formats their layout matches.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/tegra20.c | 80 ++++++++++++---------
> 1 file changed, 45 insertions(+), 35 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 3e2d746638b6..54512d1ecf83 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -28,13 +28,19 @@
> #define TEGRA20_MIN_HEIGHT 32U
> #define TEGRA20_MAX_HEIGHT 8190U
>
> +/* Tegra20/Tegra30 has 2 outputs in VI */
> +enum {
> + OUT_1,
> + OUT_2,
> +};
> +
I would prefer ..
enum tegra_vi_out {
TEGRA_VI_OUT_1 = 0, // explicit since the values are important here
TEGRA_VI_OUT_2 = 1,
};
and then using the type instead of int.
> /*
> --------------------------------------------------------------------------
> * Registers
> */
>
> -#define TEGRA_VI_CONT_SYNCPT_OUT_1 0x0060
> -#define VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT BIT(8)
> -#define VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT 0
> +#define TEGRA_VI_CONT_SYNCPT_OUT(n) (0x0060 + (n) *
4)
> +#define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
> +#define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
>
> #define TEGRA_VI_VI_INPUT_CONTROL 0x0088
> #define VI_INPUT_FIELD_DETECT BIT(27)
> @@ -46,6 +52,7 @@
> #define VI_INPUT_YUV_INPUT_FORMAT_YVYU (3 <<
> VI_INPUT_YUV_INPUT_FORMAT_SFT) #define VI_INPUT_INPUT_FORMAT_SFT
2
> /* bits [5:2] */
> #define VI_INPUT_INPUT_FORMAT_YUV422 (0 <<
> VI_INPUT_INPUT_FORMAT_SFT) +#define VI_INPUT_INPUT_FORMAT_BAYER
(2
> << VI_INPUT_INPUT_FORMAT_SFT) #define
> VI_INPUT_VIP_INPUT_ENABLE BIT(1)
>
> #define TEGRA_VI_VI_CORE_CONTROL 0x008c
> @@ -66,7 +73,7 @@
> #define VI_VI_CORE_CONTROL_OUTPUT_TO_EPP_SFT 2
> #define VI_VI_CORE_CONTROL_OUTPUT_TO_ISP_SFT 0
>
> -#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x0090
> +#define TEGRA_VI_VI_OUTPUT_CONTROL(n) (0x0090 + (n) *
4)
> #define VI_OUTPUT_FORMAT_EXT BIT(22)
> #define VI_OUTPUT_V_DIRECTION BIT(20)
> #define VI_OUTPUT_H_DIRECTION BIT(19)
> @@ -80,6 +87,7 @@
> #define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
> #define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 <<
> VI_OUTPUT_OUTPUT_FORMAT_SFT) #define
> VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 <<
VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 <<
> VI_OUTPUT_OUTPUT_FORMAT_SFT)
>
> #define TEGRA_VI_VIP_H_ACTIVE 0x00a4
> #define VI_VIP_H_ACTIVE_PERIOD_SFT 16 /* active pixels/
line, must be
> even */ @@ -89,26 +97,26 @@
> #define VI_VIP_V_ACTIVE_PERIOD_SFT 16 /* active lines */
> #define VI_VIP_V_ACTIVE_START_SFT 0
>
> -#define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x00c4
> -#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x00c8
> +#define TEGRA_VI_VB0_START_ADDRESS(n) (0x00c4 + (n) *
44)
> +#define TEGRA_VI_VB0_BASE_ADDRESS(n) (0x00c8 + (n) *
44)
> #define TEGRA_VI_VB0_START_ADDRESS_U 0x00cc
> #define TEGRA_VI_VB0_BASE_ADDRESS_U 0x00d0
> #define TEGRA_VI_VB0_START_ADDRESS_V 0x00d4
> #define TEGRA_VI_VB0_BASE_ADDRESS_V 0x00d8
>
> -#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x00e0
> -#define VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT 16
> -#define VI_FIRST_OUTPUT_FRAME_WIDTH_SFT 0
> +#define TEGRA_VI_OUTPUT_FRAME_SIZE(n) (0x00e0 + (n) *
24)
> +#define VI_OUTPUT_FRAME_HEIGHT_SFT 16
> +#define VI_OUTPUT_FRAME_WIDTH_SFT 0
>
> -#define TEGRA_VI_VB0_COUNT_FIRST 0x00e4
> +#define TEGRA_VI_VB0_COUNT(n) (0x00e4 + (n) *
24)
>
> -#define TEGRA_VI_VB0_SIZE_FIRST 0x00e8
> -#define VI_VB0_SIZE_FIRST_V_SFT 16
> -#define VI_VB0_SIZE_FIRST_H_SFT 0
> +#define TEGRA_VI_VB0_SIZE(n) (0x00e8 + (n) *
24)
> +#define VI_VB0_SIZE_V_SFT 16
> +#define VI_VB0_SIZE_H_SFT 0
>
> -#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x00ec
> -#define VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT 30
> -#define VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT 0
> +#define TEGRA_VI_VB0_BUFFER_STRIDE(n) (0x00ec + (n) *
24)
> +#define VI_VB0_BUFFER_STRIDE_CHROMA_SFT 30
> +#define VI_VB0_BUFFER_STRIDE_LUMA_SFT 0
>
> #define TEGRA_VI_H_LPF_CONTROL 0x0108
> #define VI_H_LPF_CONTROL_CHROMA_SFT 16
> @@ -136,7 +144,7 @@
> #define VI_CAMERA_CONTROL_TEST_MODE BIT(1)
> #define VI_CAMERA_CONTROL_VIP_ENABLE BIT(0)
>
> -#define TEGRA_VI_VI_ENABLE 0x01a4
> +#define TEGRA_VI_VI_ENABLE(n) (0x01a4 + (n) *
4)
> #define VI_VI_ENABLE_SW_FLOW_CONTROL_OUT1 BIT(1)
> #define VI_VI_ENABLE_FIRST_OUTPUT_TO_MEM_DISABLE BIT(0)
>
> @@ -366,8 +374,8 @@ static void tegra20_channel_vi_buffer_setup(struct
> tegra_vi_channel *chan, case V4L2_PIX_FMT_VYUY:
> case V4L2_PIX_FMT_YUYV:
> case V4L2_PIX_FMT_YVYU:
> - tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,
base);
> - tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS_FIRST,
base +
> chan->start_offset); + tegra20_vi_write(chan,
> TEGRA_VI_VB0_BASE_ADDRESS(OUT_1), base); + tegra20_vi_write(chan,
> TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
> }
> }
> @@ -455,6 +463,7 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) int stride_l = chan->format.bytesperline;
> int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
> output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> + int output_channel = OUT_1;
> int main_output_format;
> int yuv_output_format;
>
> @@ -472,33 +481,33 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) /* Set up raise-on-edge, so we get an interrupt on
> end of frame. */ tegra20_vi_write(chan, TEGRA_VI_VI_RAISE,
> VI_VI_RAISE_ON_EDGE);
>
> - tegra20_vi_write(chan, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
> + tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> yuv_output_format <<
VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> main_output_format <<
VI_OUTPUT_OUTPUT_FORMAT_SFT);
>
> /* Set up frame size */
> - tegra20_vi_write(chan, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
> - height << VI_FIRST_OUTPUT_FRAME_HEIGHT_SFT |
> - width << VI_FIRST_OUTPUT_FRAME_WIDTH_SFT);
> + tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> + height << VI_OUTPUT_FRAME_HEIGHT_SFT |
> + width << VI_OUTPUT_FRAME_WIDTH_SFT);
>
> /* First output memory enabled */
> - tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
> + tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
>
> /* Set the number of frames in the buffer */
> - tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT_FIRST, 1);
> + tegra20_vi_write(chan, TEGRA_VI_VB0_COUNT(output_channel), 1);
>
> /* Set up buffer frame size */
> - tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE_FIRST,
> - height << VI_VB0_SIZE_FIRST_V_SFT |
> - width << VI_VB0_SIZE_FIRST_H_SFT);
> + tegra20_vi_write(chan, TEGRA_VI_VB0_SIZE(output_channel),
> + height << VI_VB0_SIZE_V_SFT |
> + width << VI_VB0_SIZE_H_SFT);
>
> - tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
> - stride_l << VI_VB0_BUFFER_STRIDE_FIRST_LUMA_SFT |
> - stride_c <<
VI_VB0_BUFFER_STRIDE_FIRST_CHROMA_SFT);
> + tegra20_vi_write(chan, TEGRA_VI_VB0_BUFFER_STRIDE(output_channel),
> + stride_l << VI_VB0_BUFFER_STRIDE_LUMA_SFT |
> + stride_c << VI_VB0_BUFFER_STRIDE_CHROMA_SFT);
>
> - tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE, 0);
> + tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> }
>
> static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> @@ -607,6 +616,7 @@ static int tegra20_vip_start_streaming(struct
> tegra_vip_channel *vip_chan) struct tegra_vi_channel *vi_chan =
> v4l2_get_subdev_hostdata(&vip_chan->subdev); int width =
> vi_chan->format.width;
> int height = vi_chan->format.height;
> + int output_channel = OUT_1;
>
> unsigned int main_input_format;
> unsigned int yuv_input_format;
> @@ -637,10 +647,10 @@ static int tegra20_vip_start_streaming(struct
> tegra_vip_channel *vip_chan) GENMASK(9, 2) << VI_DATA_INPUT_SFT);
> tegra20_vi_write(vi_chan, TEGRA_VI_PIN_INVERSION, 0);
>
> - tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT_1,
> - VI_CONT_SYNCPT_OUT_1_CONTINUOUS_SYNCPT |
> + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> - << VI_CONT_SYNCPT_OUT_1_SYNCPT_IDX_SFT);
> + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
>
> tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL,
> VI_CAMERA_CONTROL_STOP_CAPTURE);
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
@ 2025-09-02 1:09 ` Mikko Perttunen
2025-09-02 5:11 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 1:09 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
> of existing YUV422_8 2X8.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
> 1 file changed, 69 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> 67631e0c9ffc..b466fe7f4504 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct
> tegra_vi_channel *chan, case MEDIA_BUS_FMT_YVYU8_2X8:
> (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
> break;
> + /* RAW8 */
> + case MEDIA_BUS_FMT_SBGGR8_1X8:
> + case MEDIA_BUS_FMT_SGBRG8_1X8:
> + case MEDIA_BUS_FMT_SGRBG8_1X8:
> + case MEDIA_BUS_FMT_SRGGB8_1X8:
> + /* RAW10 */
> + case MEDIA_BUS_FMT_SBGGR10_1X10:
> + case MEDIA_BUS_FMT_SGBRG10_1X10:
> + case MEDIA_BUS_FMT_SGRBG10_1X10:
> + case MEDIA_BUS_FMT_SRGGB10_1X10:
> + (*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
Should this be main_input_format instead of yuv_input_format?
> + break;
> }
> }
>
> @@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct
> tegra_vi_channel *chan, case V4L2_PIX_FMT_YVU420:
> (*main_output_format) =
VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
> break;
> + /* RAW8 */
> + case V4L2_PIX_FMT_SBGGR8:
> + case V4L2_PIX_FMT_SGBRG8:
> + case V4L2_PIX_FMT_SGRBG8:
> + case V4L2_PIX_FMT_SRGGB8:
> + /* RAW10 */
> + case V4L2_PIX_FMT_SBGGR10:
> + case V4L2_PIX_FMT_SGBRG10:
> + case V4L2_PIX_FMT_SGRBG10:
> + case V4L2_PIX_FMT_SRGGB10:
> + (*main_output_format) =
VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
> + break;
> }
> }
>
> @@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct
> tegra_vi_channel *chan) case V4L2_PIX_FMT_VYUY:
> case V4L2_PIX_FMT_YUYV:
> case V4L2_PIX_FMT_YVYU:
> + /* RAW8 */
> + case V4L2_PIX_FMT_SRGGB8:
> + case V4L2_PIX_FMT_SGRBG8:
> + case V4L2_PIX_FMT_SGBRG8:
> + case V4L2_PIX_FMT_SBGGR8:
> + /* RAW10 */
> + case V4L2_PIX_FMT_SRGGB10:
> + case V4L2_PIX_FMT_SGRBG10:
> + case V4L2_PIX_FMT_SGBRG10:
> + case V4L2_PIX_FMT_SBGGR10:
> if (chan->vflip)
> chan->start_offset += stride * (height - 1);
> if (chan->hflip)
> @@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct
> tegra_vi_channel *chan, tegra20_vi_write(chan,
> TEGRA_VI_VB0_BASE_ADDRESS(OUT_1), base); tegra20_vi_write(chan,
> TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
> + /* RAW8 */
> + case V4L2_PIX_FMT_SRGGB8:
> + case V4L2_PIX_FMT_SGRBG8:
> + case V4L2_PIX_FMT_SGBRG8:
> + case V4L2_PIX_FMT_SBGGR8:
> + /* RAW10 */
> + case V4L2_PIX_FMT_SRGGB10:
> + case V4L2_PIX_FMT_SGRBG10:
> + case V4L2_PIX_FMT_SGBRG10:
> + case V4L2_PIX_FMT_SBGGR10:
> + tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2),
base);
> + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2),
base +
> chan->start_offset); + break;
> }
> }
>
> @@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void
> *data) static void tegra20_camera_capture_setup(struct tegra_vi_channel
> *chan) {
> u32 output_fourcc = chan->format.pixelformat;
> + u32 data_type = chan->fmtinfo->img_dt;
> int width = chan->format.width;
> int height = chan->format.height;
> int stride_l = chan->format.bytesperline;
> int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
> output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> - int output_channel = OUT_1;
> + int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> + data_type == TEGRA_IMAGE_DT_RAW10) ?
> + OUT_2 : OUT_1;
> int main_output_format;
> int yuv_output_format;
>
> @@ -580,6 +630,20 @@ static const struct tegra_video_format
> tegra20_video_formats[] = { TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16,
> YVYU),
> TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
> TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
> + TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
> + TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
> + TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
> + TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
> + /* RAW 8 */
> + TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
> + TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
> + TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
> + TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
> + /* RAW 10 */
> + TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
> + TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
> + TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
> + TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
> };
>
> const struct tegra_vi_soc tegra20_vi_soc = {
> @@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> {
> struct tegra_vi_channel *vi_chan =
> v4l2_get_subdev_hostdata(&vip_chan->subdev); + u32 data_type =
> vi_chan->fmtinfo->img_dt;
> int width = vi_chan->format.width;
> int height = vi_chan->format.height;
> - int output_channel = OUT_1;
> + int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> + data_type == TEGRA_IMAGE_DT_RAW10) ?
> + OUT_2 : OUT_1;
>
> unsigned int main_input_format;
> unsigned int yuv_input_format;
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride
2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
@ 2025-09-02 1:16 ` Mikko Perttunen
0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 1:16 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Luma buffer stride is calculated by multiplying height in pixels of image
> by bytes per line. Adjust that value accordingly.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/tegra20.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/staging/media/tegra-video/tegra20.c
> b/drivers/staging/media/tegra-video/tegra20.c index
> b466fe7f4504..a06afe91d2de 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -496,7 +496,7 @@ static void tegra20_camera_capture_setup(struct
> tegra_vi_channel *chan) u32 data_type = chan->fmtinfo->img_dt;
> int width = chan->format.width;
> int height = chan->format.height;
> - int stride_l = chan->format.bytesperline;
> + int stride_l = chan->format.bytesperline * height;
> int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
> output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
Reviewed-by: Mikko Perttunen <mperttunen@nvidia.com>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
@ 2025-09-02 2:38 ` Mikko Perttunen
2025-09-02 5:51 ` Svyatoslav Ryhel
2025-09-02 7:11 ` Dan Carpenter
0 siblings, 2 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 2:38 UTC (permalink / raw)
To: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, Svyatoslav Ryhel
Cc: linux-media, linux-tegra, dri-devel, devicetree, linux-kernel,
linux-clk, linux-staging
On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
>
> Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> drivers/staging/media/tegra-video/csi.c | 12 +
> drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> drivers/staging/media/tegra-video/vi.h | 2 +
> drivers/staging/media/tegra-video/video.c | 2 +
> 4 files changed, 553 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> index 2f9907a20db1..714ce52a793c 100644
> --- a/drivers/staging/media/tegra-video/csi.c
> +++ b/drivers/staging/media/tegra-video/csi.c
> @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> pm_runtime_disable(&pdev->dev);
> }
>
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> +extern const struct tegra_csi_soc tegra20_csi_soc;
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> +extern const struct tegra_csi_soc tegra30_csi_soc;
> +#endif
> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> extern const struct tegra_csi_soc tegra210_csi_soc;
> #endif
>
> static const struct of_device_id tegra_csi_of_id_table[] = {
> +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> + { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> +#endif
> +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> + { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> +#endif
> #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> #endif
> diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> index a06afe91d2de..e528ba280ae4 100644
> --- a/drivers/staging/media/tegra-video/tegra20.c
> +++ b/drivers/staging/media/tegra-video/tegra20.c
> @@ -4,6 +4,9 @@
> *
> * Copyright (C) 2023 SKIDATA GmbH
> * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> + *
> + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> */
>
> /*
> @@ -12,12 +15,16 @@
> */
>
> #include <linux/bitfield.h>
> +#include <linux/clk.h>
> +#include <linux/clk/tegra.h>
> #include <linux/delay.h>
> #include <linux/host1x.h>
> +#include <linux/iopoll.h>
> #include <linux/kernel.h>
> #include <linux/kthread.h>
> #include <linux/v4l2-mediabus.h>
>
> +#include "csi.h"
> #include "vip.h"
> #include "vi.h"
>
> @@ -42,6 +49,9 @@ enum {
> #define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
> #define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
>
> +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n) (0x0070 + (n) * 8)
> +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n) (0x0074 + (n) * 8)
> +
> #define TEGRA_VI_VI_INPUT_CONTROL 0x0088
> #define VI_INPUT_FIELD_DETECT BIT(27)
> #define VI_INPUT_BT656 BIT(25)
> @@ -87,6 +97,8 @@ enum {
> #define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
> #define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> #define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> #define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
>
> #define TEGRA_VI_VIP_H_ACTIVE 0x00a4
> @@ -151,8 +163,106 @@ enum {
> #define TEGRA_VI_VI_RAISE 0x01ac
> #define VI_VI_RAISE_ON_EDGE BIT(0)
>
> +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n) (0x01d8 + (n) * 8)
> +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n) (0x01dc + (n) * 8)
> +#define TEGRA_VI_CSI_PP_H_ACTIVE(n) (0x01e8 + (n) * 8)
> +#define TEGRA_VI_CSI_PP_V_ACTIVE(n) (0x01ec + (n) * 8)
> +
> +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0000
> +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0008
> +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n) (0x0010 + (n) * 0x2c)
> +#define CSI_SKIP_PACKET_THRESHOLD(n) (((n) & 0xff) << 16)
> +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n) (0x0018 + (n) * 0x2c)
> +#define CSI_PP_PAD_FRAME_PAD0S (0 << 28)
> +#define CSI_PP_PAD_FRAME_PAD1S (1 << 28)
> +#define CSI_PP_PAD_FRAME_NOPAD (2 << 28)
> +#define CSI_PP_HEADER_EC_ENABLE BIT(27)
> +#define CSI_PP_PAD_SHORT_LINE_PAD0S (0 << 24)
> +#define CSI_PP_PAD_SHORT_LINE_PAD1S (1 << 24)
> +#define CSI_PP_PAD_SHORT_LINE_NOPAD (2 << 24)
> +#define CSI_PP_EMBEDDED_DATA_EMBEDDED BIT(20)
> +#define CSI_PP_OUTPUT_FORMAT_ARBITRARY (0 << 16)
> +#define CSI_PP_OUTPUT_FORMAT_PIXEL (1 << 16)
> +#define CSI_PP_OUTPUT_FORMAT_PIXEL_REP (2 << 16)
> +#define CSI_PP_OUTPUT_FORMAT_STORE (3 << 16)
> +#define CSI_PP_VIRTUAL_CHANNEL_ID(n) (((n) - 1) << 14)
> +#define CSI_PP_DATA_TYPE(n) ((n) << 8)
> +#define CSI_PP_CRC_CHECK_ENABLE BIT(7)
> +#define CSI_PP_WORD_COUNT_HEADER BIT(6)
> +#define CSI_PP_DATA_IDENTIFIER_ENABLE BIT(5)
> +#define CSI_PP_PACKET_HEADER_SENT BIT(4)
> +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n) (0x001c + (n) * 0x2c)
> +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n) (0x0020 + (n) * 0x2c)
> +#define TEGRA_CSI_PIXEL_STREAM_GAP(n) (0x0024 + (n) * 0x2c)
> +#define CSI_PP_FRAME_MIN_GAP(n) (((n) & 0xffff) << 16)
> +#define CSI_PP_LINE_MIN_GAP(n) (((n) & 0xffff))
> +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n) (0x0028 + (n) * 0x2c)
> +#define CSI_PP_START_MARKER_FRAME_MAX(n) (((n) & 0xf) << 12)
> +#define CSI_PP_START_MARKER_FRAME_MIN(n) (((n) & 0xf) << 8)
> +#define CSI_PP_VSYNC_START_MARKER BIT(4)
> +#define CSI_PP_SINGLE_SHOT BIT(2)
> +#define CSI_PP_NOP 0
> +#define CSI_PP_ENABLE 1
> +#define CSI_PP_DISABLE 2
> +#define CSI_PP_RST 3
> +#define TEGRA_CSI_PHY_CIL_COMMAND 0x0068
> +#define CSI_A_PHY_CIL_NOP 0x0
> +#define CSI_A_PHY_CIL_ENABLE 0x1
> +#define CSI_A_PHY_CIL_DISABLE 0x2
> +#define CSI_A_PHY_CIL_ENABLE_MASK 0x3
> +#define CSI_B_PHY_CIL_NOP (0x0 << 16)
> +#define CSI_B_PHY_CIL_ENABLE (0x1 << 16)
> +#define CSI_B_PHY_CIL_DISABLE (0x2 << 16)
> +#define CSI_B_PHY_CIL_ENABLE_MASK (0x3 << 16)
> +#define TEGRA_CSI_PHY_CIL_CONTROL0(n) (0x006c + (n) * 4)
> +#define CSI_CONTINUOUS_CLOCK_MODE_ENABLE BIT(5)
> +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0078
> +#define TEGRA_CSI_CSI_CIL_STATUS 0x007c
> +#define CSI_MIPI_AUTO_CAL_DONE BIT(15)
> +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0080
> +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0084
> +#define TEGRA_CSI_CSI_READONLY_STATUS 0x0088
> +#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x008c
> +#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0090
> +#define TEGRA_CSI_CIL_PAD_CONFIG0(n) (0x0094 + (n) * 8)
> +#define TEGRA_CSI_CIL_PAD_CONFIG1(n) (0x0098 + (n) * 8)
> +#define TEGRA_CSI_CIL_PAD_CONFIG 0x00a4
> +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x00a8
> +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x00ac
> +#define CSI_CIL_MIPI_CAL_STARTCAL BIT(31)
> +#define CSI_CIL_MIPI_CAL_OVERIDE_A BIT(30)
> +#define CSI_CIL_MIPI_CAL_OVERIDE_B BIT(30)
> +#define CSI_CIL_MIPI_CAL_NOISE_FLT(n) (((n) & 0xf) << 26)
> +#define CSI_CIL_MIPI_CAL_PRESCALE(n) (((n) & 0x3) << 24)
> +#define CSI_CIL_MIPI_CAL_SEL_A BIT(21)
> +#define CSI_CIL_MIPI_CAL_SEL_B BIT(21)
> +#define CSI_CIL_MIPI_CAL_HSPDOS(n) (((n) & 0x1f) << 16)
> +#define CSI_CIL_MIPI_CAL_HSPUOS(n) (((n) & 0x1f) << 8)
> +#define CSI_CIL_MIPI_CAL_TERMOS(n) (((n) & 0x1f))
> +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x00b0
> +#define TEGRA_CSI_CLKEN_OVERRIDE 0x00b4
> +#define TEGRA_CSI_DEBUG_CONTROL 0x00b8
> +#define CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED BIT(0)
> +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 BIT(4)
> +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 BIT(5)
> +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_2 BIT(6)
> +#define CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v) ((v) << (8 + 8 * (n)))
> +#define TEGRA_CSI_DEBUG_COUNTER(n) (0x00bc + (n) * 4)
> +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n) (0x00c8 + (n) * 4)
> +#define CSI_PP_EXP_FRAME_HEIGHT(n) (((n) & 0x1fff) << 16)
> +#define CSI_PP_MAX_CLOCKS(n) (((n) & 0xfff) << 4)
> +#define CSI_PP_LINE_TIMEOUT_ENABLE BIT(0)
> +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x00d0
> +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x00d4
> +#define CSI_PAD_DRIV_DN_REF(n) (((n) & 0x7) << 16)
> +#define CSI_PAD_DRIV_UP_REF(n) (((n) & 0x7) << 8)
> +#define CSI_PAD_TERM_REF(n) (((n) & 0x7) << 0)
> +#define TEGRA_CSI_CSI_CILA_STATUS 0x00d8
> +#define TEGRA_CSI_CSI_CILB_STATUS 0x00dc
> +
> /* --------------------------------------------------------------------------
> - * VI
> + * Read and Write helpers
> */
>
> static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> writel(val, chan->vi->iomem + addr);
> }
>
> +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> +{
> + return readl(chan->vi->iomem + addr);
> +}
> +
> +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> +{
> + writel(val, csi_chan->csi->iomem + addr);
> +}
> +
> +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> +{
> + return readl(csi_chan->csi->iomem + addr);
> +}
> +
> +/* --------------------------------------------------------------------------
> + * VI
> + */
> +
> /*
> * Get the main input format (YUV/RGB...) and the YUV variant as values to
> * be written into registers for the current VI input mbus code.
> @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> {
> struct tegra_vi *vi = chan->vi;
> - struct host1x_syncpt *out_sp;
> + struct host1x_syncpt *out_sp, *fs_sp;
>
> out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> if (!out_sp)
> - return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> + return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
>
> chan->mw_ack_sp[0] = out_sp;
>
> + fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> + if (!fs_sp)
> + return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> +
> + chan->frame_start_sp[0] = fs_sp;
> +
> return 0;
> }
>
> static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> {
> host1x_syncpt_put(chan->mw_ack_sp[0]);
> + host1x_syncpt_put(chan->frame_start_sp[0]);
> }
>
> static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> struct tegra_channel_buffer *buf)
> {
> + struct v4l2_subdev *csi_subdev = NULL;
> + struct tegra_csi_channel *csi_chan = NULL;
> + u32 port;
> int err;
>
> - chan->next_out_sp_idx++;
> + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> + if (csi_subdev) {
> + /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> + if (!strncmp(csi_subdev->name, "channel", 7)) {
> + csi_chan = to_csi_chan(csi_subdev);
> + port = csi_chan->csi_port_nums[0] & 1;
> + }
> + }
tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
>
> tegra20_channel_vi_buffer_setup(chan, buf);
>
> - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> + if (csi_chan) {
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> + CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> +
> + chan->next_fs_sp_idx++;
> + err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> + TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> + if (err) {
> + host1x_syncpt_incr(chan->frame_start_sp[0]);
This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
(I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
> + if (err != -ERESTARTSYS)
> + dev_err_ratelimited(&chan->video.dev,
> + "frame start syncpt timeout: %d\n", err);
> + }
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> + CSI_PP_DISABLE);
> + } else {
> + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> + }
>
> - /* Wait for syncpt counter to reach frame start event threshold */
> + chan->next_out_sp_idx++;
> err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> if (err) {
> host1x_syncpt_incr(chan->mw_ack_sp[0]);
> - dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> - release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> - return err;
> + if (err != -ERESTARTSYS)
> + dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> }
>
> - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> - VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> + if (!csi_chan)
> + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> + VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
>
> release_buffer(chan, buf, VB2_BUF_STATE_DONE);
>
> - return 0;
> + return err;
> }
>
> static int tegra20_chan_capture_kthread_start(void *data)
> @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> data_type == TEGRA_IMAGE_DT_RAW10) ?
> OUT_2 : OUT_1;
> - int main_output_format;
> - int yuv_output_format;
> -
> - tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> -
> - /*
> - * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> - * for luminance, which is the default and means not to touch
> - * anything.
> - */
> - tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> - 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> - 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> -
> - /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> - tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> -
> - tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> - (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> - (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> - yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> - main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
>
> /* Set up frame size */
> tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> }
>
> +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> +{
> + struct tegra_csi *csi = csi_chan->csi;
> + void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> + unsigned int port = csi_chan->csi_port_nums[0] & 1;
> + u32 value, pp, cil;
> + int ret;
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> + CSI_CIL_MIPI_CAL_HSPDOS(4) |
> + CSI_CIL_MIPI_CAL_HSPUOS(3) |
> + CSI_CIL_MIPI_CAL_TERMOS(0));
> + tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> + CSI_PAD_DRIV_DN_REF(5) |
> + CSI_PAD_DRIV_UP_REF(7) |
> + CSI_PAD_TERM_REF(0));
> +
> + /* CSI B */
> + value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> + CSI_CIL_MIPI_CAL_TERMOS(4);
> +
> + if (port == PORT_B || csi_chan->numlanes == 4)
> + value |= CSI_CIL_MIPI_CAL_SEL_B;
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> +
> + /* CSI A */
> + value = CSI_CIL_MIPI_CAL_STARTCAL |
> + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> + CSI_CIL_MIPI_CAL_TERMOS(4);
> +
> + if (port == PORT_A)
> + value |= CSI_CIL_MIPI_CAL_SEL_A;
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> +
> + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> + value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> + if (ret < 0) {
> + dev_warn(csi->dev, "MIPI calibration timeout!\n");
> + goto exit;
> + }
> +
> + /* clear status */
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> + !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> + if (ret < 0) {
> + dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> + goto exit;
> + }
> +
> + pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> + cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> + if (pp | cil) {
> + dev_warn(csi->dev, "Calibration status not been cleared!\n");
> + ret = -EINVAL;
> + goto exit;
> + }
> +
> +exit:
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> +
> + /* un-select to avoid interference with DSI */
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> + CSI_CIL_MIPI_CAL_TERMOS(4));
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> + CSI_CIL_MIPI_CAL_TERMOS(4));
> +
> + return ret;
> +}
> +
> static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> {
> struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> struct media_pipeline *pipe = &chan->video.pipe;
> + struct v4l2_subdev *csi_subdev, *src_subdev;
> + struct tegra_csi_channel *csi_chan = NULL;
> int err;
>
> + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> + if (csi_subdev) {
> + if (!strncmp(csi_subdev->name, "channel", 7))
> + csi_chan = to_csi_chan(csi_subdev);
> + }
> +
> + chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
>
> err = video_device_pipeline_start(&chan->video, pipe);
> if (err)
> goto error_pipeline_start;
>
> - tegra20_camera_capture_setup(chan);
> + /*
> + * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> + * for luminance, which is the default and means not to touch
> + * anything.
> + */
> + tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> + 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> + 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> +
> + /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> + tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
>
> err = tegra_channel_set_stream(chan, true);
> if (err)
> goto error_set_stream;
>
> + tegra20_camera_capture_setup(chan);
> +
> + if (csi_chan) {
> + /*
> + * TRM has incorrectly documented to wait for done status from
> + * calibration logic after CSI interface power on.
> + * As per the design, calibration results are latched and applied
> + * to the pads only when the link is in LP11 state which will happen
> + * during the sensor stream-on.
> + * CSI subdev stream-on triggers start of MIPI pads calibration.
> + * Wait for calibration to finish here after sensor subdev stream-on.
> + */
> + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> + if (!src_subdev->s_stream_enabled) {
> + err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> + if (err < 0 && err != -ENOIOCTLCMD)
> + goto error_set_stream;
> + }
> +
> + tegra20_csi_pad_calibration(csi_chan);
> + }
> +
> chan->sequence = 0;
>
> chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> {
> struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> + struct v4l2_subdev *src_subdev;
>
> if (chan->kthread_start_capture) {
> kthread_stop(chan->kthread_start_capture);
> chan->kthread_start_capture = NULL;
> }
>
> + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> + if (src_subdev->s_stream_enabled)
> + v4l2_subdev_call(src_subdev, video, s_stream, false);
> +
> tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> tegra_channel_set_stream(chan, false);
> video_device_pipeline_stop(&chan->video);
> @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> .default_video_format = &tegra20_video_formats[0],
> .ops = &tegra20_vi_ops,
> .hw_revision = 1,
> - .vi_max_channels = 1, /* parallel input (VIP) */
> + .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> .vi_max_clk_hz = 450000000,
> .has_h_v_flip = true,
> };
>
> +/* --------------------------------------------------------------------------
> + * CSI
> + */
> +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> +{
> + tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> + CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> + CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> + CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> +}
> +
> +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> + u8 portno)
> +{
> + struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> + int width = vi_chan->format.width;
> + int height = vi_chan->format.height;
> + u32 data_type = vi_chan->fmtinfo->img_dt;
> + u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> + int output_channel = OUT_1;
> +
> + unsigned int main_output_format, yuv_output_format;
> + unsigned int port = portno & 1;
> + u32 value;
> +
> + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> +
> + switch (data_type) {
> + case TEGRA_IMAGE_DT_RAW8:
> + case TEGRA_IMAGE_DT_RAW10:
> + output_channel = OUT_2;
> + if (port == PORT_A)
> + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> + else
> + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> + break;
> + }
> +
> + tegra20_csi_capture_clean(csi_chan);
> +
> + /* CSI port cleanup */
> + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> + tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> + CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> + CSI_PP_EXP_FRAME_HEIGHT(height) |
> + CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> + CSI_PP_LINE_TIMEOUT_ENABLE);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> + CSI_PP_OUTPUT_FORMAT_PIXEL |
> + CSI_PP_DATA_TYPE(data_type) |
> + CSI_PP_CRC_CHECK_ENABLE |
> + CSI_PP_WORD_COUNT_HEADER |
> + CSI_PP_DATA_IDENTIFIER_ENABLE |
> + CSI_PP_PACKET_HEADER_SENT |
> + port);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> + CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> + (csi_chan->numlanes - 1));
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> + CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> + 0x5); /* Clock settle time */
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> + host1x_syncpt_id(vi_chan->frame_start_sp[0])
> + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> + host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> +
> + value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> + CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> + CSI_PP_DISABLE);
> +
> + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> + yuv_output_format | main_output_format);
> +
> + return 0;
> +};
> +
> +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> +{
> + struct tegra_csi *csi = csi_chan->csi;
> + unsigned int port = portno & 1;
> + u32 value;
> +
> + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> + dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> +
> + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> + dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> +
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> + CSI_PP_DISABLE);
> +
> + if (csi_chan->numlanes == 4) {
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> + CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> + } else {
> + value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> + CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> + }
> +}
> +
> +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> +{
> + u8 *portnos = csi_chan->csi_port_nums;
> + int ret, i;
> +
> + for (i = 0; i < csi_chan->numgangports; i++) {
> + ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> + if (ret)
> + goto stream_start_fail;
> + }
> +
> + return 0;
> +
> +stream_start_fail:
> + for (i = i - 1; i >= 0; i--)
> + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> +
> + return ret;
> +}
> +
> +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> +{
> + u8 *portnos = csi_chan->csi_port_nums;
> + int i;
> +
> + for (i = 0; i < csi_chan->numgangports; i++)
> + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> +}
> +
> +/* Tegra20 CSI operations */
> +static const struct tegra_csi_ops tegra20_csi_ops = {
> + .csi_start_streaming = tegra20_csi_start_streaming,
> + .csi_stop_streaming = tegra20_csi_stop_streaming,
> +};
> +
> +static const char * const tegra20_csi_clks[] = {
> + "csi",
> +};
> +
> +/* Tegra20 CSI SoC data */
> +const struct tegra_csi_soc tegra20_csi_soc = {
> + .ops = &tegra20_csi_ops,
> + .csi_max_channels = 2, /* CSI-A and CSI-B */
> + .clk_names = tegra20_csi_clks,
> + .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> + .has_mipi_calibration = false,
> +};
> +
> +static const char * const tegra30_csi_clks[] = {
> + "csi",
> + "csia_pad",
> + "csib_pad",
> +};
> +
> +/* Tegra30 CSI SoC data */
> +const struct tegra_csi_soc tegra30_csi_soc = {
> + .ops = &tegra20_csi_ops,
> + .csi_max_channels = 2, /* CSI-A and CSI-B */
> + .clk_names = tegra30_csi_clks,
> + .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> + .has_mipi_calibration = false,
> +};
> +
> /* --------------------------------------------------------------------------
> * VIP
> */
> @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> data_type == TEGRA_IMAGE_DT_RAW10) ?
> OUT_2 : OUT_1;
>
> - unsigned int main_input_format;
> - unsigned int yuv_input_format;
> + unsigned int main_input_format, yuv_input_format;
> + unsigned int main_output_format, yuv_output_format;
>
> tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
>
> tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
>
> @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
>
> tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
>
> + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> + yuv_output_format | main_output_format);
> +
> return 0;
> }
>
> diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> index cac0c0d0e225..c02517c9e09b 100644
> --- a/drivers/staging/media/tegra-video/vi.h
> +++ b/drivers/staging/media/tegra-video/vi.h
> @@ -127,6 +127,7 @@ struct tegra_vi {
> * frame through host1x syncpoint counters (On Tegra20 used for the
> * OUT_1 syncpt)
> * @sp_incr_lock: protects cpu syncpoint increment.
> + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> *
> * @kthread_start_capture: kthread to start capture of single frame when
> @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> /* protects the cpu syncpoint increment */
> spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> u32 next_out_sp_idx;
> + u32 next_fs_sp_idx;
>
> struct task_struct *kthread_start_capture;
> wait_queue_head_t start_wait;
> diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> index a25885f93cd7..8fa660431eb0 100644
> --- a/drivers/staging/media/tegra-video/video.c
> +++ b/drivers/staging/media/tegra-video/video.c
> @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
>
> static const struct of_device_id host1x_video_subdevs[] = {
> #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> + { .compatible = "nvidia,tegra20-csi", },
> { .compatible = "nvidia,tegra20-vip", },
> { .compatible = "nvidia,tegra20-vi", },
> #endif
> #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> + { .compatible = "nvidia,tegra30-csi", },
> { .compatible = "nvidia,tegra30-vip", },
> { .compatible = "nvidia,tegra30-vi", },
> #endif
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
2025-09-02 0:46 ` Mikko Perttunen
@ 2025-09-02 5:05 ` Svyatoslav Ryhel
2025-09-02 6:35 ` Mikko Perttunen
0 siblings, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02 5:05 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 2 вер. 2025 р. о 03:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> > all MIPI calibration pads were part of VI block.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> > drivers/staging/media/tegra-video/csi.c | 12 +++++++-----
> > drivers/staging/media/tegra-video/csi.h | 1 +
> > drivers/staging/media/tegra-video/tegra210.c | 1 +
> > 3 files changed, 9 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c
> > b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> > 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> > *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
> > return 0;
> >
> > - chan->mipi = tegra_mipi_request(csi->dev, node);
> > - if (IS_ERR(chan->mipi)) {
> > - ret = PTR_ERR(chan->mipi);
> > - chan->mipi = NULL;
> > - dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> > + if (csi->soc->has_mipi_calibration) {
> > + chan->mipi = tegra_mipi_request(csi->dev, node);
>
> The way I would read 'soc->has_mipi_calibration' is that this device (CSI)
> contains the MIPI calibration hardware. I.e. the opposite of here. I would
> invert the logic and optionally call it e.g. 'internal_mipi_calib'.
>
> A cleaner way to do this might be to always call tegra_mipi_request et al. --
> on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the
> callbacks registered in the MIPI driver as we discussed before. That way the
> CSI driver won't need separate code paths for SoCs with internal MIPI
> calibration and SoCs with the external MIPI calibration device.
>
So basically MIPI calibration device for Tegra20/Tegra30 has to be
created within CSI and when MIPI calibration is requested, CSI phandle
is used. Question: may I use a dedicated node for MIPI calibration
within CSI or it has to use CSI node itself? With dedicated node
configuration should be much simpler and can help avoiding probe of
entire.
> Cheers,
> Mikko
>
> > + if (IS_ERR(chan->mipi)) {
> > + ret = PTR_ERR(chan->mipi);
> > + chan->mipi = NULL;
> > + dev_err(csi->dev, "failed to get mipi device:
> %d\n", ret);
> > + }
> > }
> >
> > return ret;
> > diff --git a/drivers/staging/media/tegra-video/csi.h
> > b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> > 100644
> > --- a/drivers/staging/media/tegra-video/csi.h
> > +++ b/drivers/staging/media/tegra-video/csi.h
> > @@ -128,6 +128,7 @@ struct tegra_csi_soc {
> > unsigned int num_clks;
> > const struct tpg_framerate *tpg_frmrate_table;
> > unsigned int tpg_frmrate_table_size;
> > + bool has_mipi_calibration;
> > };
> >
> > /**
> > diff --git a/drivers/staging/media/tegra-video/tegra210.c
> > b/drivers/staging/media/tegra-video/tegra210.c index
> > da99f19a39e7..305472e94af4 100644
> > --- a/drivers/staging/media/tegra-video/tegra210.c
> > +++ b/drivers/staging/media/tegra-video/tegra210.c
> > @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
> > .num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
> > .tpg_frmrate_table = tegra210_tpg_frmrate_table,
> > .tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> > + .has_mipi_calibration = true,
> > };
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16
2025-09-02 1:09 ` Mikko Perttunen
@ 2025-09-02 5:11 ` Svyatoslav Ryhel
0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02 5:11 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 2 вер. 2025 р. о 04:10 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Add support for Bayer formats (RAW8 and RAW10) and YUV422_8 1X16 versions
> > of existing YUV422_8 2X8.
> >
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> > drivers/staging/media/tegra-video/tegra20.c | 71 ++++++++++++++++++++-
> > 1 file changed, 69 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/tegra20.c
> > b/drivers/staging/media/tegra-video/tegra20.c index
> > 67631e0c9ffc..b466fe7f4504 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -186,6 +186,18 @@ static void tegra20_vi_get_input_formats(struct
> > tegra_vi_channel *chan, case MEDIA_BUS_FMT_YVYU8_2X8:
> > (*yuv_input_format) = VI_INPUT_YUV_INPUT_FORMAT_YVYU;
> > break;
> > + /* RAW8 */
> > + case MEDIA_BUS_FMT_SBGGR8_1X8:
> > + case MEDIA_BUS_FMT_SGBRG8_1X8:
> > + case MEDIA_BUS_FMT_SGRBG8_1X8:
> > + case MEDIA_BUS_FMT_SRGGB8_1X8:
> > + /* RAW10 */
> > + case MEDIA_BUS_FMT_SBGGR10_1X10:
> > + case MEDIA_BUS_FMT_SGBRG10_1X10:
> > + case MEDIA_BUS_FMT_SGRBG10_1X10:
> > + case MEDIA_BUS_FMT_SRGGB10_1X10:
> > + (*yuv_input_format) = VI_INPUT_INPUT_FORMAT_BAYER;
>
> Should this be main_input_format instead of yuv_input_format?
>
Yes, it should be main_input_format, you are correct. Thank you.
> > + break;
> > }
> > }
> >
> > @@ -220,6 +232,18 @@ static void tegra20_vi_get_output_formats(struct
> > tegra_vi_channel *chan, case V4L2_PIX_FMT_YVU420:
> > (*main_output_format) =
> VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR;
> > break;
> > + /* RAW8 */
> > + case V4L2_PIX_FMT_SBGGR8:
> > + case V4L2_PIX_FMT_SGBRG8:
> > + case V4L2_PIX_FMT_SGRBG8:
> > + case V4L2_PIX_FMT_SRGGB8:
> > + /* RAW10 */
> > + case V4L2_PIX_FMT_SBGGR10:
> > + case V4L2_PIX_FMT_SGBRG10:
> > + case V4L2_PIX_FMT_SGRBG10:
> > + case V4L2_PIX_FMT_SRGGB10:
> > + (*main_output_format) =
> VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT;
> > + break;
> > }
> > }
> >
> > @@ -300,6 +324,16 @@ static void tegra20_channel_queue_setup(struct
> > tegra_vi_channel *chan) case V4L2_PIX_FMT_VYUY:
> > case V4L2_PIX_FMT_YUYV:
> > case V4L2_PIX_FMT_YVYU:
> > + /* RAW8 */
> > + case V4L2_PIX_FMT_SRGGB8:
> > + case V4L2_PIX_FMT_SGRBG8:
> > + case V4L2_PIX_FMT_SGBRG8:
> > + case V4L2_PIX_FMT_SBGGR8:
> > + /* RAW10 */
> > + case V4L2_PIX_FMT_SRGGB10:
> > + case V4L2_PIX_FMT_SGRBG10:
> > + case V4L2_PIX_FMT_SGBRG10:
> > + case V4L2_PIX_FMT_SBGGR10:
> > if (chan->vflip)
> > chan->start_offset += stride * (height - 1);
> > if (chan->hflip)
> > @@ -365,6 +399,19 @@ static void tegra20_channel_vi_buffer_setup(struct
> > tegra_vi_channel *chan, tegra20_vi_write(chan,
> > TEGRA_VI_VB0_BASE_ADDRESS(OUT_1), base); tegra20_vi_write(chan,
> > TEGRA_VI_VB0_START_ADDRESS(OUT_1), base + chan->start_offset); break;
> > + /* RAW8 */
> > + case V4L2_PIX_FMT_SRGGB8:
> > + case V4L2_PIX_FMT_SGRBG8:
> > + case V4L2_PIX_FMT_SGBRG8:
> > + case V4L2_PIX_FMT_SBGGR8:
> > + /* RAW10 */
> > + case V4L2_PIX_FMT_SRGGB10:
> > + case V4L2_PIX_FMT_SGRBG10:
> > + case V4L2_PIX_FMT_SGBRG10:
> > + case V4L2_PIX_FMT_SBGGR10:
> > + tegra20_vi_write(chan, TEGRA_VI_VB0_BASE_ADDRESS(OUT_2),
> base);
> > + tegra20_vi_write(chan, TEGRA_VI_VB0_START_ADDRESS(OUT_2),
> base +
> > chan->start_offset); + break;
> > }
> > }
> >
> > @@ -446,12 +493,15 @@ static int tegra20_chan_capture_kthread_start(void
> > *data) static void tegra20_camera_capture_setup(struct tegra_vi_channel
> > *chan) {
> > u32 output_fourcc = chan->format.pixelformat;
> > + u32 data_type = chan->fmtinfo->img_dt;
> > int width = chan->format.width;
> > int height = chan->format.height;
> > int stride_l = chan->format.bytesperline;
> > int stride_c = (output_fourcc == V4L2_PIX_FMT_YUV420 ||
> > output_fourcc == V4L2_PIX_FMT_YVU420) ? 1 : 0;
> > - int output_channel = OUT_1;
> > + int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > + data_type == TEGRA_IMAGE_DT_RAW10) ?
> > + OUT_2 : OUT_1;
> > int main_output_format;
> > int yuv_output_format;
> >
> > @@ -580,6 +630,20 @@ static const struct tegra_video_format
> > tegra20_video_formats[] = { TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_2X8, 16,
> > YVYU),
> > TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YUV420),
> > TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_2X8, 12, YVU420),
> > + TEGRA20_VIDEO_FMT(YUV422_8, 16, UYVY8_1X16, 16, UYVY),
> > + TEGRA20_VIDEO_FMT(YUV422_8, 16, VYUY8_1X16, 16, VYUY),
> > + TEGRA20_VIDEO_FMT(YUV422_8, 16, YUYV8_1X16, 16, YUYV),
> > + TEGRA20_VIDEO_FMT(YUV422_8, 16, YVYU8_1X16, 16, YVYU),
> > + /* RAW 8 */
> > + TEGRA20_VIDEO_FMT(RAW8, 8, SRGGB8_1X8, 16, SRGGB8),
> > + TEGRA20_VIDEO_FMT(RAW8, 8, SGRBG8_1X8, 16, SGRBG8),
> > + TEGRA20_VIDEO_FMT(RAW8, 8, SGBRG8_1X8, 16, SGBRG8),
> > + TEGRA20_VIDEO_FMT(RAW8, 8, SBGGR8_1X8, 16, SBGGR8),
> > + /* RAW 10 */
> > + TEGRA20_VIDEO_FMT(RAW10, 10, SRGGB10_1X10, 16, SRGGB10),
> > + TEGRA20_VIDEO_FMT(RAW10, 10, SGRBG10_1X10, 16, SGRBG10),
> > + TEGRA20_VIDEO_FMT(RAW10, 10, SGBRG10_1X10, 16, SGBRG10),
> > + TEGRA20_VIDEO_FMT(RAW10, 10, SBGGR10_1X10, 16, SBGGR10),
> > };
> >
> > const struct tegra_vi_soc tegra20_vi_soc = {
> > @@ -606,9 +670,12 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > {
> > struct tegra_vi_channel *vi_chan =
> > v4l2_get_subdev_hostdata(&vip_chan->subdev); + u32 data_type =
> > vi_chan->fmtinfo->img_dt;
> > int width = vi_chan->format.width;
> > int height = vi_chan->format.height;
> > - int output_channel = OUT_1;
> > + int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > + data_type == TEGRA_IMAGE_DT_RAW10) ?
> > + OUT_2 : OUT_1;
> >
> > unsigned int main_input_format;
> > unsigned int yuv_input_format;
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-09-02 2:38 ` Mikko Perttunen
@ 2025-09-02 5:51 ` Svyatoslav Ryhel
2025-09-02 6:17 ` Mikko Perttunen
2025-09-02 7:11 ` Dan Carpenter
1 sibling, 1 reply; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02 5:51 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> >
> > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > ---
> > drivers/staging/media/tegra-video/csi.c | 12 +
> > drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> > drivers/staging/media/tegra-video/vi.h | 2 +
> > drivers/staging/media/tegra-video/video.c | 2 +
> > 4 files changed, 553 insertions(+), 38 deletions(-)
> >
> > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > index 2f9907a20db1..714ce52a793c 100644
> > --- a/drivers/staging/media/tegra-video/csi.c
> > +++ b/drivers/staging/media/tegra-video/csi.c
> > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> > pm_runtime_disable(&pdev->dev);
> > }
> >
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > +#endif
> > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > extern const struct tegra_csi_soc tegra210_csi_soc;
> > #endif
> >
> > static const struct of_device_id tegra_csi_of_id_table[] = {
> > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > + { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > +#endif
> > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > + { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > +#endif
> > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> > #endif
> > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > index a06afe91d2de..e528ba280ae4 100644
> > --- a/drivers/staging/media/tegra-video/tegra20.c
> > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > @@ -4,6 +4,9 @@
> > *
> > * Copyright (C) 2023 SKIDATA GmbH
> > * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > + *
> > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > */
> >
> > /*
> > @@ -12,12 +15,16 @@
> > */
> >
> > #include <linux/bitfield.h>
> > +#include <linux/clk.h>
> > +#include <linux/clk/tegra.h>
> > #include <linux/delay.h>
> > #include <linux/host1x.h>
> > +#include <linux/iopoll.h>
> > #include <linux/kernel.h>
> > #include <linux/kthread.h>
> > #include <linux/v4l2-mediabus.h>
> >
> > +#include "csi.h"
> > #include "vip.h"
> > #include "vi.h"
> >
> > @@ -42,6 +49,9 @@ enum {
> > #define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
> > #define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
> >
> > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n) (0x0070 + (n) * 8)
> > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n) (0x0074 + (n) * 8)
> > +
> > #define TEGRA_VI_VI_INPUT_CONTROL 0x0088
> > #define VI_INPUT_FIELD_DETECT BIT(27)
> > #define VI_INPUT_BT656 BIT(25)
> > @@ -87,6 +97,8 @@ enum {
> > #define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
> > #define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > #define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > #define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> >
> > #define TEGRA_VI_VIP_H_ACTIVE 0x00a4
> > @@ -151,8 +163,106 @@ enum {
> > #define TEGRA_VI_VI_RAISE 0x01ac
> > #define VI_VI_RAISE_ON_EDGE BIT(0)
> >
> > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n) (0x01d8 + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n) (0x01dc + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n) (0x01e8 + (n) * 8)
> > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n) (0x01ec + (n) * 8)
> > +
> > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0000
> > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0008
> > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n) (0x0010 + (n) * 0x2c)
> > +#define CSI_SKIP_PACKET_THRESHOLD(n) (((n) & 0xff) << 16)
> > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n) (0x0018 + (n) * 0x2c)
> > +#define CSI_PP_PAD_FRAME_PAD0S (0 << 28)
> > +#define CSI_PP_PAD_FRAME_PAD1S (1 << 28)
> > +#define CSI_PP_PAD_FRAME_NOPAD (2 << 28)
> > +#define CSI_PP_HEADER_EC_ENABLE BIT(27)
> > +#define CSI_PP_PAD_SHORT_LINE_PAD0S (0 << 24)
> > +#define CSI_PP_PAD_SHORT_LINE_PAD1S (1 << 24)
> > +#define CSI_PP_PAD_SHORT_LINE_NOPAD (2 << 24)
> > +#define CSI_PP_EMBEDDED_DATA_EMBEDDED BIT(20)
> > +#define CSI_PP_OUTPUT_FORMAT_ARBITRARY (0 << 16)
> > +#define CSI_PP_OUTPUT_FORMAT_PIXEL (1 << 16)
> > +#define CSI_PP_OUTPUT_FORMAT_PIXEL_REP (2 << 16)
> > +#define CSI_PP_OUTPUT_FORMAT_STORE (3 << 16)
> > +#define CSI_PP_VIRTUAL_CHANNEL_ID(n) (((n) - 1) << 14)
> > +#define CSI_PP_DATA_TYPE(n) ((n) << 8)
> > +#define CSI_PP_CRC_CHECK_ENABLE BIT(7)
> > +#define CSI_PP_WORD_COUNT_HEADER BIT(6)
> > +#define CSI_PP_DATA_IDENTIFIER_ENABLE BIT(5)
> > +#define CSI_PP_PACKET_HEADER_SENT BIT(4)
> > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n) (0x001c + (n) * 0x2c)
> > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n) (0x0020 + (n) * 0x2c)
> > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n) (0x0024 + (n) * 0x2c)
> > +#define CSI_PP_FRAME_MIN_GAP(n) (((n) & 0xffff) << 16)
> > +#define CSI_PP_LINE_MIN_GAP(n) (((n) & 0xffff))
> > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n) (0x0028 + (n) * 0x2c)
> > +#define CSI_PP_START_MARKER_FRAME_MAX(n) (((n) & 0xf) << 12)
> > +#define CSI_PP_START_MARKER_FRAME_MIN(n) (((n) & 0xf) << 8)
> > +#define CSI_PP_VSYNC_START_MARKER BIT(4)
> > +#define CSI_PP_SINGLE_SHOT BIT(2)
> > +#define CSI_PP_NOP 0
> > +#define CSI_PP_ENABLE 1
> > +#define CSI_PP_DISABLE 2
> > +#define CSI_PP_RST 3
> > +#define TEGRA_CSI_PHY_CIL_COMMAND 0x0068
> > +#define CSI_A_PHY_CIL_NOP 0x0
> > +#define CSI_A_PHY_CIL_ENABLE 0x1
> > +#define CSI_A_PHY_CIL_DISABLE 0x2
> > +#define CSI_A_PHY_CIL_ENABLE_MASK 0x3
> > +#define CSI_B_PHY_CIL_NOP (0x0 << 16)
> > +#define CSI_B_PHY_CIL_ENABLE (0x1 << 16)
> > +#define CSI_B_PHY_CIL_DISABLE (0x2 << 16)
> > +#define CSI_B_PHY_CIL_ENABLE_MASK (0x3 << 16)
> > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n) (0x006c + (n) * 4)
> > +#define CSI_CONTINUOUS_CLOCK_MODE_ENABLE BIT(5)
> > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0078
> > +#define TEGRA_CSI_CSI_CIL_STATUS 0x007c
> > +#define CSI_MIPI_AUTO_CAL_DONE BIT(15)
> > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0080
> > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0084
> > +#define TEGRA_CSI_CSI_READONLY_STATUS 0x0088
> > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x008c
> > +#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0090
> > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n) (0x0094 + (n) * 8)
> > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n) (0x0098 + (n) * 8)
> > +#define TEGRA_CSI_CIL_PAD_CONFIG 0x00a4
> > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x00a8
> > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x00ac
> > +#define CSI_CIL_MIPI_CAL_STARTCAL BIT(31)
> > +#define CSI_CIL_MIPI_CAL_OVERIDE_A BIT(30)
> > +#define CSI_CIL_MIPI_CAL_OVERIDE_B BIT(30)
> > +#define CSI_CIL_MIPI_CAL_NOISE_FLT(n) (((n) & 0xf) << 26)
> > +#define CSI_CIL_MIPI_CAL_PRESCALE(n) (((n) & 0x3) << 24)
> > +#define CSI_CIL_MIPI_CAL_SEL_A BIT(21)
> > +#define CSI_CIL_MIPI_CAL_SEL_B BIT(21)
> > +#define CSI_CIL_MIPI_CAL_HSPDOS(n) (((n) & 0x1f) << 16)
> > +#define CSI_CIL_MIPI_CAL_HSPUOS(n) (((n) & 0x1f) << 8)
> > +#define CSI_CIL_MIPI_CAL_TERMOS(n) (((n) & 0x1f))
> > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x00b0
> > +#define TEGRA_CSI_CLKEN_OVERRIDE 0x00b4
> > +#define TEGRA_CSI_DEBUG_CONTROL 0x00b8
> > +#define CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED BIT(0)
> > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 BIT(4)
> > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 BIT(5)
> > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_2 BIT(6)
> > +#define CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v) ((v) << (8 + 8 * (n)))
> > +#define TEGRA_CSI_DEBUG_COUNTER(n) (0x00bc + (n) * 4)
> > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n) (0x00c8 + (n) * 4)
> > +#define CSI_PP_EXP_FRAME_HEIGHT(n) (((n) & 0x1fff) << 16)
> > +#define CSI_PP_MAX_CLOCKS(n) (((n) & 0xfff) << 4)
> > +#define CSI_PP_LINE_TIMEOUT_ENABLE BIT(0)
> > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x00d0
> > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x00d4
> > +#define CSI_PAD_DRIV_DN_REF(n) (((n) & 0x7) << 16)
> > +#define CSI_PAD_DRIV_UP_REF(n) (((n) & 0x7) << 8)
> > +#define CSI_PAD_TERM_REF(n) (((n) & 0x7) << 0)
> > +#define TEGRA_CSI_CSI_CILA_STATUS 0x00d8
> > +#define TEGRA_CSI_CSI_CILB_STATUS 0x00dc
> > +
> > /* --------------------------------------------------------------------------
> > - * VI
> > + * Read and Write helpers
> > */
> >
> > static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> > writel(val, chan->vi->iomem + addr);
> > }
> >
> > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > +{
> > + return readl(chan->vi->iomem + addr);
> > +}
> > +
> > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > +{
> > + writel(val, csi_chan->csi->iomem + addr);
> > +}
> > +
> > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > +{
> > + return readl(csi_chan->csi->iomem + addr);
> > +}
> > +
> > +/* --------------------------------------------------------------------------
> > + * VI
> > + */
> > +
> > /*
> > * Get the main input format (YUV/RGB...) and the YUV variant as values to
> > * be written into registers for the current VI input mbus code.
> > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > {
> > struct tegra_vi *vi = chan->vi;
> > - struct host1x_syncpt *out_sp;
> > + struct host1x_syncpt *out_sp, *fs_sp;
> >
> > out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > if (!out_sp)
> > - return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
>
> Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
>
That is interesting. I am fine to switching to any error code as long
as it fits here, EBUSY fits fine.
> >
> > chan->mw_ack_sp[0] = out_sp;
> >
> > + fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > + if (!fs_sp)
> > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > +
> > + chan->frame_start_sp[0] = fs_sp;
> > +
> > return 0;
> > }
> >
> > static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> > {
> > host1x_syncpt_put(chan->mw_ack_sp[0]);
> > + host1x_syncpt_put(chan->frame_start_sp[0]);
> > }
> >
> > static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> > static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> > struct tegra_channel_buffer *buf)
> > {
> > + struct v4l2_subdev *csi_subdev = NULL;
> > + struct tegra_csi_channel *csi_chan = NULL;
> > + u32 port;
> > int err;
> >
> > - chan->next_out_sp_idx++;
> > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > + if (csi_subdev) {
> > + /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > + if (!strncmp(csi_subdev->name, "channel", 7)) {
> > + csi_chan = to_csi_chan(csi_subdev);
> > + port = csi_chan->csi_port_nums[0] & 1;
> > + }
> > + }
>
> tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
>
That is possible.
> Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
>
I may try that. My main concern was VIP. Unlike Tegra210,
Tegra20/Tegra30 have VIP which can cause issues if no additional
checks are done.
> Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
>
Yes, I hope so. We did not implement this logic, it existed before, we
just expanded it to support CSI.
> >
> > tegra20_channel_vi_buffer_setup(chan, buf);
> >
> > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > + if (csi_chan) {
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > + CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > +
> > + chan->next_fs_sp_idx++;
> > + err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > + TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > + if (err) {
> > + host1x_syncpt_incr(chan->frame_start_sp[0]);
>
> This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
>
The race condition should be avoidable by resetting pixel parser and
checking syncpt value again.
Incrementing the software reference counter only if hardware completed
successfully sounds like a good idea.
> Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
>
> (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
>
> > + if (err != -ERESTARTSYS)
> > + dev_err_ratelimited(&chan->video.dev,
> > + "frame start syncpt timeout: %d\n", err);
> > + }
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > + CSI_PP_DISABLE);
> > + } else {
> > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > + }
> >
> > - /* Wait for syncpt counter to reach frame start event threshold */
> > + chan->next_out_sp_idx++;
> > err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> > TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > if (err) {
> > host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > - dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > - release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > - return err;
> > + if (err != -ERESTARTSYS)
> > + dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> > }
> >
> > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > - VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > + if (!csi_chan)
> > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > + VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> >
> > release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> >
> > - return 0;
> > + return err;
> > }
> >
> > static int tegra20_chan_capture_kthread_start(void *data)
> > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > OUT_2 : OUT_1;
> > - int main_output_format;
> > - int yuv_output_format;
> > -
> > - tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > -
> > - /*
> > - * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > - * for luminance, which is the default and means not to touch
> > - * anything.
> > - */
> > - tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > - 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > - 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > -
> > - /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > - tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > -
> > - tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > - (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > - (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > - yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > - main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> >
> > /* Set up frame size */
> > tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> > }
> >
> > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > +{
> > + struct tegra_csi *csi = csi_chan->csi;
> > + void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > + unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > + u32 value, pp, cil;
> > + int ret;
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > + CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > + CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > + CSI_CIL_MIPI_CAL_TERMOS(0));
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > + CSI_PAD_DRIV_DN_REF(5) |
> > + CSI_PAD_DRIV_UP_REF(7) |
> > + CSI_PAD_TERM_REF(0));
> > +
> > + /* CSI B */
> > + value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > +
> > + if (port == PORT_B || csi_chan->numlanes == 4)
> > + value |= CSI_CIL_MIPI_CAL_SEL_B;
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > +
> > + /* CSI A */
> > + value = CSI_CIL_MIPI_CAL_STARTCAL |
> > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > +
> > + if (port == PORT_A)
> > + value |= CSI_CIL_MIPI_CAL_SEL_A;
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > +
> > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > + value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > + if (ret < 0) {
> > + dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > + goto exit;
> > + }
> > +
> > + /* clear status */
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > + !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > + if (ret < 0) {
> > + dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > + goto exit;
> > + }
> > +
> > + pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > + cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > + if (pp | cil) {
> > + dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > + ret = -EINVAL;
> > + goto exit;
> > + }
> > +
> > +exit:
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > +
> > + /* un-select to avoid interference with DSI */
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > +
> > + return ret;
> > +}
> > +
> > static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > {
> > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > struct media_pipeline *pipe = &chan->video.pipe;
> > + struct v4l2_subdev *csi_subdev, *src_subdev;
> > + struct tegra_csi_channel *csi_chan = NULL;
> > int err;
> >
> > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > + if (csi_subdev) {
> > + if (!strncmp(csi_subdev->name, "channel", 7))
> > + csi_chan = to_csi_chan(csi_subdev);
> > + }
> > +
> > + chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> > chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> >
> > err = video_device_pipeline_start(&chan->video, pipe);
> > if (err)
> > goto error_pipeline_start;
> >
> > - tegra20_camera_capture_setup(chan);
> > + /*
> > + * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > + * for luminance, which is the default and means not to touch
> > + * anything.
> > + */
> > + tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > + 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > + 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > +
> > + /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > + tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> >
> > err = tegra_channel_set_stream(chan, true);
> > if (err)
> > goto error_set_stream;
> >
> > + tegra20_camera_capture_setup(chan);
> > +
> > + if (csi_chan) {
> > + /*
> > + * TRM has incorrectly documented to wait for done status from
> > + * calibration logic after CSI interface power on.
> > + * As per the design, calibration results are latched and applied
> > + * to the pads only when the link is in LP11 state which will happen
> > + * during the sensor stream-on.
> > + * CSI subdev stream-on triggers start of MIPI pads calibration.
> > + * Wait for calibration to finish here after sensor subdev stream-on.
> > + */
> > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > + if (!src_subdev->s_stream_enabled) {
> > + err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > + if (err < 0 && err != -ENOIOCTLCMD)
> > + goto error_set_stream;
> > + }
> > +
> > + tegra20_csi_pad_calibration(csi_chan);
> > + }
> > +
> > chan->sequence = 0;
> >
> > chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> > {
> > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > + struct v4l2_subdev *src_subdev;
> >
> > if (chan->kthread_start_capture) {
> > kthread_stop(chan->kthread_start_capture);
> > chan->kthread_start_capture = NULL;
> > }
> >
> > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > + if (src_subdev->s_stream_enabled)
> > + v4l2_subdev_call(src_subdev, video, s_stream, false);
> > +
> > tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> > tegra_channel_set_stream(chan, false);
> > video_device_pipeline_stop(&chan->video);
> > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > .default_video_format = &tegra20_video_formats[0],
> > .ops = &tegra20_vi_ops,
> > .hw_revision = 1,
> > - .vi_max_channels = 1, /* parallel input (VIP) */
> > + .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> > .vi_max_clk_hz = 450000000,
> > .has_h_v_flip = true,
> > };
> >
> > +/* --------------------------------------------------------------------------
> > + * CSI
> > + */
> > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > +{
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > +}
> > +
> > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > + u8 portno)
> > +{
> > + struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > + int width = vi_chan->format.width;
> > + int height = vi_chan->format.height;
> > + u32 data_type = vi_chan->fmtinfo->img_dt;
> > + u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > + int output_channel = OUT_1;
> > +
> > + unsigned int main_output_format, yuv_output_format;
> > + unsigned int port = portno & 1;
> > + u32 value;
> > +
> > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > +
> > + switch (data_type) {
> > + case TEGRA_IMAGE_DT_RAW8:
> > + case TEGRA_IMAGE_DT_RAW10:
> > + output_channel = OUT_2;
> > + if (port == PORT_A)
> > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > + else
> > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > + break;
> > + }
> > +
> > + tegra20_csi_capture_clean(csi_chan);
> > +
> > + /* CSI port cleanup */
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > + tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > + CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > + CSI_PP_EXP_FRAME_HEIGHT(height) |
> > + CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > + CSI_PP_LINE_TIMEOUT_ENABLE);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > + CSI_PP_OUTPUT_FORMAT_PIXEL |
> > + CSI_PP_DATA_TYPE(data_type) |
> > + CSI_PP_CRC_CHECK_ENABLE |
> > + CSI_PP_WORD_COUNT_HEADER |
> > + CSI_PP_DATA_IDENTIFIER_ENABLE |
> > + CSI_PP_PACKET_HEADER_SENT |
> > + port);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > + CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > + (csi_chan->numlanes - 1));
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > + CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > + 0x5); /* Clock settle time */
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > + host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > + host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > +
> > + value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > + CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > + CSI_PP_DISABLE);
> > +
> > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > + yuv_output_format | main_output_format);
> > +
> > + return 0;
> > +};
> > +
> > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > +{
> > + struct tegra_csi *csi = csi_chan->csi;
> > + unsigned int port = portno & 1;
> > + u32 value;
> > +
> > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > +
> > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > +
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > + CSI_PP_DISABLE);
> > +
> > + if (csi_chan->numlanes == 4) {
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > + CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > + } else {
> > + value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > + CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > + }
> > +}
> > +
> > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > +{
> > + u8 *portnos = csi_chan->csi_port_nums;
> > + int ret, i;
> > +
> > + for (i = 0; i < csi_chan->numgangports; i++) {
> > + ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > + if (ret)
> > + goto stream_start_fail;
> > + }
> > +
> > + return 0;
> > +
> > +stream_start_fail:
> > + for (i = i - 1; i >= 0; i--)
> > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > +
> > + return ret;
> > +}
> > +
> > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > +{
> > + u8 *portnos = csi_chan->csi_port_nums;
> > + int i;
> > +
> > + for (i = 0; i < csi_chan->numgangports; i++)
> > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > +}
> > +
> > +/* Tegra20 CSI operations */
> > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > + .csi_start_streaming = tegra20_csi_start_streaming,
> > + .csi_stop_streaming = tegra20_csi_stop_streaming,
> > +};
> > +
> > +static const char * const tegra20_csi_clks[] = {
> > + "csi",
> > +};
> > +
> > +/* Tegra20 CSI SoC data */
> > +const struct tegra_csi_soc tegra20_csi_soc = {
> > + .ops = &tegra20_csi_ops,
> > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > + .clk_names = tegra20_csi_clks,
> > + .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > + .has_mipi_calibration = false,
> > +};
> > +
> > +static const char * const tegra30_csi_clks[] = {
> > + "csi",
> > + "csia_pad",
> > + "csib_pad",
> > +};
> > +
> > +/* Tegra30 CSI SoC data */
> > +const struct tegra_csi_soc tegra30_csi_soc = {
> > + .ops = &tegra20_csi_ops,
> > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > + .clk_names = tegra30_csi_clks,
> > + .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > + .has_mipi_calibration = false,
> > +};
> > +
> > /* --------------------------------------------------------------------------
> > * VIP
> > */
> > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > OUT_2 : OUT_1;
> >
> > - unsigned int main_input_format;
> > - unsigned int yuv_input_format;
> > + unsigned int main_input_format, yuv_input_format;
> > + unsigned int main_output_format, yuv_output_format;
> >
> > tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> >
> > tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> >
> > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> >
> > tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> >
> > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > + yuv_output_format | main_output_format);
> > +
> > return 0;
> > }
> >
> > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > index cac0c0d0e225..c02517c9e09b 100644
> > --- a/drivers/staging/media/tegra-video/vi.h
> > +++ b/drivers/staging/media/tegra-video/vi.h
> > @@ -127,6 +127,7 @@ struct tegra_vi {
> > * frame through host1x syncpoint counters (On Tegra20 used for the
> > * OUT_1 syncpt)
> > * @sp_incr_lock: protects cpu syncpoint increment.
> > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> > * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> > *
> > * @kthread_start_capture: kthread to start capture of single frame when
> > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> > /* protects the cpu syncpoint increment */
> > spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> > u32 next_out_sp_idx;
> > + u32 next_fs_sp_idx;
> >
> > struct task_struct *kthread_start_capture;
> > wait_queue_head_t start_wait;
> > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > index a25885f93cd7..8fa660431eb0 100644
> > --- a/drivers/staging/media/tegra-video/video.c
> > +++ b/drivers/staging/media/tegra-video/video.c
> > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> >
> > static const struct of_device_id host1x_video_subdevs[] = {
> > #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > + { .compatible = "nvidia,tegra20-csi", },
> > { .compatible = "nvidia,tegra20-vip", },
> > { .compatible = "nvidia,tegra20-vi", },
> > #endif
> > #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > + { .compatible = "nvidia,tegra30-csi", },
> > { .compatible = "nvidia,tegra30-vip", },
> > { .compatible = "nvidia,tegra30-vi", },
> > #endif
> >
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-09-02 5:51 ` Svyatoslav Ryhel
@ 2025-09-02 6:17 ` Mikko Perttunen
2025-09-02 6:21 ` Svyatoslav Ryhel
0 siblings, 1 reply; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 6:17 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Tuesday, September 2, 2025 2:51 PM Svyatoslav Ryhel wrote:
> вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> > >
> > > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > > drivers/staging/media/tegra-video/csi.c | 12 +
> > > drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> > > drivers/staging/media/tegra-video/vi.h | 2 +
> > > drivers/staging/media/tegra-video/video.c | 2 +
> > > 4 files changed, 553 insertions(+), 38 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > index 2f9907a20db1..714ce52a793c 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> > > pm_runtime_disable(&pdev->dev);
> > > }
> > >
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > > +#endif
> > > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > extern const struct tegra_csi_soc tegra210_csi_soc;
> > > #endif
> > >
> > > static const struct of_device_id tegra_csi_of_id_table[] = {
> > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > + { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > > +#endif
> > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > + { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > > +#endif
> > > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> > > #endif
> > > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > > index a06afe91d2de..e528ba280ae4 100644
> > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > @@ -4,6 +4,9 @@
> > > *
> > > * Copyright (C) 2023 SKIDATA GmbH
> > > * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > > + *
> > > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > */
> > >
> > > /*
> > > @@ -12,12 +15,16 @@
> > > */
> > >
> > > #include <linux/bitfield.h>
> > > +#include <linux/clk.h>
> > > +#include <linux/clk/tegra.h>
> > > #include <linux/delay.h>
> > > #include <linux/host1x.h>
> > > +#include <linux/iopoll.h>
> > > #include <linux/kernel.h>
> > > #include <linux/kthread.h>
> > > #include <linux/v4l2-mediabus.h>
> > >
> > > +#include "csi.h"
> > > #include "vip.h"
> > > #include "vi.h"
> > >
> > > @@ -42,6 +49,9 @@ enum {
> > > #define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
> > > #define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
> > >
> > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n) (0x0070 + (n) * 8)
> > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n) (0x0074 + (n) * 8)
> > > +
> > > #define TEGRA_VI_VI_INPUT_CONTROL 0x0088
> > > #define VI_INPUT_FIELD_DETECT BIT(27)
> > > #define VI_INPUT_BT656 BIT(25)
> > > @@ -87,6 +97,8 @@ enum {
> > > #define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
> > > #define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > #define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > #define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > >
> > > #define TEGRA_VI_VIP_H_ACTIVE 0x00a4
> > > @@ -151,8 +163,106 @@ enum {
> > > #define TEGRA_VI_VI_RAISE 0x01ac
> > > #define VI_VI_RAISE_ON_EDGE BIT(0)
> > >
> > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n) (0x01d8 + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n) (0x01dc + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n) (0x01e8 + (n) * 8)
> > > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n) (0x01ec + (n) * 8)
> > > +
> > > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0000
> > > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0008
> > > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n) (0x0010 + (n) * 0x2c)
> > > +#define CSI_SKIP_PACKET_THRESHOLD(n) (((n) & 0xff) << 16)
> > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n) (0x0018 + (n) * 0x2c)
> > > +#define CSI_PP_PAD_FRAME_PAD0S (0 << 28)
> > > +#define CSI_PP_PAD_FRAME_PAD1S (1 << 28)
> > > +#define CSI_PP_PAD_FRAME_NOPAD (2 << 28)
> > > +#define CSI_PP_HEADER_EC_ENABLE BIT(27)
> > > +#define CSI_PP_PAD_SHORT_LINE_PAD0S (0 << 24)
> > > +#define CSI_PP_PAD_SHORT_LINE_PAD1S (1 << 24)
> > > +#define CSI_PP_PAD_SHORT_LINE_NOPAD (2 << 24)
> > > +#define CSI_PP_EMBEDDED_DATA_EMBEDDED BIT(20)
> > > +#define CSI_PP_OUTPUT_FORMAT_ARBITRARY (0 << 16)
> > > +#define CSI_PP_OUTPUT_FORMAT_PIXEL (1 << 16)
> > > +#define CSI_PP_OUTPUT_FORMAT_PIXEL_REP (2 << 16)
> > > +#define CSI_PP_OUTPUT_FORMAT_STORE (3 << 16)
> > > +#define CSI_PP_VIRTUAL_CHANNEL_ID(n) (((n) - 1) << 14)
> > > +#define CSI_PP_DATA_TYPE(n) ((n) << 8)
> > > +#define CSI_PP_CRC_CHECK_ENABLE BIT(7)
> > > +#define CSI_PP_WORD_COUNT_HEADER BIT(6)
> > > +#define CSI_PP_DATA_IDENTIFIER_ENABLE BIT(5)
> > > +#define CSI_PP_PACKET_HEADER_SENT BIT(4)
> > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n) (0x001c + (n) * 0x2c)
> > > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n) (0x0020 + (n) * 0x2c)
> > > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n) (0x0024 + (n) * 0x2c)
> > > +#define CSI_PP_FRAME_MIN_GAP(n) (((n) & 0xffff) << 16)
> > > +#define CSI_PP_LINE_MIN_GAP(n) (((n) & 0xffff))
> > > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n) (0x0028 + (n) * 0x2c)
> > > +#define CSI_PP_START_MARKER_FRAME_MAX(n) (((n) & 0xf) << 12)
> > > +#define CSI_PP_START_MARKER_FRAME_MIN(n) (((n) & 0xf) << 8)
> > > +#define CSI_PP_VSYNC_START_MARKER BIT(4)
> > > +#define CSI_PP_SINGLE_SHOT BIT(2)
> > > +#define CSI_PP_NOP 0
> > > +#define CSI_PP_ENABLE 1
> > > +#define CSI_PP_DISABLE 2
> > > +#define CSI_PP_RST 3
> > > +#define TEGRA_CSI_PHY_CIL_COMMAND 0x0068
> > > +#define CSI_A_PHY_CIL_NOP 0x0
> > > +#define CSI_A_PHY_CIL_ENABLE 0x1
> > > +#define CSI_A_PHY_CIL_DISABLE 0x2
> > > +#define CSI_A_PHY_CIL_ENABLE_MASK 0x3
> > > +#define CSI_B_PHY_CIL_NOP (0x0 << 16)
> > > +#define CSI_B_PHY_CIL_ENABLE (0x1 << 16)
> > > +#define CSI_B_PHY_CIL_DISABLE (0x2 << 16)
> > > +#define CSI_B_PHY_CIL_ENABLE_MASK (0x3 << 16)
> > > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n) (0x006c + (n) * 4)
> > > +#define CSI_CONTINUOUS_CLOCK_MODE_ENABLE BIT(5)
> > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0078
> > > +#define TEGRA_CSI_CSI_CIL_STATUS 0x007c
> > > +#define CSI_MIPI_AUTO_CAL_DONE BIT(15)
> > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0080
> > > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0084
> > > +#define TEGRA_CSI_CSI_READONLY_STATUS 0x0088
> > > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x008c
> > > +#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0090
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n) (0x0094 + (n) * 8)
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n) (0x0098 + (n) * 8)
> > > +#define TEGRA_CSI_CIL_PAD_CONFIG 0x00a4
> > > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x00a8
> > > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x00ac
> > > +#define CSI_CIL_MIPI_CAL_STARTCAL BIT(31)
> > > +#define CSI_CIL_MIPI_CAL_OVERIDE_A BIT(30)
> > > +#define CSI_CIL_MIPI_CAL_OVERIDE_B BIT(30)
> > > +#define CSI_CIL_MIPI_CAL_NOISE_FLT(n) (((n) & 0xf) << 26)
> > > +#define CSI_CIL_MIPI_CAL_PRESCALE(n) (((n) & 0x3) << 24)
> > > +#define CSI_CIL_MIPI_CAL_SEL_A BIT(21)
> > > +#define CSI_CIL_MIPI_CAL_SEL_B BIT(21)
> > > +#define CSI_CIL_MIPI_CAL_HSPDOS(n) (((n) & 0x1f) << 16)
> > > +#define CSI_CIL_MIPI_CAL_HSPUOS(n) (((n) & 0x1f) << 8)
> > > +#define CSI_CIL_MIPI_CAL_TERMOS(n) (((n) & 0x1f))
> > > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x00b0
> > > +#define TEGRA_CSI_CLKEN_OVERRIDE 0x00b4
> > > +#define TEGRA_CSI_DEBUG_CONTROL 0x00b8
> > > +#define CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED BIT(0)
> > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 BIT(4)
> > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 BIT(5)
> > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_2 BIT(6)
> > > +#define CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v) ((v) << (8 + 8 * (n)))
> > > +#define TEGRA_CSI_DEBUG_COUNTER(n) (0x00bc + (n) * 4)
> > > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n) (0x00c8 + (n) * 4)
> > > +#define CSI_PP_EXP_FRAME_HEIGHT(n) (((n) & 0x1fff) << 16)
> > > +#define CSI_PP_MAX_CLOCKS(n) (((n) & 0xfff) << 4)
> > > +#define CSI_PP_LINE_TIMEOUT_ENABLE BIT(0)
> > > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x00d0
> > > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x00d4
> > > +#define CSI_PAD_DRIV_DN_REF(n) (((n) & 0x7) << 16)
> > > +#define CSI_PAD_DRIV_UP_REF(n) (((n) & 0x7) << 8)
> > > +#define CSI_PAD_TERM_REF(n) (((n) & 0x7) << 0)
> > > +#define TEGRA_CSI_CSI_CILA_STATUS 0x00d8
> > > +#define TEGRA_CSI_CSI_CILB_STATUS 0x00dc
> > > +
> > > /* --------------------------------------------------------------------------
> > > - * VI
> > > + * Read and Write helpers
> > > */
> > >
> > > static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> > > writel(val, chan->vi->iomem + addr);
> > > }
> > >
> > > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > > +{
> > > + return readl(chan->vi->iomem + addr);
> > > +}
> > > +
> > > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > > +{
> > > + writel(val, csi_chan->csi->iomem + addr);
> > > +}
> > > +
> > > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > > +{
> > > + return readl(csi_chan->csi->iomem + addr);
> > > +}
> > > +
> > > +/* --------------------------------------------------------------------------
> > > + * VI
> > > + */
> > > +
> > > /*
> > > * Get the main input format (YUV/RGB...) and the YUV variant as values to
> > > * be written into registers for the current VI input mbus code.
> > > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > > static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > > {
> > > struct tegra_vi *vi = chan->vi;
> > > - struct host1x_syncpt *out_sp;
> > > + struct host1x_syncpt *out_sp, *fs_sp;
> > >
> > > out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > if (!out_sp)
> > > - return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
> >
> > Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
> >
>
> That is interesting. I am fine to switching to any error code as long
> as it fits here, EBUSY fits fine.
>
> > >
> > > chan->mw_ack_sp[0] = out_sp;
> > >
> > > + fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > + if (!fs_sp)
> > > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > > +
> > > + chan->frame_start_sp[0] = fs_sp;
> > > +
> > > return 0;
> > > }
> > >
> > > static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> > > {
> > > host1x_syncpt_put(chan->mw_ack_sp[0]);
> > > + host1x_syncpt_put(chan->frame_start_sp[0]);
> > > }
> > >
> > > static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> > > static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> > > struct tegra_channel_buffer *buf)
> > > {
> > > + struct v4l2_subdev *csi_subdev = NULL;
> > > + struct tegra_csi_channel *csi_chan = NULL;
> > > + u32 port;
> > > int err;
> > >
> > > - chan->next_out_sp_idx++;
> > > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > + if (csi_subdev) {
> > > + /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > > + if (!strncmp(csi_subdev->name, "channel", 7)) {
> > > + csi_chan = to_csi_chan(csi_subdev);
> > > + port = csi_chan->csi_port_nums[0] & 1;
> > > + }
> > > + }
> >
> > tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
> >
>
> That is possible.
>
> > Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
> >
>
> I may try that. My main concern was VIP. Unlike Tegra210,
> Tegra20/Tegra30 have VIP which can cause issues if no additional
> checks are done.
>
> > Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
> >
>
> Yes, I hope so. We did not implement this logic, it existed before, we
> just expanded it to support CSI.
If it's non-trivial it can be left for later.
>
> > >
> > > tegra20_channel_vi_buffer_setup(chan, buf);
> > >
> > > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > + if (csi_chan) {
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > + CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > > +
> > > + chan->next_fs_sp_idx++;
> > > + err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > > + TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > + if (err) {
> > > + host1x_syncpt_incr(chan->frame_start_sp[0]);
> >
> > This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
> >
>
> The race condition should be avoidable by resetting pixel parser and
> checking syncpt value again.
> Incrementing the software reference counter only if hardware completed
> successfully sounds like a good idea.
>
> > Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
> >
> > (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
> >
> > > + if (err != -ERESTARTSYS)
> > > + dev_err_ratelimited(&chan->video.dev,
> > > + "frame start syncpt timeout: %d\n", err);
> > > + }
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > + CSI_PP_DISABLE);
> > > + } else {
> > > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > + }
> > >
> > > - /* Wait for syncpt counter to reach frame start event threshold */
> > > + chan->next_out_sp_idx++;
> > > err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> > > TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > if (err) {
> > > host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > > - dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > > - release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > > - return err;
> > > + if (err != -ERESTARTSYS)
> > > + dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> > > }
> > >
> > > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > - VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > + if (!csi_chan)
> > > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > + VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > >
> > > release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> > >
> > > - return 0;
> > > + return err;
> > > }
> > >
> > > static int tegra20_chan_capture_kthread_start(void *data)
> > > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > OUT_2 : OUT_1;
> > > - int main_output_format;
> > > - int yuv_output_format;
> > > -
> > > - tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > > -
> > > - /*
> > > - * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > > - * for luminance, which is the default and means not to touch
> > > - * anything.
> > > - */
> > > - tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > - 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > - 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > -
> > > - /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > - tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > -
> > > - tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > - (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > - (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > - yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > > - main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> > >
> > > /* Set up frame size */
> > > tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> > > }
> > >
> > > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > > +{
> > > + struct tegra_csi *csi = csi_chan->csi;
> > > + void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > + unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > > + u32 value, pp, cil;
> > > + int ret;
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > > + CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > > + CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > > + CSI_CIL_MIPI_CAL_TERMOS(0));
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > > + CSI_PAD_DRIV_DN_REF(5) |
> > > + CSI_PAD_DRIV_UP_REF(7) |
> > > + CSI_PAD_TERM_REF(0));
> > > +
> > > + /* CSI B */
> > > + value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > > +
> > > + if (port == PORT_B || csi_chan->numlanes == 4)
> > > + value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > > +
> > > + /* CSI A */
> > > + value = CSI_CIL_MIPI_CAL_STARTCAL |
> > > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > > +
> > > + if (port == PORT_A)
> > > + value |= CSI_CIL_MIPI_CAL_SEL_A;
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > +
> > > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > + value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > > + if (ret < 0) {
> > > + dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > > + goto exit;
> > > + }
> > > +
> > > + /* clear status */
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > + !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > > + if (ret < 0) {
> > > + dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > > + goto exit;
> > > + }
> > > +
> > > + pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > + cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > + if (pp | cil) {
> > > + dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > + ret = -EINVAL;
> > > + goto exit;
> > > + }
> > > +
> > > +exit:
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > +
> > > + /* un-select to avoid interference with DSI */
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > > +
> > > + return ret;
> > > +}
> > > +
> > > static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > {
> > > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > struct media_pipeline *pipe = &chan->video.pipe;
> > > + struct v4l2_subdev *csi_subdev, *src_subdev;
> > > + struct tegra_csi_channel *csi_chan = NULL;
> > > int err;
> > >
> > > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > + if (csi_subdev) {
> > > + if (!strncmp(csi_subdev->name, "channel", 7))
> > > + csi_chan = to_csi_chan(csi_subdev);
> > > + }
> > > +
> > > + chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> > > chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> > >
> > > err = video_device_pipeline_start(&chan->video, pipe);
> > > if (err)
> > > goto error_pipeline_start;
> > >
> > > - tegra20_camera_capture_setup(chan);
> > > + /*
> > > + * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > > + * for luminance, which is the default and means not to touch
> > > + * anything.
> > > + */
> > > + tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > + 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > + 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > +
> > > + /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > + tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > >
> > > err = tegra_channel_set_stream(chan, true);
> > > if (err)
> > > goto error_set_stream;
> > >
> > > + tegra20_camera_capture_setup(chan);
> > > +
> > > + if (csi_chan) {
> > > + /*
> > > + * TRM has incorrectly documented to wait for done status from
> > > + * calibration logic after CSI interface power on.
> > > + * As per the design, calibration results are latched and applied
> > > + * to the pads only when the link is in LP11 state which will happen
> > > + * during the sensor stream-on.
> > > + * CSI subdev stream-on triggers start of MIPI pads calibration.
> > > + * Wait for calibration to finish here after sensor subdev stream-on.
> > > + */
> > > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > + if (!src_subdev->s_stream_enabled) {
> > > + err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > > + if (err < 0 && err != -ENOIOCTLCMD)
> > > + goto error_set_stream;
> > > + }
> > > +
> > > + tegra20_csi_pad_calibration(csi_chan);
> > > + }
> > > +
> > > chan->sequence = 0;
> > >
> > > chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> > > {
> > > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > + struct v4l2_subdev *src_subdev;
> > >
> > > if (chan->kthread_start_capture) {
> > > kthread_stop(chan->kthread_start_capture);
> > > chan->kthread_start_capture = NULL;
> > > }
> > >
> > > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > + if (src_subdev->s_stream_enabled)
> > > + v4l2_subdev_call(src_subdev, video, s_stream, false);
> > > +
> > > tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> > > tegra_channel_set_stream(chan, false);
> > > video_device_pipeline_stop(&chan->video);
> > > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > > .default_video_format = &tegra20_video_formats[0],
> > > .ops = &tegra20_vi_ops,
> > > .hw_revision = 1,
> > > - .vi_max_channels = 1, /* parallel input (VIP) */
> > > + .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> > > .vi_max_clk_hz = 450000000,
> > > .has_h_v_flip = true,
> > > };
> > >
> > > +/* --------------------------------------------------------------------------
> > > + * CSI
> > > + */
> > > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > > +{
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > > +}
> > > +
> > > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > > + u8 portno)
> > > +{
> > > + struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > > + int width = vi_chan->format.width;
> > > + int height = vi_chan->format.height;
> > > + u32 data_type = vi_chan->fmtinfo->img_dt;
> > > + u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > > + int output_channel = OUT_1;
> > > +
> > > + unsigned int main_output_format, yuv_output_format;
> > > + unsigned int port = portno & 1;
> > > + u32 value;
> > > +
> > > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > +
> > > + switch (data_type) {
> > > + case TEGRA_IMAGE_DT_RAW8:
> > > + case TEGRA_IMAGE_DT_RAW10:
> > > + output_channel = OUT_2;
> > > + if (port == PORT_A)
> > > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > > + else
> > > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > > + break;
> > > + }
> > > +
> > > + tegra20_csi_capture_clean(csi_chan);
> > > +
> > > + /* CSI port cleanup */
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > > + CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > > + CSI_PP_EXP_FRAME_HEIGHT(height) |
> > > + CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > > + CSI_PP_LINE_TIMEOUT_ENABLE);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > > + CSI_PP_OUTPUT_FORMAT_PIXEL |
> > > + CSI_PP_DATA_TYPE(data_type) |
> > > + CSI_PP_CRC_CHECK_ENABLE |
> > > + CSI_PP_WORD_COUNT_HEADER |
> > > + CSI_PP_DATA_IDENTIFIER_ENABLE |
> > > + CSI_PP_PACKET_HEADER_SENT |
> > > + port);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > > + CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > > + (csi_chan->numlanes - 1));
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > > + CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > > + 0x5); /* Clock settle time */
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > + host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > + host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > +
> > > + value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > > + CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > + CSI_PP_DISABLE);
> > > +
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > + yuv_output_format | main_output_format);
> > > +
> > > + return 0;
> > > +};
> > > +
> > > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > > +{
> > > + struct tegra_csi *csi = csi_chan->csi;
> > > + unsigned int port = portno & 1;
> > > + u32 value;
> > > +
> > > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > > +
> > > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > +
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > + CSI_PP_DISABLE);
> > > +
> > > + if (csi_chan->numlanes == 4) {
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > > + CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > > + } else {
> > > + value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > > + CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > + }
> > > +}
> > > +
> > > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > > +{
> > > + u8 *portnos = csi_chan->csi_port_nums;
> > > + int ret, i;
> > > +
> > > + for (i = 0; i < csi_chan->numgangports; i++) {
> > > + ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > > + if (ret)
> > > + goto stream_start_fail;
> > > + }
> > > +
> > > + return 0;
> > > +
> > > +stream_start_fail:
> > > + for (i = i - 1; i >= 0; i--)
> > > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > +
> > > + return ret;
> > > +}
> > > +
> > > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > > +{
> > > + u8 *portnos = csi_chan->csi_port_nums;
> > > + int i;
> > > +
> > > + for (i = 0; i < csi_chan->numgangports; i++)
> > > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > +}
> > > +
> > > +/* Tegra20 CSI operations */
> > > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > > + .csi_start_streaming = tegra20_csi_start_streaming,
> > > + .csi_stop_streaming = tegra20_csi_stop_streaming,
> > > +};
> > > +
> > > +static const char * const tegra20_csi_clks[] = {
> > > + "csi",
> > > +};
> > > +
> > > +/* Tegra20 CSI SoC data */
> > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > + .ops = &tegra20_csi_ops,
> > > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > + .clk_names = tegra20_csi_clks,
> > > + .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > + .has_mipi_calibration = false,
> > > +};
> > > +
> > > +static const char * const tegra30_csi_clks[] = {
> > > + "csi",
> > > + "csia_pad",
> > > + "csib_pad",
> > > +};
> > > +
> > > +/* Tegra30 CSI SoC data */
> > > +const struct tegra_csi_soc tegra30_csi_soc = {
> > > + .ops = &tegra20_csi_ops,
> > > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > + .clk_names = tegra30_csi_clks,
> > > + .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > + .has_mipi_calibration = false,
> > > +};
> > > +
> > > /* --------------------------------------------------------------------------
> > > * VIP
> > > */
> > > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > OUT_2 : OUT_1;
> > >
> > > - unsigned int main_input_format;
> > > - unsigned int yuv_input_format;
> > > + unsigned int main_input_format, yuv_input_format;
> > > + unsigned int main_output_format, yuv_output_format;
> > >
> > > tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > >
> > > tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> > >
> > > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > >
> > > tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> > >
> > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > + yuv_output_format | main_output_format);
> > > +
> > > return 0;
> > > }
> > >
> > > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > > index cac0c0d0e225..c02517c9e09b 100644
> > > --- a/drivers/staging/media/tegra-video/vi.h
> > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > @@ -127,6 +127,7 @@ struct tegra_vi {
> > > * frame through host1x syncpoint counters (On Tegra20 used for the
> > > * OUT_1 syncpt)
> > > * @sp_incr_lock: protects cpu syncpoint increment.
> > > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> > > * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> > > *
> > > * @kthread_start_capture: kthread to start capture of single frame when
> > > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> > > /* protects the cpu syncpoint increment */
> > > spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> > > u32 next_out_sp_idx;
> > > + u32 next_fs_sp_idx;
> > >
> > > struct task_struct *kthread_start_capture;
> > > wait_queue_head_t start_wait;
> > > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > > index a25885f93cd7..8fa660431eb0 100644
> > > --- a/drivers/staging/media/tegra-video/video.c
> > > +++ b/drivers/staging/media/tegra-video/video.c
> > > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> > >
> > > static const struct of_device_id host1x_video_subdevs[] = {
> > > #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > + { .compatible = "nvidia,tegra20-csi", },
> > > { .compatible = "nvidia,tegra20-vip", },
> > > { .compatible = "nvidia,tegra20-vi", },
> > > #endif
> > > #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > + { .compatible = "nvidia,tegra30-csi", },
> > > { .compatible = "nvidia,tegra30-vip", },
> > > { .compatible = "nvidia,tegra30-vi", },
> > > #endif
> > >
> >
> >
> >
> >
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-09-02 6:17 ` Mikko Perttunen
@ 2025-09-02 6:21 ` Svyatoslav Ryhel
0 siblings, 0 replies; 59+ messages in thread
From: Svyatoslav Ryhel @ 2025-09-02 6:21 UTC (permalink / raw)
To: Mikko Perttunen
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
вт, 2 вер. 2025 р. о 09:18 Mikko Perttunen <mperttunen@nvidia.com> пише:
>
> On Tuesday, September 2, 2025 2:51 PM Svyatoslav Ryhel wrote:
> > вт, 2 вер. 2025 р. о 05:38 Mikko Perttunen <mperttunen@nvidia.com> пише:
> > >
> > > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > > Add support for MIPI CSI device found in Tegra20 and Tegra30 SoC.
> > > >
> > > > Co-developed-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > > Signed-off-by: Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > > ---
> > > > drivers/staging/media/tegra-video/csi.c | 12 +
> > > > drivers/staging/media/tegra-video/tegra20.c | 575 ++++++++++++++++++--
> > > > drivers/staging/media/tegra-video/vi.h | 2 +
> > > > drivers/staging/media/tegra-video/video.c | 2 +
> > > > 4 files changed, 553 insertions(+), 38 deletions(-)
> > > >
> > > > diff --git a/drivers/staging/media/tegra-video/csi.c b/drivers/staging/media/tegra-video/csi.c
> > > > index 2f9907a20db1..714ce52a793c 100644
> > > > --- a/drivers/staging/media/tegra-video/csi.c
> > > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > > @@ -826,11 +826,23 @@ static void tegra_csi_remove(struct platform_device *pdev)
> > > > pm_runtime_disable(&pdev->dev);
> > > > }
> > > >
> > > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > +extern const struct tegra_csi_soc tegra20_csi_soc;
> > > > +#endif
> > > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > +extern const struct tegra_csi_soc tegra30_csi_soc;
> > > > +#endif
> > > > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > > extern const struct tegra_csi_soc tegra210_csi_soc;
> > > > #endif
> > > >
> > > > static const struct of_device_id tegra_csi_of_id_table[] = {
> > > > +#if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > + { .compatible = "nvidia,tegra20-csi", .data = &tegra20_csi_soc },
> > > > +#endif
> > > > +#if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > + { .compatible = "nvidia,tegra30-csi", .data = &tegra30_csi_soc },
> > > > +#endif
> > > > #if defined(CONFIG_ARCH_TEGRA_210_SOC)
> > > > { .compatible = "nvidia,tegra210-csi", .data = &tegra210_csi_soc },
> > > > #endif
> > > > diff --git a/drivers/staging/media/tegra-video/tegra20.c b/drivers/staging/media/tegra-video/tegra20.c
> > > > index a06afe91d2de..e528ba280ae4 100644
> > > > --- a/drivers/staging/media/tegra-video/tegra20.c
> > > > +++ b/drivers/staging/media/tegra-video/tegra20.c
> > > > @@ -4,6 +4,9 @@
> > > > *
> > > > * Copyright (C) 2023 SKIDATA GmbH
> > > > * Author: Luca Ceresoli <luca.ceresoli@bootlin.com>
> > > > + *
> > > > + * Copyright (c) 2025 Svyatoslav Ryhel <clamor95@gmail.com>
> > > > + * Copyright (c) 2025 Jonas Schwöbel <jonasschwoebel@yahoo.de>
> > > > */
> > > >
> > > > /*
> > > > @@ -12,12 +15,16 @@
> > > > */
> > > >
> > > > #include <linux/bitfield.h>
> > > > +#include <linux/clk.h>
> > > > +#include <linux/clk/tegra.h>
> > > > #include <linux/delay.h>
> > > > #include <linux/host1x.h>
> > > > +#include <linux/iopoll.h>
> > > > #include <linux/kernel.h>
> > > > #include <linux/kthread.h>
> > > > #include <linux/v4l2-mediabus.h>
> > > >
> > > > +#include "csi.h"
> > > > #include "vip.h"
> > > > #include "vi.h"
> > > >
> > > > @@ -42,6 +49,9 @@ enum {
> > > > #define VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT BIT(8)
> > > > #define VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT 0
> > > >
> > > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(n) (0x0070 + (n) * 8)
> > > > +#define TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_END(n) (0x0074 + (n) * 8)
> > > > +
> > > > #define TEGRA_VI_VI_INPUT_CONTROL 0x0088
> > > > #define VI_INPUT_FIELD_DETECT BIT(27)
> > > > #define VI_INPUT_BT656 BIT(25)
> > > > @@ -87,6 +97,8 @@ enum {
> > > > #define VI_OUTPUT_OUTPUT_FORMAT_SFT 0
> > > > #define VI_OUTPUT_OUTPUT_FORMAT_YUV422POST (3 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > #define VI_OUTPUT_OUTPUT_FORMAT_YUV420PLANAR (6 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER (7 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > +#define VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER (8 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > > #define VI_OUTPUT_OUTPUT_FORMAT_VIP_BAYER_DIRECT (9 << VI_OUTPUT_OUTPUT_FORMAT_SFT)
> > > >
> > > > #define TEGRA_VI_VIP_H_ACTIVE 0x00a4
> > > > @@ -151,8 +163,106 @@ enum {
> > > > #define TEGRA_VI_VI_RAISE 0x01ac
> > > > #define VI_VI_RAISE_ON_EDGE BIT(0)
> > > >
> > > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_START(n) (0x01d8 + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_RAISE_FRAME_END(n) (0x01dc + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_H_ACTIVE(n) (0x01e8 + (n) * 8)
> > > > +#define TEGRA_VI_CSI_PP_V_ACTIVE(n) (0x01ec + (n) * 8)
> > > > +
> > > > +/* Tegra20 CSI registers: Starts from 0x800, offset 0x0 */
> > > > +#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0000
> > > > +#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0008
> > > > +#define TEGRA_CSI_INPUT_STREAM_CONTROL(n) (0x0010 + (n) * 0x2c)
> > > > +#define CSI_SKIP_PACKET_THRESHOLD(n) (((n) & 0xff) << 16)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL0(n) (0x0018 + (n) * 0x2c)
> > > > +#define CSI_PP_PAD_FRAME_PAD0S (0 << 28)
> > > > +#define CSI_PP_PAD_FRAME_PAD1S (1 << 28)
> > > > +#define CSI_PP_PAD_FRAME_NOPAD (2 << 28)
> > > > +#define CSI_PP_HEADER_EC_ENABLE BIT(27)
> > > > +#define CSI_PP_PAD_SHORT_LINE_PAD0S (0 << 24)
> > > > +#define CSI_PP_PAD_SHORT_LINE_PAD1S (1 << 24)
> > > > +#define CSI_PP_PAD_SHORT_LINE_NOPAD (2 << 24)
> > > > +#define CSI_PP_EMBEDDED_DATA_EMBEDDED BIT(20)
> > > > +#define CSI_PP_OUTPUT_FORMAT_ARBITRARY (0 << 16)
> > > > +#define CSI_PP_OUTPUT_FORMAT_PIXEL (1 << 16)
> > > > +#define CSI_PP_OUTPUT_FORMAT_PIXEL_REP (2 << 16)
> > > > +#define CSI_PP_OUTPUT_FORMAT_STORE (3 << 16)
> > > > +#define CSI_PP_VIRTUAL_CHANNEL_ID(n) (((n) - 1) << 14)
> > > > +#define CSI_PP_DATA_TYPE(n) ((n) << 8)
> > > > +#define CSI_PP_CRC_CHECK_ENABLE BIT(7)
> > > > +#define CSI_PP_WORD_COUNT_HEADER BIT(6)
> > > > +#define CSI_PP_DATA_IDENTIFIER_ENABLE BIT(5)
> > > > +#define CSI_PP_PACKET_HEADER_SENT BIT(4)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_CONTROL1(n) (0x001c + (n) * 0x2c)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(n) (0x0020 + (n) * 0x2c)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_GAP(n) (0x0024 + (n) * 0x2c)
> > > > +#define CSI_PP_FRAME_MIN_GAP(n) (((n) & 0xffff) << 16)
> > > > +#define CSI_PP_LINE_MIN_GAP(n) (((n) & 0xffff))
> > > > +#define TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(n) (0x0028 + (n) * 0x2c)
> > > > +#define CSI_PP_START_MARKER_FRAME_MAX(n) (((n) & 0xf) << 12)
> > > > +#define CSI_PP_START_MARKER_FRAME_MIN(n) (((n) & 0xf) << 8)
> > > > +#define CSI_PP_VSYNC_START_MARKER BIT(4)
> > > > +#define CSI_PP_SINGLE_SHOT BIT(2)
> > > > +#define CSI_PP_NOP 0
> > > > +#define CSI_PP_ENABLE 1
> > > > +#define CSI_PP_DISABLE 2
> > > > +#define CSI_PP_RST 3
> > > > +#define TEGRA_CSI_PHY_CIL_COMMAND 0x0068
> > > > +#define CSI_A_PHY_CIL_NOP 0x0
> > > > +#define CSI_A_PHY_CIL_ENABLE 0x1
> > > > +#define CSI_A_PHY_CIL_DISABLE 0x2
> > > > +#define CSI_A_PHY_CIL_ENABLE_MASK 0x3
> > > > +#define CSI_B_PHY_CIL_NOP (0x0 << 16)
> > > > +#define CSI_B_PHY_CIL_ENABLE (0x1 << 16)
> > > > +#define CSI_B_PHY_CIL_DISABLE (0x2 << 16)
> > > > +#define CSI_B_PHY_CIL_ENABLE_MASK (0x3 << 16)
> > > > +#define TEGRA_CSI_PHY_CIL_CONTROL0(n) (0x006c + (n) * 4)
> > > > +#define CSI_CONTINUOUS_CLOCK_MODE_ENABLE BIT(5)
> > > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0078
> > > > +#define TEGRA_CSI_CSI_CIL_STATUS 0x007c
> > > > +#define CSI_MIPI_AUTO_CAL_DONE BIT(15)
> > > > +#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0080
> > > > +#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0084
> > > > +#define TEGRA_CSI_CSI_READONLY_STATUS 0x0088
> > > > +#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x008c
> > > > +#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0090
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG0(n) (0x0094 + (n) * 8)
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG1(n) (0x0098 + (n) * 8)
> > > > +#define TEGRA_CSI_CIL_PAD_CONFIG 0x00a4
> > > > +#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x00a8
> > > > +#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x00ac
> > > > +#define CSI_CIL_MIPI_CAL_STARTCAL BIT(31)
> > > > +#define CSI_CIL_MIPI_CAL_OVERIDE_A BIT(30)
> > > > +#define CSI_CIL_MIPI_CAL_OVERIDE_B BIT(30)
> > > > +#define CSI_CIL_MIPI_CAL_NOISE_FLT(n) (((n) & 0xf) << 26)
> > > > +#define CSI_CIL_MIPI_CAL_PRESCALE(n) (((n) & 0x3) << 24)
> > > > +#define CSI_CIL_MIPI_CAL_SEL_A BIT(21)
> > > > +#define CSI_CIL_MIPI_CAL_SEL_B BIT(21)
> > > > +#define CSI_CIL_MIPI_CAL_HSPDOS(n) (((n) & 0x1f) << 16)
> > > > +#define CSI_CIL_MIPI_CAL_HSPUOS(n) (((n) & 0x1f) << 8)
> > > > +#define CSI_CIL_MIPI_CAL_TERMOS(n) (((n) & 0x1f))
> > > > +#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x00b0
> > > > +#define TEGRA_CSI_CLKEN_OVERRIDE 0x00b4
> > > > +#define TEGRA_CSI_DEBUG_CONTROL 0x00b8
> > > > +#define CSI_DEBUG_CONTROL_DEBUG_EN_ENABLED BIT(0)
> > > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 BIT(4)
> > > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 BIT(5)
> > > > +#define CSI_DEBUG_CONTROL_CLR_DBG_CNT_2 BIT(6)
> > > > +#define CSI_DEBUG_CONTROL_DBG_CNT_SEL(n, v) ((v) << (8 + 8 * (n)))
> > > > +#define TEGRA_CSI_DEBUG_COUNTER(n) (0x00bc + (n) * 4)
> > > > +#define TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(n) (0x00c8 + (n) * 4)
> > > > +#define CSI_PP_EXP_FRAME_HEIGHT(n) (((n) & 0x1fff) << 16)
> > > > +#define CSI_PP_MAX_CLOCKS(n) (((n) & 0xfff) << 4)
> > > > +#define CSI_PP_LINE_TIMEOUT_ENABLE BIT(0)
> > > > +#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x00d0
> > > > +#define TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x00d4
> > > > +#define CSI_PAD_DRIV_DN_REF(n) (((n) & 0x7) << 16)
> > > > +#define CSI_PAD_DRIV_UP_REF(n) (((n) & 0x7) << 8)
> > > > +#define CSI_PAD_TERM_REF(n) (((n) & 0x7) << 0)
> > > > +#define TEGRA_CSI_CSI_CILA_STATUS 0x00d8
> > > > +#define TEGRA_CSI_CSI_CILB_STATUS 0x00dc
> > > > +
> > > > /* --------------------------------------------------------------------------
> > > > - * VI
> > > > + * Read and Write helpers
> > > > */
> > > >
> > > > static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u32 val)
> > > > @@ -160,6 +270,25 @@ static void tegra20_vi_write(struct tegra_vi_channel *chan, unsigned int addr, u
> > > > writel(val, chan->vi->iomem + addr);
> > > > }
> > > >
> > > > +static int __maybe_unused tegra20_vi_read(struct tegra_vi_channel *chan, unsigned int addr)
> > > > +{
> > > > + return readl(chan->vi->iomem + addr);
> > > > +}
> > > > +
> > > > +static void tegra20_csi_write(struct tegra_csi_channel *csi_chan, unsigned int addr, u32 val)
> > > > +{
> > > > + writel(val, csi_chan->csi->iomem + addr);
> > > > +}
> > > > +
> > > > +static int __maybe_unused tegra20_csi_read(struct tegra_csi_channel *csi_chan, unsigned int addr)
> > > > +{
> > > > + return readl(csi_chan->csi->iomem + addr);
> > > > +}
> > > > +
> > > > +/* --------------------------------------------------------------------------
> > > > + * VI
> > > > + */
> > > > +
> > > > /*
> > > > * Get the main input format (YUV/RGB...) and the YUV variant as values to
> > > > * be written into registers for the current VI input mbus code.
> > > > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > > > static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > > > {
> > > > struct tegra_vi *vi = chan->vi;
> > > > - struct host1x_syncpt *out_sp;
> > > > + struct host1x_syncpt *out_sp, *fs_sp;
> > > >
> > > > out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > > if (!out_sp)
> > > > - return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > > > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
> > >
> > > Existing issue, but dev_err_probe doesn't print anything when the error is -ENOMEM, since "there is already enough output". But that's not necessarily the case with failing syncpoint allocation. Maybe we should be using a different error code like EBUSY?
> > >
> >
> > That is interesting. I am fine to switching to any error code as long
> > as it fits here, EBUSY fits fine.
> >
> > > >
> > > > chan->mw_ack_sp[0] = out_sp;
> > > >
> > > > + fs_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > > > + if (!fs_sp)
> > > > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request frame start syncpoint\n");
> > > > +
> > > > + chan->frame_start_sp[0] = fs_sp;
> > > > +
> > > > return 0;
> > > > }
> > > >
> > > > static void tegra20_channel_host1x_syncpt_free(struct tegra_vi_channel *chan)
> > > > {
> > > > host1x_syncpt_put(chan->mw_ack_sp[0]);
> > > > + host1x_syncpt_put(chan->frame_start_sp[0]);
> > > > }
> > > >
> > > > static void tegra20_fmt_align(struct v4l2_pix_format *pix, unsigned int bpp)
> > > > @@ -418,30 +554,60 @@ static void tegra20_channel_vi_buffer_setup(struct tegra_vi_channel *chan,
> > > > static int tegra20_channel_capture_frame(struct tegra_vi_channel *chan,
> > > > struct tegra_channel_buffer *buf)
> > > > {
> > > > + struct v4l2_subdev *csi_subdev = NULL;
> > > > + struct tegra_csi_channel *csi_chan = NULL;
> > > > + u32 port;
> > > > int err;
> > > >
> > > > - chan->next_out_sp_idx++;
> > > > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > > + if (csi_subdev) {
> > > > + /* CSI subdevs are named after nodes, channel@0 or channel@1 */
> > > > + if (!strncmp(csi_subdev->name, "channel", 7)) {
> > > > + csi_chan = to_csi_chan(csi_subdev);
> > > > + port = csi_chan->csi_port_nums[0] & 1;
> > > > + }
> > > > + }
> > >
> > > tegra_channel_get_remote_csi_subdev sounds like it should only return non-NULL if it's a CSI subdev. I'd move this check into that function.
> > >
> >
> > That is possible.
> >
> > > Checking by name doesn't seem right -- v4l2_subdev has an 'ops' pointer, could we compare that to tegra_csi_ops to check if it's a CSI subdev?
> > >
> >
> > I may try that. My main concern was VIP. Unlike Tegra210,
> > Tegra20/Tegra30 have VIP which can cause issues if no additional
> > checks are done.
> >
> > > Finally, is it possible to move this logic to some initialization logic for the 'chan' instead of each frame?
> > >
> >
> > Yes, I hope so. We did not implement this logic, it existed before, we
> > just expanded it to support CSI.
>
> If it's non-trivial it can be left for later.
>
No no, I have some ideas that may address this.
> >
> > > >
> > > > tegra20_channel_vi_buffer_setup(chan, buf);
> > > >
> > > > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > + if (csi_chan) {
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > + CSI_PP_SINGLE_SHOT | CSI_PP_ENABLE);
> > > > +
> > > > + chan->next_fs_sp_idx++;
> > > > + err = host1x_syncpt_wait(chan->frame_start_sp[0], chan->next_fs_sp_idx,
> > > > + TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > > + if (err) {
> > > > + host1x_syncpt_incr(chan->frame_start_sp[0]);
> > >
> > > This is technically a race condition -- the HW could increment the syncpoint between the wait timing out and the call to _incr. The driver should ensure the HW won't increment the syncpoint before checking the value one more time and then making conclusions about the syncpoint's value. I also don't think it's necessary to call _incr here, you can pass chan->next_fs_sp_idx + 1 to syncpt_wait, and then only on success increment chan->next_fs_sp_idx.
> > >
> >
> > The race condition should be avoidable by resetting pixel parser and
> > checking syncpt value again.
> > Incrementing the software reference counter only if hardware completed
> > successfully sounds like a good idea.
> >
> > > Also, I'd rename this to next_fs_sp_value. 'idx' to me sounds like there are multiple syncpoints that are used e.g. in succession.
> > >
> > > (I know these are in line with the existing out_sp code, but it'd be great if we can fix these issues.)
> > >
> > > > + if (err != -ERESTARTSYS)
> > > > + dev_err_ratelimited(&chan->video.dev,
> > > > + "frame start syncpt timeout: %d\n", err);
> > > > + }
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > + CSI_PP_DISABLE);
> > > > + } else {
> > > > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > + }
> > > >
> > > > - /* Wait for syncpt counter to reach frame start event threshold */
> > > > + chan->next_out_sp_idx++;
> > > > err = host1x_syncpt_wait(chan->mw_ack_sp[0], chan->next_out_sp_idx,
> > > > TEGRA_VI_SYNCPT_WAIT_TIMEOUT, NULL);
> > > > if (err) {
> > > > host1x_syncpt_incr(chan->mw_ack_sp[0]);
> > > > - dev_err_ratelimited(&chan->video.dev, "frame start syncpt timeout: %d\n", err);
> > > > - release_buffer(chan, buf, VB2_BUF_STATE_ERROR);
> > > > - return err;
> > > > + if (err != -ERESTARTSYS)
> > > > + dev_err_ratelimited(&chan->video.dev, "mw ack syncpt timeout: %d\n", err);
> > > > }
> > > >
> > > > - tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > > - VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > > + if (!csi_chan)
> > > > + tegra20_vi_write(chan, TEGRA_VI_CAMERA_CONTROL,
> > > > + VI_CAMERA_CONTROL_STOP_CAPTURE | VI_CAMERA_CONTROL_VIP_ENABLE);
> > > >
> > > > release_buffer(chan, buf, VB2_BUF_STATE_DONE);
> > > >
> > > > - return 0;
> > > > + return err;
> > > > }
> > > >
> > > > static int tegra20_chan_capture_kthread_start(void *data)
> > > > @@ -502,28 +668,6 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > > int output_channel = (data_type == TEGRA_IMAGE_DT_RAW8 ||
> > > > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > > OUT_2 : OUT_1;
> > > > - int main_output_format;
> > > > - int yuv_output_format;
> > > > -
> > > > - tegra20_vi_get_output_formats(chan, &main_output_format, &yuv_output_format);
> > > > -
> > > > - /*
> > > > - * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > > > - * for luminance, which is the default and means not to touch
> > > > - * anything.
> > > > - */
> > > > - tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > > - 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > > - 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > > -
> > > > - /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > > - tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > > -
> > > > - tegra20_vi_write(chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > - (chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > - (chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > - yuv_output_format << VI_OUTPUT_YUV_OUTPUT_FORMAT_SFT |
> > > > - main_output_format << VI_OUTPUT_OUTPUT_FORMAT_SFT);
> > > >
> > > > /* Set up frame size */
> > > > tegra20_vi_write(chan, TEGRA_VI_OUTPUT_FRAME_SIZE(output_channel),
> > > > @@ -548,24 +692,148 @@ static void tegra20_camera_capture_setup(struct tegra_vi_channel *chan)
> > > > tegra20_vi_write(chan, TEGRA_VI_VI_ENABLE(output_channel), 0);
> > > > }
> > > >
> > > > +static int tegra20_csi_pad_calibration(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > + struct tegra_csi *csi = csi_chan->csi;
> > > > + void __iomem *cil_status_reg = csi_chan->csi->iomem + TEGRA_CSI_CSI_CIL_STATUS;
> > > > + unsigned int port = csi_chan->csi_port_nums[0] & 1;
> > > > + u32 value, pp, cil;
> > > > + int ret;
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_DSI_MIPI_CAL_CONFIG,
> > > > + CSI_CIL_MIPI_CAL_HSPDOS(4) |
> > > > + CSI_CIL_MIPI_CAL_HSPUOS(3) |
> > > > + CSI_CIL_MIPI_CAL_TERMOS(0));
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0,
> > > > + CSI_PAD_DRIV_DN_REF(5) |
> > > > + CSI_PAD_DRIV_UP_REF(7) |
> > > > + CSI_PAD_TERM_REF(0));
> > > > +
> > > > + /* CSI B */
> > > > + value = CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > > > +
> > > > + if (port == PORT_B || csi_chan->numlanes == 4)
> > > > + value |= CSI_CIL_MIPI_CAL_SEL_B;
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, value);
> > > > +
> > > > + /* CSI A */
> > > > + value = CSI_CIL_MIPI_CAL_STARTCAL |
> > > > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > + CSI_CIL_MIPI_CAL_TERMOS(4);
> > > > +
> > > > + if (port == PORT_A)
> > > > + value |= CSI_CIL_MIPI_CAL_SEL_A;
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, value);
> > > > +
> > > > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > > + value & CSI_MIPI_AUTO_CAL_DONE, 50, 250000);
> > > > + if (ret < 0) {
> > > > + dev_warn(csi->dev, "MIPI calibration timeout!\n");
> > > > + goto exit;
> > > > + }
> > > > +
> > > > + /* clear status */
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > > + ret = readl_relaxed_poll_timeout(cil_status_reg, value,
> > > > + !(value & CSI_MIPI_AUTO_CAL_DONE), 50, 250000);
> > > > + if (ret < 0) {
> > > > + dev_warn(csi->dev, "MIPI calibration status timeout!\n");
> > > > + goto exit;
> > > > + }
> > > > +
> > > > + pp = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > > + cil = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > > + if (pp | cil) {
> > > > + dev_warn(csi->dev, "Calibration status not been cleared!\n");
> > > > + ret = -EINVAL;
> > > > + goto exit;
> > > > + }
> > > > +
> > > > +exit:
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, pp);
> > > > +
> > > > + /* un-select to avoid interference with DSI */
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILB_MIPI_CAL_CONFIG,
> > > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CILA_MIPI_CAL_CONFIG,
> > > > + CSI_CIL_MIPI_CAL_NOISE_FLT(0xa) |
> > > > + CSI_CIL_MIPI_CAL_PRESCALE(0x2) |
> > > > + CSI_CIL_MIPI_CAL_HSPDOS(0) |
> > > > + CSI_CIL_MIPI_CAL_HSPUOS(0) |
> > > > + CSI_CIL_MIPI_CAL_TERMOS(4));
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > > {
> > > > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > > struct media_pipeline *pipe = &chan->video.pipe;
> > > > + struct v4l2_subdev *csi_subdev, *src_subdev;
> > > > + struct tegra_csi_channel *csi_chan = NULL;
> > > > int err;
> > > >
> > > > + csi_subdev = tegra_channel_get_remote_csi_subdev(chan);
> > > > + if (csi_subdev) {
> > > > + if (!strncmp(csi_subdev->name, "channel", 7))
> > > > + csi_chan = to_csi_chan(csi_subdev);
> > > > + }
> > > > +
> > > > + chan->next_fs_sp_idx = host1x_syncpt_read(chan->frame_start_sp[0]);
> > > > chan->next_out_sp_idx = host1x_syncpt_read(chan->mw_ack_sp[0]);
> > > >
> > > > err = video_device_pipeline_start(&chan->video, pipe);
> > > > if (err)
> > > > goto error_pipeline_start;
> > > >
> > > > - tegra20_camera_capture_setup(chan);
> > > > + /*
> > > > + * Set up low pass filter. Use 0x240 for chromaticity and 0x240
> > > > + * for luminance, which is the default and means not to touch
> > > > + * anything.
> > > > + */
> > > > + tegra20_vi_write(chan, TEGRA_VI_H_LPF_CONTROL,
> > > > + 0x0240 << VI_H_LPF_CONTROL_LUMA_SFT |
> > > > + 0x0240 << VI_H_LPF_CONTROL_CHROMA_SFT);
> > > > +
> > > > + /* Set up raise-on-edge, so we get an interrupt on end of frame. */
> > > > + tegra20_vi_write(chan, TEGRA_VI_VI_RAISE, VI_VI_RAISE_ON_EDGE);
> > > >
> > > > err = tegra_channel_set_stream(chan, true);
> > > > if (err)
> > > > goto error_set_stream;
> > > >
> > > > + tegra20_camera_capture_setup(chan);
> > > > +
> > > > + if (csi_chan) {
> > > > + /*
> > > > + * TRM has incorrectly documented to wait for done status from
> > > > + * calibration logic after CSI interface power on.
> > > > + * As per the design, calibration results are latched and applied
> > > > + * to the pads only when the link is in LP11 state which will happen
> > > > + * during the sensor stream-on.
> > > > + * CSI subdev stream-on triggers start of MIPI pads calibration.
> > > > + * Wait for calibration to finish here after sensor subdev stream-on.
> > > > + */
> > > > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > > + if (!src_subdev->s_stream_enabled) {
> > > > + err = v4l2_subdev_call(src_subdev, video, s_stream, true);
> > > > + if (err < 0 && err != -ENOIOCTLCMD)
> > > > + goto error_set_stream;
> > > > + }
> > > > +
> > > > + tegra20_csi_pad_calibration(csi_chan);
> > > > + }
> > > > +
> > > > chan->sequence = 0;
> > > >
> > > > chan->kthread_start_capture = kthread_run(tegra20_chan_capture_kthread_start,
> > > > @@ -592,12 +860,17 @@ static int tegra20_vi_start_streaming(struct vb2_queue *vq, u32 count)
> > > > static void tegra20_vi_stop_streaming(struct vb2_queue *vq)
> > > > {
> > > > struct tegra_vi_channel *chan = vb2_get_drv_priv(vq);
> > > > + struct v4l2_subdev *src_subdev;
> > > >
> > > > if (chan->kthread_start_capture) {
> > > > kthread_stop(chan->kthread_start_capture);
> > > > chan->kthread_start_capture = NULL;
> > > > }
> > > >
> > > > + src_subdev = tegra_channel_get_remote_source_subdev(chan);
> > > > + if (src_subdev->s_stream_enabled)
> > > > + v4l2_subdev_call(src_subdev, video, s_stream, false);
> > > > +
> > > > tegra_channel_release_buffers(chan, VB2_BUF_STATE_ERROR);
> > > > tegra_channel_set_stream(chan, false);
> > > > video_device_pipeline_stop(&chan->video);
> > > > @@ -652,11 +925,231 @@ const struct tegra_vi_soc tegra20_vi_soc = {
> > > > .default_video_format = &tegra20_video_formats[0],
> > > > .ops = &tegra20_vi_ops,
> > > > .hw_revision = 1,
> > > > - .vi_max_channels = 1, /* parallel input (VIP) */
> > > > + .vi_max_channels = 4, /* parallel input (VIP), CSIA, CSIB, HOST */
> > > > .vi_max_clk_hz = 450000000,
> > > > .has_h_v_flip = true,
> > > > };
> > > >
> > > > +/* --------------------------------------------------------------------------
> > > > + * CSI
> > > > + */
> > > > +static void tegra20_csi_capture_clean(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_READONLY_STATUS, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_ESCAPE_MODE_DATA, 0);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CLKEN_OVERRIDE, 0);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_DEBUG_CONTROL,
> > > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_0 |
> > > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_1 |
> > > > + CSI_DEBUG_CONTROL_CLR_DBG_CNT_2);
> > > > +}
> > > > +
> > > > +static int tegra20_csi_port_start_streaming(struct tegra_csi_channel *csi_chan,
> > > > + u8 portno)
> > > > +{
> > > > + struct tegra_vi_channel *vi_chan = v4l2_get_subdev_hostdata(&csi_chan->subdev);
> > > > + int width = vi_chan->format.width;
> > > > + int height = vi_chan->format.height;
> > > > + u32 data_type = vi_chan->fmtinfo->img_dt;
> > > > + u32 word_count = (width * vi_chan->fmtinfo->bit_width) / 8;
> > > > + int output_channel = OUT_1;
> > > > +
> > > > + unsigned int main_output_format, yuv_output_format;
> > > > + unsigned int port = portno & 1;
> > > > + u32 value;
> > > > +
> > > > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > > +
> > > > + switch (data_type) {
> > > > + case TEGRA_IMAGE_DT_RAW8:
> > > > + case TEGRA_IMAGE_DT_RAW10:
> > > > + output_channel = OUT_2;
> > > > + if (port == PORT_A)
> > > > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPA_BAYER;
> > > > + else
> > > > + main_output_format = VI_OUTPUT_OUTPUT_FORMAT_CSI_PPB_BAYER;
> > > > + break;
> > > > + }
> > > > +
> > > > + tegra20_csi_capture_clean(csi_chan);
> > > > +
> > > > + /* CSI port cleanup */
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG0(port), 0);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CIL_PAD_CONFIG1(port), 0);
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, BIT(25 + port)); /* CSI_PP_YUV422 */
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_H_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_V_DOWNSCALE_CONTROL, BIT(2 + port)); /* CSI_PP */
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_H_ACTIVE(port), width << 16);
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_CSI_PP_V_ACTIVE(port), height << 16);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL1(port), 0x1);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_WORD_COUNT(port), word_count);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_GAP(port),
> > > > + CSI_PP_FRAME_MIN_GAP(0x14)); /* 14 vi clks between frames */
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_EXPECTED_FRAME(port),
> > > > + CSI_PP_EXP_FRAME_HEIGHT(height) |
> > > > + CSI_PP_MAX_CLOCKS(0x300) | /* wait 0x300 vi clks for timeout */
> > > > + CSI_PP_LINE_TIMEOUT_ENABLE);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_CONTROL0(port),
> > > > + CSI_PP_OUTPUT_FORMAT_PIXEL |
> > > > + CSI_PP_DATA_TYPE(data_type) |
> > > > + CSI_PP_CRC_CHECK_ENABLE |
> > > > + CSI_PP_WORD_COUNT_HEADER |
> > > > + CSI_PP_DATA_IDENTIFIER_ENABLE |
> > > > + CSI_PP_PACKET_HEADER_SENT |
> > > > + port);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_INPUT_STREAM_CONTROL(port),
> > > > + CSI_SKIP_PACKET_THRESHOLD(0x3f) |
> > > > + (csi_chan->numlanes - 1));
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_CONTROL0(port),
> > > > + CSI_CONTINUOUS_CLOCK_MODE_ENABLE |
> > > > + 0x5); /* Clock settle time */
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_CSI_PP_FRAME_START(port),
> > > > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > > + host1x_syncpt_id(vi_chan->frame_start_sp[0])
> > > > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_CONT_SYNCPT_OUT(output_channel),
> > > > + VI_CONT_SYNCPT_OUT_CONTINUOUS_SYNCPT |
> > > > + host1x_syncpt_id(vi_chan->mw_ack_sp[0])
> > > > + << VI_CONT_SYNCPT_OUT_SYNCPT_IDX_SFT);
> > > > +
> > > > + value = (port == PORT_A) ? CSI_A_PHY_CIL_ENABLE | CSI_B_PHY_CIL_DISABLE :
> > > > + CSI_B_PHY_CIL_ENABLE | CSI_A_PHY_CIL_DISABLE;
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > + CSI_PP_DISABLE);
> > > > +
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > + yuv_output_format | main_output_format);
> > > > +
> > > > + return 0;
> > > > +};
> > > > +
> > > > +static void tegra20_csi_port_stop_streaming(struct tegra_csi_channel *csi_chan, u8 portno)
> > > > +{
> > > > + struct tegra_csi *csi = csi_chan->csi;
> > > > + unsigned int port = portno & 1;
> > > > + u32 value;
> > > > +
> > > > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
> > > > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x%08x\n", value);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, value);
> > > > +
> > > > + value = tegra20_csi_read(csi_chan, TEGRA_CSI_CSI_CIL_STATUS);
> > > > + dev_dbg(csi->dev, "TEGRA_CSI_CSI_CIL_STATUS 0x%08x\n", value);
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_CSI_CIL_STATUS, value);
> > > > +
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PIXEL_STREAM_PP_COMMAND(port),
> > > > + CSI_PP_START_MARKER_FRAME_MAX(0xf) |
> > > > + CSI_PP_DISABLE);
> > > > +
> > > > + if (csi_chan->numlanes == 4) {
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND,
> > > > + CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_DISABLE);
> > > > + } else {
> > > > + value = (port == PORT_A) ? CSI_A_PHY_CIL_DISABLE | CSI_B_PHY_CIL_NOP :
> > > > + CSI_B_PHY_CIL_DISABLE | CSI_A_PHY_CIL_NOP;
> > > > + tegra20_csi_write(csi_chan, TEGRA_CSI_PHY_CIL_COMMAND, value);
> > > > + }
> > > > +}
> > > > +
> > > > +static int tegra20_csi_start_streaming(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > + u8 *portnos = csi_chan->csi_port_nums;
> > > > + int ret, i;
> > > > +
> > > > + for (i = 0; i < csi_chan->numgangports; i++) {
> > > > + ret = tegra20_csi_port_start_streaming(csi_chan, portnos[i]);
> > > > + if (ret)
> > > > + goto stream_start_fail;
> > > > + }
> > > > +
> > > > + return 0;
> > > > +
> > > > +stream_start_fail:
> > > > + for (i = i - 1; i >= 0; i--)
> > > > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > > +
> > > > + return ret;
> > > > +}
> > > > +
> > > > +static void tegra20_csi_stop_streaming(struct tegra_csi_channel *csi_chan)
> > > > +{
> > > > + u8 *portnos = csi_chan->csi_port_nums;
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < csi_chan->numgangports; i++)
> > > > + tegra20_csi_port_stop_streaming(csi_chan, portnos[i]);
> > > > +}
> > > > +
> > > > +/* Tegra20 CSI operations */
> > > > +static const struct tegra_csi_ops tegra20_csi_ops = {
> > > > + .csi_start_streaming = tegra20_csi_start_streaming,
> > > > + .csi_stop_streaming = tegra20_csi_stop_streaming,
> > > > +};
> > > > +
> > > > +static const char * const tegra20_csi_clks[] = {
> > > > + "csi",
> > > > +};
> > > > +
> > > > +/* Tegra20 CSI SoC data */
> > > > +const struct tegra_csi_soc tegra20_csi_soc = {
> > > > + .ops = &tegra20_csi_ops,
> > > > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > > + .clk_names = tegra20_csi_clks,
> > > > + .num_clks = ARRAY_SIZE(tegra20_csi_clks),
> > > > + .has_mipi_calibration = false,
> > > > +};
> > > > +
> > > > +static const char * const tegra30_csi_clks[] = {
> > > > + "csi",
> > > > + "csia_pad",
> > > > + "csib_pad",
> > > > +};
> > > > +
> > > > +/* Tegra30 CSI SoC data */
> > > > +const struct tegra_csi_soc tegra30_csi_soc = {
> > > > + .ops = &tegra20_csi_ops,
> > > > + .csi_max_channels = 2, /* CSI-A and CSI-B */
> > > > + .clk_names = tegra30_csi_clks,
> > > > + .num_clks = ARRAY_SIZE(tegra30_csi_clks),
> > > > + .has_mipi_calibration = false,
> > > > +};
> > > > +
> > > > /* --------------------------------------------------------------------------
> > > > * VIP
> > > > */
> > > > @@ -677,10 +1170,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > > > data_type == TEGRA_IMAGE_DT_RAW10) ?
> > > > OUT_2 : OUT_1;
> > > >
> > > > - unsigned int main_input_format;
> > > > - unsigned int yuv_input_format;
> > > > + unsigned int main_input_format, yuv_input_format;
> > > > + unsigned int main_output_format, yuv_output_format;
> > > >
> > > > tegra20_vi_get_input_formats(vi_chan, &main_input_format, &yuv_input_format);
> > > > + tegra20_vi_get_output_formats(vi_chan, &main_output_format, &yuv_output_format);
> > > >
> > > > tegra20_vi_write(vi_chan, TEGRA_VI_VI_CORE_CONTROL, 0);
> > > >
> > > > @@ -713,6 +1207,11 @@ static int tegra20_vip_start_streaming(struct tegra_vip_channel *vip_chan)
> > > >
> > > > tegra20_vi_write(vi_chan, TEGRA_VI_CAMERA_CONTROL, VI_CAMERA_CONTROL_STOP_CAPTURE);
> > > >
> > > > + tegra20_vi_write(vi_chan, TEGRA_VI_VI_OUTPUT_CONTROL(output_channel),
> > > > + (vi_chan->vflip ? VI_OUTPUT_V_DIRECTION : 0) |
> > > > + (vi_chan->hflip ? VI_OUTPUT_H_DIRECTION : 0) |
> > > > + yuv_output_format | main_output_format);
> > > > +
> > > > return 0;
> > > > }
> > > >
> > > > diff --git a/drivers/staging/media/tegra-video/vi.h b/drivers/staging/media/tegra-video/vi.h
> > > > index cac0c0d0e225..c02517c9e09b 100644
> > > > --- a/drivers/staging/media/tegra-video/vi.h
> > > > +++ b/drivers/staging/media/tegra-video/vi.h
> > > > @@ -127,6 +127,7 @@ struct tegra_vi {
> > > > * frame through host1x syncpoint counters (On Tegra20 used for the
> > > > * OUT_1 syncpt)
> > > > * @sp_incr_lock: protects cpu syncpoint increment.
> > > > + * @next_fs_sp_idx: next expected value for frame_start_sp[0] (Tegra20)
> > > > * @next_out_sp_idx: next expected value for mw_ack_sp[0], i.e. OUT_1 (Tegra20)
> > > > *
> > > > * @kthread_start_capture: kthread to start capture of single frame when
> > > > @@ -191,6 +192,7 @@ struct tegra_vi_channel {
> > > > /* protects the cpu syncpoint increment */
> > > > spinlock_t sp_incr_lock[GANG_PORTS_MAX];
> > > > u32 next_out_sp_idx;
> > > > + u32 next_fs_sp_idx;
> > > >
> > > > struct task_struct *kthread_start_capture;
> > > > wait_queue_head_t start_wait;
> > > > diff --git a/drivers/staging/media/tegra-video/video.c b/drivers/staging/media/tegra-video/video.c
> > > > index a25885f93cd7..8fa660431eb0 100644
> > > > --- a/drivers/staging/media/tegra-video/video.c
> > > > +++ b/drivers/staging/media/tegra-video/video.c
> > > > @@ -124,10 +124,12 @@ static int host1x_video_remove(struct host1x_device *dev)
> > > >
> > > > static const struct of_device_id host1x_video_subdevs[] = {
> > > > #if defined(CONFIG_ARCH_TEGRA_2x_SOC)
> > > > + { .compatible = "nvidia,tegra20-csi", },
> > > > { .compatible = "nvidia,tegra20-vip", },
> > > > { .compatible = "nvidia,tegra20-vi", },
> > > > #endif
> > > > #if defined(CONFIG_ARCH_TEGRA_3x_SOC)
> > > > + { .compatible = "nvidia,tegra30-csi", },
> > > > { .compatible = "nvidia,tegra30-vip", },
> > > > { .compatible = "nvidia,tegra30-vi", },
> > > > #endif
> > > >
> > >
> > >
> > >
> > >
>
>
>
>
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence
2025-09-02 5:05 ` Svyatoslav Ryhel
@ 2025-09-02 6:35 ` Mikko Perttunen
0 siblings, 0 replies; 59+ messages in thread
From: Mikko Perttunen @ 2025-09-02 6:35 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Dmitry Osipenko,
Charan Pedumuru, linux-media, linux-tegra, dri-devel, devicetree,
linux-kernel, linux-clk, linux-staging
On Tuesday, September 2, 2025 2:05 PM Svyatoslav Ryhel wrote:
> вт, 2 вер. 2025 р. о 03:47 Mikko Perttunen <mperttunen@nvidia.com> пише:
> >
> > On Tuesday, August 19, 2025 9:16 PM Svyatoslav Ryhel wrote:
> > > Dedicated MIPI calibration block appears only in Tegra114, before Tegra114
> > > all MIPI calibration pads were part of VI block.
> > >
> > > Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> > > ---
> > > drivers/staging/media/tegra-video/csi.c | 12 +++++++-----
> > > drivers/staging/media/tegra-video/csi.h | 1 +
> > > drivers/staging/media/tegra-video/tegra210.c | 1 +
> > > 3 files changed, 9 insertions(+), 5 deletions(-)
> > >
> > > diff --git a/drivers/staging/media/tegra-video/csi.c
> > > b/drivers/staging/media/tegra-video/csi.c index 74c92db1032f..2f9907a20db1
> > > 100644
> > > --- a/drivers/staging/media/tegra-video/csi.c
> > > +++ b/drivers/staging/media/tegra-video/csi.c
> > > @@ -485,11 +485,13 @@ static int tegra_csi_channel_alloc(struct tegra_csi
> > > *csi, if (IS_ENABLED(CONFIG_VIDEO_TEGRA_TPG))
> > > return 0;
> > >
> > > - chan->mipi = tegra_mipi_request(csi->dev, node);
> > > - if (IS_ERR(chan->mipi)) {
> > > - ret = PTR_ERR(chan->mipi);
> > > - chan->mipi = NULL;
> > > - dev_err(csi->dev, "failed to get mipi device: %d\n", ret);
> > > + if (csi->soc->has_mipi_calibration) {
> > > + chan->mipi = tegra_mipi_request(csi->dev, node);
> >
> > The way I would read 'soc->has_mipi_calibration' is that this device (CSI)
> > contains the MIPI calibration hardware. I.e. the opposite of here. I would
> > invert the logic and optionally call it e.g. 'internal_mipi_calib'.
> >
> > A cleaner way to do this might be to always call tegra_mipi_request et al. --
> > on pre-Tegra114 SoCs this would just call back to the VI/CSI driver using the
> > callbacks registered in the MIPI driver as we discussed before. That way the
> > CSI driver won't need separate code paths for SoCs with internal MIPI
> > calibration and SoCs with the external MIPI calibration device.
> >
>
> So basically MIPI calibration device for Tegra20/Tegra30 has to be
> created within CSI and when MIPI calibration is requested, CSI phandle
> is used. Question: may I use a dedicated node for MIPI calibration
> within CSI or it has to use CSI node itself? With dedicated node
> configuration should be much simpler and can help avoiding probe of
> entire.
I think it'd better to use the CSI node itself. The calibration registers are somewhat scattered in the address space so it's hard to argue for the MIPI calibration to be a subdevice of CSI.
If it's problematic, we can also just call the calibration logic internally within the driver. But in that case also I'd place both the DSI and CSI calibration logic together in one place since AIUI they can interact with each other.
>
> > Cheers,
> > Mikko
> >
> > > + if (IS_ERR(chan->mipi)) {
> > > + ret = PTR_ERR(chan->mipi);
> > > + chan->mipi = NULL;
> > > + dev_err(csi->dev, "failed to get mipi device:
> > %d\n", ret);
> > > + }
> > > }
> > >
> > > return ret;
> > > diff --git a/drivers/staging/media/tegra-video/csi.h
> > > b/drivers/staging/media/tegra-video/csi.h index 3ed2dbc73ce9..400b913bb1cb
> > > 100644
> > > --- a/drivers/staging/media/tegra-video/csi.h
> > > +++ b/drivers/staging/media/tegra-video/csi.h
> > > @@ -128,6 +128,7 @@ struct tegra_csi_soc {
> > > unsigned int num_clks;
> > > const struct tpg_framerate *tpg_frmrate_table;
> > > unsigned int tpg_frmrate_table_size;
> > > + bool has_mipi_calibration;
> > > };
> > >
> > > /**
> > > diff --git a/drivers/staging/media/tegra-video/tegra210.c
> > > b/drivers/staging/media/tegra-video/tegra210.c index
> > > da99f19a39e7..305472e94af4 100644
> > > --- a/drivers/staging/media/tegra-video/tegra210.c
> > > +++ b/drivers/staging/media/tegra-video/tegra210.c
> > > @@ -1218,4 +1218,5 @@ const struct tegra_csi_soc tegra210_csi_soc = {
> > > .num_clks = ARRAY_SIZE(tegra210_csi_cil_clks),
> > > .tpg_frmrate_table = tegra210_tpg_frmrate_table,
> > > .tpg_frmrate_table_size = ARRAY_SIZE(tegra210_tpg_frmrate_table),
> > > + .has_mipi_calibration = true,
> > > };
> >
> >
> >
> >
^ permalink raw reply [flat|nested] 59+ messages in thread
* Re: [PATCH v1 19/19] staging: media: tegra-video: add CSI support for Tegra20 and Tegra30
2025-09-02 2:38 ` Mikko Perttunen
2025-09-02 5:51 ` Svyatoslav Ryhel
@ 2025-09-02 7:11 ` Dan Carpenter
1 sibling, 0 replies; 59+ messages in thread
From: Dan Carpenter @ 2025-09-02 7:11 UTC (permalink / raw)
To: Mikko Perttunen, Uwe Kleine-König
Cc: Thierry Reding, Thierry Reding, Jonathan Hunter,
Sowjanya Komatineni, Luca Ceresoli, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Peter De Schrijver,
Prashant Gaikwad, Michael Turquette, Stephen Boyd,
Mauro Carvalho Chehab, Greg Kroah-Hartman, Svyatoslav Ryhel,
Dmitry Osipenko, Charan Pedumuru, linux-media, linux-tegra,
dri-devel, devicetree, linux-kernel, linux-clk, linux-staging
On Tue, Sep 02, 2025 at 11:38:18AM +0900, Mikko Perttunen wrote:
> > @@ -282,20 +411,27 @@ static int tegra20_vi_enable(struct tegra_vi *vi, bool on)
> > static int tegra20_channel_host1x_syncpt_init(struct tegra_vi_channel *chan)
> > {
> > struct tegra_vi *vi = chan->vi;
> > - struct host1x_syncpt *out_sp;
> > + struct host1x_syncpt *out_sp, *fs_sp;
> >
> > out_sp = host1x_syncpt_request(&vi->client, HOST1X_SYNCPT_CLIENT_MANAGED);
> > if (!out_sp)
> > - return dev_err_probe(vi->dev, -ENOMEM, "failed to request syncpoint\n");
> > + return dev_err_probe(vi->dev, -ENOMEM, "failed to request mw ack syncpoint\n");
>
> Existing issue, but dev_err_probe doesn't print anything when the error is
> -ENOMEM, since "there is already enough output". But that's not necessarily
> the case with failing syncpoint allocation. Maybe we should be using a
> different error code like EBUSY?
>
I'm not sure I love the rule that -ENOMEM doesn't print a message.
Deleting error messages is fine because it makes the code simpler and
saves a little memory. But with dev_err_probe() the message is still
there in the memory, we just don't print it. Printing the error message
doesn't hurt anything.
But if we go down that road, we should make it make it a checkpatch
warning to pass a hard coded -ENOMEM to dev_err_probe().
regards,
dan carpenter
^ permalink raw reply [flat|nested] 59+ messages in thread
end of thread, other threads:[~2025-09-02 7:12 UTC | newest]
Thread overview: 59+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-19 12:16 [PATCH v1 00/19] tegra-video: add CSI support for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 01/19] clk: tegra: init CSUS clock " Svyatoslav Ryhel
2025-08-27 4:09 ` Mikko Perttunen
2025-08-27 4:32 ` Svyatoslav
2025-08-27 10:36 ` Mikko Perttunen
2025-08-27 10:45 ` Svyatoslav Ryhel
2025-08-28 8:13 ` Mikko Perttunen
2025-08-28 8:28 ` Svyatoslav Ryhel
2025-08-28 10:15 ` Mikko Perttunen
2025-08-28 10:23 ` Svyatoslav Ryhel
2025-08-29 0:29 ` Mikko Perttunen
2025-08-29 7:05 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 02/19] dt-bindings: clock: tegra20: Add IDs for CSI PAD clocks Svyatoslav Ryhel
2025-08-22 13:59 ` Rob Herring
2025-08-27 4:19 ` Mikko Perttunen
2025-08-27 4:28 ` Svyatoslav
2025-08-27 10:27 ` Mikko Perttunen
2025-08-29 6:54 ` Krzysztof Kozlowski
2025-08-19 12:16 ` [PATCH v1 03/19] clk: tegra30: add CSI PAD clock gates Svyatoslav Ryhel
2025-08-27 4:26 ` Mikko Perttunen
2025-08-29 0:44 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 04/19] dt-bindings: display: tegra: document Tegra30 VIP Svyatoslav Ryhel
2025-08-19 20:27 ` Rob Herring
2025-08-20 5:36 ` Svyatoslav Ryhel
2025-08-29 6:42 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 05/19] staging: media: tegra-video: expand VI and VIP support to Tegra30 Svyatoslav Ryhel
2025-08-27 4:29 ` Mikko Perttunen
2025-08-27 4:47 ` Svyatoslav
2025-08-29 0:56 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 06/19] staging: media: tegra-video: csi: move CSI helpers to header Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 07/19] staging: media: tegra-video: csi: parametrize MIPI calibration device presence Svyatoslav Ryhel
2025-09-02 0:46 ` Mikko Perttunen
2025-09-02 5:05 ` Svyatoslav Ryhel
2025-09-02 6:35 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 08/19] staging: media: tegra-video: vi: adjust get_selection op check Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 09/19] staging: media: tegra-video: vi: add flip controls only if no source controls are provided Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 10/19] staging: media: tegra-video: tegra20: set correct maximum width and height Svyatoslav Ryhel
2025-09-02 0:51 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 11/19] staging: media: tegra-video: tegra20: add support for second output of VI Svyatoslav Ryhel
2025-09-02 1:00 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 12/19] staging: media: tegra-video: tegra20: simplify format align calculations Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 13/19] staging: media: tegra-video: tegra20: set VI HW revision Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 14/19] staging: media: tegra-video: tegra20: increase maximum VI clock frequency Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 15/19] staging: media: tegra-video: tegra20: expand format support with RAW8/10 and YUV422 1X16 Svyatoslav Ryhel
2025-09-02 1:09 ` Mikko Perttunen
2025-09-02 5:11 ` Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 16/19] staging: media: tegra-video: tegra20: adjust luma buffer stride Svyatoslav Ryhel
2025-09-02 1:16 ` Mikko Perttunen
2025-08-19 12:16 ` [PATCH v1 17/19] dt-bindings: display: tegra: document Tegra20 and Tegra30 CSI Svyatoslav Ryhel
2025-08-19 20:30 ` Rob Herring
2025-08-20 5:39 ` Svyatoslav Ryhel
2025-08-22 14:06 ` Rob Herring
2025-08-19 12:16 ` [PATCH v1 18/19] ARM: tegra: add CSI binding for Tegra20 and Tegra30 Svyatoslav Ryhel
2025-08-19 12:16 ` [PATCH v1 19/19] staging: media: tegra-video: add CSI support " Svyatoslav Ryhel
2025-09-02 2:38 ` Mikko Perttunen
2025-09-02 5:51 ` Svyatoslav Ryhel
2025-09-02 6:17 ` Mikko Perttunen
2025-09-02 6:21 ` Svyatoslav Ryhel
2025-09-02 7:11 ` Dan Carpenter
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).