* [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface
@ 2026-10-04 16:31 Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 1/7] drm/tegra: dc: Expand available registers layouts Svyatoslav Ryhel
` (6 more replies)
0 siblings, 7 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
The display controller in Tegra20/30 SoCs features an 8-bit SPI interface
that closely resembles the MIPI DBI Type B protocol and is referred to as
'8-bit CPU'.
Add DC parametrization options needed for fine tuning by bridges.
Add 8-bit CPU interface in form of a bridge linking to RGB port.
Add 2 DBI Type B panels used in LG Optimus 2X which work with
the 8-bit CPU interface.
---
Changes in v2:
- convert enums in the dc header into definitions list
- add check in RGB if bridge_state is not NULL, if yes, use default flags
- inverted FLAG_PIXDATA_SAMPLE flag setup logic since default value is set to
be on NEGEDGE while v1 set default to be on POSEDGE
- 8bit-cpu schema renamed to dbi, removed compaible and set as DC child
- expanded list of required properties
- 8bit-cpu bridge remodelled into dbi interface as DC child
- improve gpio handling
- rework attach to get drvdata from parent
- add panel supplies description
- split panel driver into per-panel drivers
- get DBI interface from the patent directly
I have deliberately left GPIO parsing from device tree since it seems to
be the most convenient and mainstream method of working with GPIOs.
---
Svyatoslav Ryhel (7):
drm/tegra: dc: Expand available registers layouts
drm/tegra: rgb: Parameterize configuration based on bus flags
dt-bindings: display: tegra: Document 8-bit CPU parallel interface
drm/tegra: Add support for 8-bit CPU interface
dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG
LH400WV3 panels
drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver
drm/panel: Add LG LH400WV3-SD04 MIPI DBI Type B panel driver
.../display/panel/hit,tx10d07vm0baa.yaml | 58 +++
.../display/tegra/nvidia,tegra-dbi.yaml | 143 ++++++
.../display/tegra/nvidia,tegra20-dc.yaml | 3 +
drivers/gpu/drm/panel/Kconfig | 27 ++
drivers/gpu/drm/panel/Makefile | 2 +
.../drm/panel/panel-hitachi-tx10d07vm0baa.c | 297 +++++++++++++
drivers/gpu/drm/panel/panel-lg-lh400wv3.c | 236 ++++++++++
drivers/gpu/drm/tegra/Kconfig | 7 +
drivers/gpu/drm/tegra/Makefile | 1 +
drivers/gpu/drm/tegra/dbi.c | 416 ++++++++++++++++++
drivers/gpu/drm/tegra/dc.c | 24 +-
drivers/gpu/drm/tegra/dc.h | 50 ++-
drivers/gpu/drm/tegra/rgb.c | 41 +-
13 files changed, 1293 insertions(+), 12 deletions(-)
create mode 100644 Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml
create mode 100644 drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
create mode 100644 drivers/gpu/drm/panel/panel-lg-lh400wv3.c
create mode 100644 drivers/gpu/drm/tegra/dbi.c
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 1/7] drm/tegra: dc: Expand available registers layouts
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 2/7] drm/tegra: rgb: Parameterize configuration based on bus flags Svyatoslav Ryhel
` (5 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Expand existing DC register definitions with additional fields in
preparation for adding the 8-bit CPU interface.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/dc.c | 3 ++-
drivers/gpu/drm/tegra/dc.h | 49 +++++++++++++++++++++++++++++++++-----
2 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index b0bfa946e6979..5c67928bcabfa 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -2384,7 +2384,8 @@ static void tegra_crtc_atomic_enable(struct drm_crtc *crtc,
if (dc->rgb) {
/* XXX: parameterize? */
- value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
+ value = SC0_H_QUALIFIER(SC_H_QUALIFIER_NONE) |
+ SC1_H_QUALIFIER(SC_H_QUALIFIER_NONE);
tegra_dc_writel(dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
}
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 0cb0515968b35..7005df32f485f 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -274,8 +274,11 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_COM_CRC_CHECKSUM 0x301
#define DC_COM_PIN_OUTPUT_ENABLE(x) (0x302 + (x))
#define DC_COM_PIN_OUTPUT_POLARITY(x) (0x306 + (x))
+#define LSC0_OUTPUT_POLARITY_LOW BIT(24)
#define LVS_OUTPUT_POLARITY_LOW (1 << 28)
#define LHS_OUTPUT_POLARITY_LOW (1 << 30)
+#define LSPI_OUTPUT_POLARITY_LOW BIT(8)
+#define LDC_OUTPUT_SELECT_V_PULSE1 BIT(14)
#define DC_COM_PIN_OUTPUT_DATA(x) (0x30a + (x))
#define DC_COM_PIN_INPUT_ENABLE(x) (0x30e + (x))
#define DC_COM_PIN_INPUT_DATA(x) (0x312 + (x))
@@ -303,9 +306,15 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define UNDERFLOW_REPORT_ENABLE (1 << 0)
#define DC_DISP_DISP_SIGNAL_OPTIONS0 0x400
-#define H_PULSE0_ENABLE (1 << 8)
-#define H_PULSE1_ENABLE (1 << 10)
-#define H_PULSE2_ENABLE (1 << 12)
+#define H_PULSE0_ENABLE BIT(8)
+#define H_PULSE1_ENABLE BIT(10)
+#define H_PULSE2_ENABLE BIT(12)
+#define V_PULSE0_ENABLE BIT(16)
+#define V_PULSE1_ENABLE BIT(18)
+#define V_PULSE2_ENABLE BIT(19)
+#define V_PULSE3_ENABLE BIT(20)
+#define M0_ENABLE BIT(24)
+#define M1_ENABLE BIT(26)
#define DC_DISP_DISP_SIGNAL_OPTIONS1 0x401
@@ -451,12 +460,26 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define BASE_COLOR_SIZE_888 ( 8 << 0)
#define BASE_COLOR_SIZE_101010 ( 10 << 0)
#define BASE_COLOR_SIZE_121212 ( 12 << 0)
+#define DISP_COLOR_SWAP_BGR BIT(16)
#define CMU_ENABLE_ENABLE (1 << 20)
#define DC_DISP_SHIFT_CLOCK_OPTIONS 0x431
-#define SC1_H_QUALIFIER_NONE (1 << 16)
-#define SC0_H_QUALIFIER_NONE (1 << 0)
-
+#define SC0_H_QUALIFIER(x) (((x) & 0x7) << 0)
+#define SC1_H_QUALIFIER(x) (((x) & 0x7) << 16)
+#define SC_H_QUALIFIER_DISABLE 0
+#define SC_H_QUALIFIER_NONE 1
+#define SC_H_QUALIFIER_HACTIVE 2
+#define SC_H_QUALIFIER_EXT_HACTIVE 3
+#define SC_H_QUALIFIER_HPULSE 4
+#define SC_H_QUALIFIER_EXT_HPULSE 5
+#define SC0_V_QUALIFIER(x) (((x) & 0x7) << 3)
+#define SC1_V_QUALIFIER(x) (((x) & 0x7) << 19)
+#define SC_V_QUALIFIER_NONE 0
+#define SC_V_QUALIFIER_RSVD 1
+#define SC_V_QUALIFIER_VACTIVE 2
+#define SC_V_QUALIFIER_EXT_VACTIVE 3
+#define SC_V_QUALIFIER_VPULSE 4
+#define SC_V_QUALIFIER_EXT_VPULSE 5
#define DC_DISP_DATA_ENABLE_OPTIONS 0x432
#define DE_SELECT_ACTIVE_BLANK (0 << 0)
#define DE_SELECT_ACTIVE (1 << 0)
@@ -493,6 +516,20 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
#define DC_DISP_CURSOR_POSITION_NS 0x441
#define DC_DISP_INIT_SEQ_CONTROL 0x442
+#define SEND_INIT_SEQUENCE BIT(0)
+#define INIT_SEQUENCE_MODE_SPI BIT(1)
+#define INIT_SEQUENCE_MODE_PLCD 0x0
+#define INIT_SEQ_DC_SIGNAL_SHIFT 4
+#define INIT_SEQ_DC_SIGNAL_MASK (0x7 << INIT_SEQ_DC_SIGNAL_SHIFT)
+#define NO_DC_SIGNAL 0
+#define DC_SIGNAL_VSYNC 1
+#define DC_SIGNAL_VPULSE0 2
+#define DC_SIGNAL_VPULSE1 3
+#define DC_SIGNAL_VPULSE2 4
+#define DC_SIGNAL_VPULSE3 5
+#define INIT_SEQ_DC_CONTROL_SHIFT 7
+#define FRAME_INIT_SEQ_CYCLES_SHIFT 8
+
#define DC_DISP_SPI_INIT_SEQ_DATA_A 0x443
#define DC_DISP_SPI_INIT_SEQ_DATA_B 0x444
#define DC_DISP_SPI_INIT_SEQ_DATA_C 0x445
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 2/7] drm/tegra: rgb: Parameterize configuration based on bus flags
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 1/7] drm/tegra: dc: Expand available registers layouts Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
` (4 subsequent siblings)
6 siblings, 0 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Parameterize configuration based on bus flags passed from the bridge or
panel. The list of supported flags includes now pixel clock polarity,
display enable (DE) polarity, and data alignment.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/rgb.c | 41 ++++++++++++++++++++++++++++++++-----
1 file changed, 36 insertions(+), 5 deletions(-)
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index bc1c93c7554c5..8167447cec900 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -5,6 +5,7 @@
*/
#include <linux/clk.h>
+#include <linux/media-bus-format.h>
#include <linux/of.h>
#include <drm/drm_atomic_helper.h>
@@ -103,14 +104,24 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
struct drm_display_mode *mode = &encoder->crtc->state->adjusted_mode;
struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
- u32 value;
+ struct drm_bridge_state *bridge_state;
+ u32 bus_flags, value;
+
+ /* Get but flags from the bridge state. */
+ bridge_state = drm_bridge_get_current_state(output->bridge);
+ if (bridge_state)
+ bus_flags = bridge_state->input_bus_cfg.flags;
+ else
+ bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_MSB_TO_LSB;
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
- /* configure H- and V-sync signal polarities */
+ /* configure H- and V-sync and pixel clock signal polarities */
value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
if (mode->flags & DRM_MODE_FLAG_NHSYNC)
@@ -123,11 +134,31 @@ static void tegra_rgb_encoder_enable(struct drm_encoder *encoder)
else
value &= ~LVS_OUTPUT_POLARITY_LOW;
+ if (bus_flags & DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE)
+ value &= ~LSC0_OUTPUT_POLARITY_LOW;
+ else
+ value |= LSC0_OUTPUT_POLARITY_LOW;
+
tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
- /* XXX: parameterize? */
- value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB |
- DISP_ORDER_RED_BLUE;
+ /* configure DE signal polarities */
+ value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(3));
+
+ if (bus_flags & DRM_BUS_FLAG_DE_LOW)
+ value |= LSPI_OUTPUT_POLARITY_LOW;
+ else
+ value &= ~LSPI_OUTPUT_POLARITY_LOW;
+
+ tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(3));
+
+ /* configure DATA order and alignment */
+ value = DISP_DATA_FORMAT_DF1P1C | DISP_ORDER_RED_BLUE;
+
+ if (bus_flags & DRM_BUS_FLAG_DATA_LSB_TO_MSB)
+ value |= DISP_ALIGNMENT_LSB;
+ else
+ value &= ~DISP_ALIGNMENT_LSB;
+
tegra_dc_writel(rgb->dc, value, DC_DISP_DISP_INTERFACE_CONTROL);
tegra_dc_commit(rgb->dc);
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 1/7] drm/tegra: dc: Expand available registers layouts Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 2/7] drm/tegra: rgb: Parameterize configuration based on bus flags Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-05 13:30 ` Rob Herring (Arm)
2026-10-04 16:31 ` [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
` (3 subsequent siblings)
6 siblings, 1 reply; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Document 8-bit CPU parallel MIPI DBI Type B interface provided by
Tegra20/30 SoCs display controller.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../display/tegra/nvidia,tegra-dbi.yaml | 143 ++++++++++++++++++
.../display/tegra/nvidia,tegra20-dc.yaml | 3 +
2 files changed, 146 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml
new file mode 100644
index 0000000000000..184c33d436308
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml
@@ -0,0 +1,143 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/tegra/nvidia,tegra-dbi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Nvidia Tegra DC based MIPI DBI Type B interface
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+description: The display controller in Tegra20/30 SoCs features an
+ 8-bit SPI interface that closely resembles the MIPI DBI Type B
+ protocol and is referred to as '8-bit CPU'. Each display controller
+ provides two such interfaces, which can be used to send MIPI DCS
+ commands to initialize and control the panel while image data is
+ transmitted via 16/18/24-line RGB.
+
+properties:
+ dc-gpios:
+ description: Data/command selection pin.
+ maxItems: 1
+
+ rw-gpios:
+ description: Read/write pin.
+ maxItems: 1
+
+ cs-gpios:
+ description: Chip select pin.
+ maxItems: 1
+
+ data-gpios:
+ description: Specifies a set of 8 gpio pins used to transfer data.
+ minItems: 8
+ maxItems: 8
+
+ nvidia,init-sequence:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ description:
+ Device specific set of values used in DC DISP_SPI_INIT_SEQ registers.
+ minItems: 4
+ maxItems: 4
+
+ panel:
+ type: object
+ description: Node of supported panel driven by the bridge.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Video port for RGB input.
+
+ properties:
+ endpoint:
+ $ref: /schemas/graph.yaml#/$defs/endpoint-base
+ unevaluatedProperties: false
+
+ properties:
+ bus-width:
+ enum: [ 16, 18, 24 ]
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Video port for DBI output (panel or connector).
+
+ required:
+ - port@0
+ - port@1
+
+required:
+ - compatible
+ - dc-gpios
+ - rw-gpios
+ - cs-gpios
+ - data-gpios
+ - panel
+ - ports
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ dc@54200000 {
+ reg = <0x54200000 0x00040000>;
+
+ dbi {
+ dc-gpios = <&gpio 110 GPIO_ACTIVE_HIGH>;
+ rw-gpios = <&gpio 11 GPIO_ACTIVE_HIGH>;
+ cs-gpios = <&gpio 108 GPIO_ACTIVE_HIGH>;
+
+ data-gpios = <&gpio 32 GPIO_ACTIVE_HIGH>, <&gpio 33 GPIO_ACTIVE_HIGH>,
+ <&gpio 34 GPIO_ACTIVE_HIGH>, <&gpio 35 GPIO_ACTIVE_HIGH>,
+ <&gpio 36 GPIO_ACTIVE_HIGH>, <&gpio 37 GPIO_ACTIVE_HIGH>,
+ <&gpio 38 GPIO_ACTIVE_HIGH>, <&gpio 39 GPIO_ACTIVE_HIGH>;
+
+ nvidia,init-sequence = <0x0000002c 0x0 0x0 0x00005000>;
+
+ panel {
+ compatible = "hit,tx10d07vm0baa";
+
+ reset-gpios = <&gpio 175 GPIO_ACTIVE_LOW>;
+
+ avci-supply = <&vcc_2v8_lcd>;
+ iovcc-supply = <&iovcc_1v8_lcd>;
+
+ backlight = <&backlight>;
+
+ port {
+ panel_input: endpoint {
+ remote-endpoint = <&bridge_output>;
+ };
+ };
+ };
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ bridge_input: endpoint {
+ remote-endpoint = <&dpi_output>;
+ bus-width = <24>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ bridge_output: endpoint {
+ remote-endpoint = <&panel_input>;
+ };
+ };
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
index 69be95afd5627..bb280f8dbfc7c 100644
--- a/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
+++ b/Documentation/devicetree/bindings/display/tegra/nvidia,tegra20-dc.yaml
@@ -76,6 +76,9 @@ properties:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: A list of phandles of outputs that this display controller can drive.
+ dbi:
+ $ref: /schemas/display/tegra/nvidia,tegra-dbi.yaml#
+
rgb:
type: object
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (2 preceding siblings ...)
2026-10-04 16:31 ` [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-05 14:29 ` kernel test robot
2026-10-06 3:42 ` kernel test robot
2026-10-04 16:31 ` [PATCH v2 5/7] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels Svyatoslav Ryhel
` (2 subsequent siblings)
6 siblings, 2 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
The display controller in Tegra20/30 SoCs features an 8-bit SPI interface
that closely resembles the MIPI DBI Type B protocol and is referred to as
'8-bit CPU'. Each display controller provides two such interfaces, which
can be used to send MIPI DCS commands to initialize and control the panel
while image data is transmitted via 16/18/24-line RGB.
The '8-bit CPU', although being the DC interface, is modeled using a
bridge framework for flexibility and convenience. This implementation does
not change the existing codebase besides registering a fragment and can be
enabled/disabled without losing other Tegra DRM functionality.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/tegra/Kconfig | 7 +
drivers/gpu/drm/tegra/Makefile | 1 +
drivers/gpu/drm/tegra/dbi.c | 416 +++++++++++++++++++++++++++++++++
drivers/gpu/drm/tegra/dc.c | 21 ++
drivers/gpu/drm/tegra/dc.h | 1 +
5 files changed, 446 insertions(+)
create mode 100644 drivers/gpu/drm/tegra/dbi.c
diff --git a/drivers/gpu/drm/tegra/Kconfig b/drivers/gpu/drm/tegra/Kconfig
index 8a3b16aac5d68..3258e077d6666 100644
--- a/drivers/gpu/drm/tegra/Kconfig
+++ b/drivers/gpu/drm/tegra/Kconfig
@@ -30,6 +30,13 @@ config DRM_TEGRA
if DRM_TEGRA
+config DRM_TEGRA_DBI
+ bool "Enable MIPI DBI type B communication protocol for Tegra 20/30"
+ help
+ Tegra20 and Tegra30 feature 8 bit CPU driver panel control
+ protocol (similar to MIPI DBI Type B). This option allows use
+ it to set up and control compatible panel.
+
config DRM_TEGRA_DEBUG
bool "NVIDIA Tegra DRM debug support"
help
diff --git a/drivers/gpu/drm/tegra/Makefile b/drivers/gpu/drm/tegra/Makefile
index e399b40d64a1d..4850aa1c56ba3 100644
--- a/drivers/gpu/drm/tegra/Makefile
+++ b/drivers/gpu/drm/tegra/Makefile
@@ -31,5 +31,6 @@ tegra-drm-y := \
tegra-drm-y += trace.o
tegra-drm-$(CONFIG_DRM_FBDEV_EMULATION) += fbdev.o
+tegra-drm-$(CONFIG_DRM_TEGRA_DBI) += dbi.o
obj-$(CONFIG_DRM_TEGRA) += tegra-drm.o
diff --git a/drivers/gpu/drm/tegra/dbi.c b/drivers/gpu/drm/tegra/dbi.c
new file mode 100644
index 0000000000000..74a1051b86778
--- /dev/null
+++ b/drivers/gpu/drm/tegra/dbi.c
@@ -0,0 +1,416 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/kernel.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/property.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+#include "dc.h"
+
+#define TEGRA_DBI_COMMAND 0
+#define TEGRA_DBI_DATA 1
+#define TEGRA_DBI_DATA_PINS_MAX 8
+
+struct tegra_dbi_output {
+ struct drm_panel *panel;
+ struct drm_bridge *bridge;
+};
+
+struct tegra_dbi_priv {
+ struct mipi_dbi dbi; /* must be first */
+ struct device *dev;
+ struct tegra_dc *dc;
+
+ struct gpio_desc *dc_gpio;
+ struct gpio_desc *rw_gpio;
+ struct gpio_desc *cs_gpio;
+ struct gpio_descs *data_gpios;
+
+ struct drm_bridge bridge;
+ struct tegra_dbi_output output;
+
+ u32 spi_init_seq[4];
+ u32 bus_width;
+ u32 idx;
+ bool prepared;
+};
+
+static inline struct tegra_dbi_priv *mipi_dbi_to_tegra_dbi(struct mipi_dbi *dbi)
+{
+ return container_of(dbi, struct tegra_dbi_priv, dbi);
+}
+
+static inline struct tegra_dbi_priv *bridge_to_tegra_dbi(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct tegra_dbi_priv, bridge);
+}
+
+static void tegra_dbi_write(struct tegra_dbi_priv *priv, u8 type, u8 value)
+{
+ DECLARE_BITMAP(value_bitmap, 8);
+
+ value_bitmap[0] = value;
+
+ gpiod_set_value(priv->dc_gpio, type);
+
+ gpiod_set_value(priv->cs_gpio, 0);
+ gpiod_set_value(priv->rw_gpio, 0);
+
+ gpiod_set_array_value(priv->data_gpios->ndescs, priv->data_gpios->desc,
+ priv->data_gpios->info, value_bitmap);
+
+ gpiod_set_value(priv->cs_gpio, 1);
+ gpiod_set_value(priv->rw_gpio, 1);
+
+ udelay(10);
+}
+
+static int tegra_dbi_dbi_command(struct mipi_dbi *dbi, u8 *cmd, u8 *param, size_t num)
+{
+ struct tegra_dbi_priv *priv = mipi_dbi_to_tegra_dbi(dbi);
+ u8 command = *cmd;
+
+ if (!priv->data_gpios)
+ return 0;
+
+ tegra_dbi_write(priv, TEGRA_DBI_COMMAND, command);
+
+ for (int i = 0; i < num; i++)
+ tegra_dbi_write(priv, TEGRA_DBI_DATA, param[i]);
+
+ return 0;
+}
+
+static int tegra_dbi_prepare_gpios(struct tegra_dbi_priv *priv)
+{
+ struct device *dev = priv->dev;
+ int ret;
+
+ if (priv->prepared)
+ return 0;
+
+ /*
+ * Control and data GPIOs are shared between SPI and DPI. The bridge
+ * driver must get and put the required GPIOs each time DCS commands
+ * are transmitted.
+ */
+
+ priv->cs_gpio = gpiod_get(dev, "cs", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->cs_gpio)) {
+ dev_err(dev, "Failed to get CS GPIO: %ld\n", PTR_ERR(priv->cs_gpio));
+ return PTR_ERR(priv->cs_gpio);
+ }
+
+ priv->rw_gpio = gpiod_get(dev, "rw", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->rw_gpio)) {
+ ret = PTR_ERR(priv->rw_gpio);
+ dev_err(dev, "Failed to get RW GPIO: %d\n", ret);
+ goto free_cs;
+ }
+
+ priv->dc_gpio = gpiod_get(dev, "dc", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->dc_gpio)) {
+ ret = PTR_ERR(priv->dc_gpio);
+ dev_err(dev, "Failed to get DC GPIO: %d\n", ret);
+ goto free_rw;
+ }
+
+ priv->data_gpios = gpiod_get_array(dev, "data", GPIOD_OUT_LOW);
+ if (IS_ERR(priv->data_gpios)) {
+ ret = PTR_ERR(priv->data_gpios);
+ dev_err(dev, "Failed to get data gpios %d\n", ret);
+ goto free_dc;
+ }
+
+ if (priv->data_gpios && priv->data_gpios->ndescs > TEGRA_DBI_DATA_PINS_MAX) {
+ ret = -EINVAL;
+ dev_err(dev, "Too many data gpios\n");
+ goto free_data;
+ }
+
+ priv->prepared = true;
+
+ return 0;
+
+free_data:
+ gpiod_put_array(priv->data_gpios);
+free_dc:
+ gpiod_put(priv->dc_gpio);
+free_rw:
+ gpiod_put(priv->rw_gpio);
+free_cs:
+ gpiod_put(priv->cs_gpio);
+
+ return ret;
+}
+
+static void tegra_dbi_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ struct tegra_dc *dc = priv->dc;
+ u32 value;
+ int ret;
+
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+ /* Disable all options except cursor if enabled */
+ value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ value &= CURSOR_ENABLE;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+ tegra_dc_commit(dc);
+
+ tegra_dc_writel(dc, V_PULSE1_ENABLE, DC_DISP_DISP_SIGNAL_OPTIONS0);
+ tegra_dc_writel(dc, PULSE_POLARITY_LOW, DC_DISP_V_PULSE1_CONTROL);
+
+ tegra_dc_writel(dc, PULSE_END(1), DC_DISP_V_PULSE0_POSITION_A);
+ tegra_dc_writel(dc, 0, DC_DISP_V_PULSE0_POSITION_B);
+ tegra_dc_writel(dc, 0, DC_DISP_V_PULSE0_POSITION_C);
+
+ value = 1 << FRAME_INIT_SEQ_CYCLES_SHIFT |
+ DC_SIGNAL_VPULSE1 << INIT_SEQ_DC_SIGNAL_SHIFT |
+ INIT_SEQUENCE_MODE_PLCD | SEND_INIT_SEQUENCE;
+ tegra_dc_writel(dc, value, DC_DISP_INIT_SEQ_CONTROL);
+
+ tegra_dc_writel(dc, priv->spi_init_seq[0], DC_DISP_SPI_INIT_SEQ_DATA_A);
+ tegra_dc_writel(dc, priv->spi_init_seq[1], DC_DISP_SPI_INIT_SEQ_DATA_B);
+ tegra_dc_writel(dc, priv->spi_init_seq[2], DC_DISP_SPI_INIT_SEQ_DATA_C);
+ tegra_dc_writel(dc, priv->spi_init_seq[3], DC_DISP_SPI_INIT_SEQ_DATA_D);
+
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ value |= DISP_CTRL_MODE_C_DISPLAY;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+ /* set LDC pin to V Pulse 1 */
+ value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_SELECT(6));
+ value |= LDC_OUTPUT_SELECT_V_PULSE1;
+ tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_SELECT(6));
+
+ value = SC1_H_QUALIFIER(SC_H_QUALIFIER_NONE) |
+ SC0_V_QUALIFIER(SC_V_QUALIFIER_VACTIVE) |
+ SC0_H_QUALIFIER(SC_H_QUALIFIER_HACTIVE);
+ tegra_dc_writel(dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
+
+ value = tegra_dc_readl(dc, DC_DISP_DISP_COLOR_CONTROL);
+ value &= ~BASE_COLOR_SIZE_MASK;
+
+ switch (priv->bus_width) {
+ case 16:
+ value |= BASE_COLOR_SIZE_565;
+ break;
+ case 18:
+ value |= BASE_COLOR_SIZE_666;
+ break;
+ case 24:
+ default:
+ value |= BASE_COLOR_SIZE_888;
+ break;
+ }
+
+ tegra_dc_writel(dc, value, DC_DISP_DISP_COLOR_CONTROL);
+
+ ret = tegra_dbi_prepare_gpios(priv);
+ if (ret)
+ return;
+
+ if (priv->output.panel)
+ drm_panel_enable(priv->output.panel);
+
+ gpiod_set_value(priv->cs_gpio, 0);
+
+ gpiod_put(priv->dc_gpio);
+ gpiod_put(priv->rw_gpio);
+ gpiod_put(priv->cs_gpio);
+
+ gpiod_put_array(priv->data_gpios);
+ priv->prepared = false;
+}
+
+static void tegra_dbi_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_commit *state)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ int ret;
+
+ ret = tegra_dbi_prepare_gpios(priv);
+ if (ret)
+ return;
+
+ if (priv->output.panel)
+ drm_panel_disable(priv->output.panel);
+
+ gpiod_set_value(priv->cs_gpio, 0);
+
+ gpiod_put(priv->dc_gpio);
+ gpiod_put(priv->rw_gpio);
+ gpiod_put(priv->cs_gpio);
+
+ gpiod_put_array(priv->data_gpios);
+ priv->prepared = false;
+}
+
+static int tegra_dbi_atomic_check(struct drm_bridge *bridge,
+ struct drm_bridge_state *bridge_state,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
+{
+ struct drm_display_mode *adjusted_mode = &crtc_state->adjusted_mode;
+
+ /* Set safe default bus flags if panel does not specify them */
+ if (!bridge_state->input_bus_cfg.flags)
+ bridge_state->input_bus_cfg.flags = bridge->timings->input_bus_flags;
+
+ /* Default to positive sync */
+ if (!(adjusted_mode->flags &
+ (DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
+ adjusted_mode->flags |= DRM_MODE_FLAG_PHSYNC;
+
+ if (!(adjusted_mode->flags &
+ (DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
+ adjusted_mode->flags |= DRM_MODE_FLAG_PVSYNC;
+
+ return 0;
+}
+
+static int tegra_dbi_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct tegra_dbi_priv *priv = bridge_to_tegra_dbi(bridge);
+ struct device *dev = priv->dev;
+
+ priv->dc = dev_get_drvdata(dev->parent);
+ if (!priv->dc)
+ return -ENODEV;
+
+ return drm_bridge_attach(bridge->encoder, priv->output.bridge, bridge,
+ flags);
+}
+
+static enum drm_mode_status tegra_dbi_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ if (mode->hdisplay > 800)
+ return MODE_H_ILLEGAL;
+
+ if (mode->vdisplay > 800)
+ return MODE_V_ILLEGAL;
+
+ return MODE_OK;
+}
+
+static const struct drm_bridge_funcs tegra_dbi_funcs = {
+ .attach = tegra_dbi_attach,
+ .mode_valid = tegra_dbi_mode_valid,
+
+ .atomic_enable = tegra_dbi_atomic_enable,
+ .atomic_disable = tegra_dbi_atomic_disable,
+ .atomic_check = tegra_dbi_atomic_check,
+
+ .atomic_create_state = drm_atomic_helper_bridge_create_state,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+};
+
+static const struct drm_bridge_timings default_tegra_dbi_timings = {
+ .input_bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH,
+};
+
+static int tegra_dbi_probe(struct platform_device *pdev)
+{
+ struct tegra_dbi_priv *priv;
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct drm_bridge *bridge;
+ struct drm_panel *panel;
+ struct device_node *ep;
+ int ret;
+
+ priv = devm_drm_bridge_alloc(dev, struct tegra_dbi_priv, bridge,
+ &tegra_dbi_funcs);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ priv->dev = dev;
+
+ ret = device_property_read_u32_array(dev, "nvidia,init-sequence",
+ priv->spi_init_seq, 4);
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to get init sequence\n");
+
+ ret = devm_of_platform_populate(dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to probe children\n");
+
+ /* Initialize MIPI DBI interface */
+ mutex_init(&priv->dbi.cmdlock);
+ priv->dbi.command = tegra_dbi_dbi_command;
+
+ ret = drm_of_find_panel_or_bridge(np, 1, 0, &panel, &bridge);
+ if (ret)
+ return ret;
+
+ if (panel) {
+ bridge = devm_drm_panel_bridge_add_typed(dev, panel,
+ DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(bridge))
+ return PTR_ERR(bridge);
+ }
+
+ priv->output.bridge = bridge;
+ priv->output.panel = panel;
+
+ /* get input ep (port0/endpoint0) */
+ ret = -EINVAL;
+ ep = of_graph_get_endpoint_by_regs(np, 0, 0);
+ if (ep) {
+ ret = of_property_read_u32(ep, "bus-width", &priv->bus_width);
+ of_node_put(ep);
+ }
+
+ if (ret)
+ priv->bus_width = 24;
+
+ priv->bridge.of_node = np;
+ priv->bridge.timings = &default_tegra_dbi_timings;
+
+ ret = devm_drm_bridge_add(dev, &priv->bridge);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add bridge\n");
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static struct platform_driver tegra_dbi_driver = {
+ .driver.name = "tegra-dbi",
+ .probe = tegra_dbi_probe,
+};
+module_platform_driver(tegra_dbi_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("Nvidia Tegra20/30 MIPI-DBI Type B driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 5c67928bcabfa..dae2b14f79e31 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -3282,6 +3282,7 @@ static int tegra_dc_init_opp_table(struct tegra_dc *dc)
static int tegra_dc_probe(struct platform_device *pdev)
{
u64 dma_mask = dma_get_mask(pdev->dev.parent);
+ struct device_node *dbi_np;
struct tegra_dc *dc;
int err;
@@ -3382,6 +3383,23 @@ static int tegra_dc_probe(struct platform_device *pdev)
}
}
+ dbi_np = of_get_available_child_by_name(pdev->dev.of_node, "dbi");
+ if (dbi_np) {
+ struct platform_device_info dbi_info = {
+ .parent = &pdev->dev,
+ .name = "tegra-dbi",
+ .id = PLATFORM_DEVID_AUTO,
+ .fwnode = of_fwnode_handle(dbi_np),
+ .of_node_reused = true,
+ };
+
+ dc->dbi = platform_device_register_full(&dbi_info);
+ of_node_put(dbi_np);
+ if (IS_ERR(dc->dbi))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dc->dbi),
+ "Failed to create DBI device\n");
+ }
+
err = tegra_dc_rgb_probe(dc);
if (err < 0 && err != -ENODEV)
return dev_err_probe(&pdev->dev, err,
@@ -3418,6 +3436,9 @@ static void tegra_dc_remove(struct platform_device *pdev)
tegra_dc_rgb_remove(dc);
+ if (dc->dbi)
+ platform_device_unregister(dc->dbi);
+
pm_runtime_disable(&pdev->dev);
}
diff --git a/drivers/gpu/drm/tegra/dc.h b/drivers/gpu/drm/tegra/dc.h
index 7005df32f485f..27dbee57f8f72 100644
--- a/drivers/gpu/drm/tegra/dc.h
+++ b/drivers/gpu/drm/tegra/dc.h
@@ -95,6 +95,7 @@ struct tegra_dc {
struct tegra_output *rgb;
struct tegra_pmc *pmc;
+ struct platform_device *dbi;
struct tegra_dc_stats stats;
struct list_head list;
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 5/7] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (3 preceding siblings ...)
2026-10-04 16:31 ` [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 6/7] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 7/7] drm/panel: Add LG LH400WV3-SD04 " Svyatoslav Ryhel
6 siblings, 0 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Document Hitachi TX10D07VM0BAA and LG LH400WV3 MIPI DBI 4" WVGA panels
found in LG Optimus 2X P990.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
.../display/panel/hit,tx10d07vm0baa.yaml | 58 +++++++++++++++++++
1 file changed, 58 insertions(+)
create mode 100644 Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
diff --git a/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml b/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
new file mode 100644
index 0000000000000..4642dc14c42eb
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/panel/hit,tx10d07vm0baa.yaml
@@ -0,0 +1,58 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/panel/hit,tx10d07vm0baa.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Hitachi/LG 4" WVGA TFT LCD panel
+
+maintainers:
+ - Svyatoslav Ryhel <clamor95@gmail.com>
+
+allOf:
+ - $ref: panel-common.yaml#
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - hit,tx10d07vm0baa
+ - lg,lh400wv3-sd04
+
+ avci-supply:
+ description: Panel power supply
+
+ iovcc-supply:
+ description: I/O voltage supply
+
+ reset-gpios: true
+
+ backlight: true
+ port: true
+
+required:
+ - compatible
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ panel {
+ compatible = "lg,lh400wv3-sd04";
+
+ reset-gpios = <&gpio 175 GPIO_ACTIVE_LOW>;
+
+ avci-supply = <&vcc_2v8_lcd>;
+ iovcc-supply = <&iovcc_1v8_lcd>;
+
+ backlight = <&backlight>;
+
+ port {
+ endpoint {
+ remote-endpoint = <&dbi_out>;
+ };
+ };
+ };
+...
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 6/7] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (4 preceding siblings ...)
2026-10-04 16:31 ` [PATCH v2 5/7] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 7/7] drm/panel: Add LG LH400WV3-SD04 " Svyatoslav Ryhel
6 siblings, 0 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Add a driver for panel used in LG Optimus 2X P990. Panel is 4" WVGA MIPI
DBI Type B linked to DRM encoder via RGB to DBI bridge.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/panel/Kconfig | 14 +
drivers/gpu/drm/panel/Makefile | 1 +
.../drm/panel/panel-hitachi-tx10d07vm0baa.c | 297 ++++++++++++++++++
3 files changed, 312 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 747f47347521a..f9e4441dad1c0 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -273,6 +273,20 @@ config DRM_PANEL_HIMAX_HX8394
If M is selected the module will be called panel-himax-hx8394.
+config DRM_PANEL_HITACHI_TX10D07VM0BAA
+ tristate "Hitachi TX10D07VM0BAA MIPI DBI Type B panel"
+ depends on OF
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_MIPI_DBI
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for the HITACHI
+ TX10D07VM0BAA MIPI DBI Type B panel found in the LG Optimus 2X
+ P990 smartphone.
+
+ To compile this driver as a module, choose M here: the module will
+ be called panel-hitachi-tx10d07vm0baa.
+
config DRM_PANEL_HYDIS_HV101HD1
tristate "Hydis HV101HD1 panel"
depends on OF
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index f2c9c80a218f0..414267a49d922 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112A) += panel-himax-hx83112a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83112B) += panel-himax-hx83112b.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX83121A) += panel-himax-hx83121a.o
obj-$(CONFIG_DRM_PANEL_HIMAX_HX8394) += panel-himax-hx8394.o
+obj-$(CONFIG_DRM_PANEL_HITACHI_TX10D07VM0BAA) += panel-hitachi-tx10d07vm0baa.o
obj-$(CONFIG_DRM_PANEL_HYDIS_HV101HD1) += panel-hydis-hv101hd1.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7807S) += panel-ilitek-ili7807s.o
obj-$(CONFIG_DRM_PANEL_ILITEK_ILI7836A) += panel-ilitek-ili7836a.o
diff --git a/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c b/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
new file mode 100644
index 0000000000000..c3434cb96c86c
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-hitachi-tx10d07vm0baa.c
@@ -0,0 +1,297 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+static const struct regulator_bulk_data hitachi_tx10d07vm0baa_supplies[] = {
+ { .supply = "avci" }, { .supply = "iovcc" },
+};
+
+struct hitachi_tx10d07vm0baa {
+ struct drm_panel panel;
+ struct mipi_dbi *dbi;
+
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct hitachi_tx10d07vm0baa *to_hitachi_tx10d07vm0baa(struct drm_panel *panel)
+{
+ return container_of(panel, struct hitachi_tx10d07vm0baa, panel);
+}
+
+#define panel_dbi_command(priv, cmd, seq...) \
+({ \
+ const u8 d[] = { seq }; \
+ struct drm_panel *panel = &(priv)->panel; \
+ struct device *dev = panel->dev; \
+ int ret; \
+ ret = mipi_dbi_command_stackbuf((priv)->dbi, cmd, d, ARRAY_SIZE(d)); \
+ if (ret) \
+ dev_err_ratelimited(dev, "error %d when sending command %#02x\n", ret, cmd); \
+ ret; \
+})
+
+static int hitachi_tx10d07vm0baa_prepare(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+ struct device *dev = panel->dev;
+ int ret;
+
+ priv->dbi = dev_get_drvdata(dev->parent);
+ if (!priv->dbi)
+ return -ENODEV;
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies), priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable power supplies: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int hitachi_tx10d07vm0baa_enable(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_PARTIAL_ROWS, 0x00, 0x00, 0x03, 0x1f);
+ panel_dbi_command(priv, MIPI_DCS_SET_SCROLL_AREA, 0x00, 0x00, 0x03, 0x20,
+ 0x00, 0x00);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_ADDRESS_MODE, 0x0a);
+ panel_dbi_command(priv, MIPI_DCS_SET_SCROLL_START, 0x00, 0x00);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_24BIT);
+ panel_dbi_command(priv, MIPI_DCS_SET_TEAR_SCANLINE, 0x00, 0x00);
+
+ panel_dbi_command(priv, 0x71, 0x00); /* Ex_Vsync_en */
+
+ panel_dbi_command(priv, 0xb2, 0x00); /* VCSEL */
+ panel_dbi_command(priv, 0xb4, 0xaa); /* setvgmpm */
+ panel_dbi_command(priv, 0xb5, 0x33); /* rbias1 */
+ panel_dbi_command(priv, 0xb6, 0x03); /* rbias2 */
+
+ panel_dbi_command(priv, 0xb7, 0x1a, 0x33, 0x03, 0x03,
+ 0x03, 0x00, 0x00, 0x01, 0x02, 0x00,
+ 0x00, 0x04, 0x00, 0x01, 0x01, 0x01); /* set_ddvdhp */
+ panel_dbi_command(priv, 0xb8, 0x1c, 0x53, 0x03, 0x03,
+ 0x00, 0x01, 0x02, 0x00, 0x00, 0x04,
+ 0x00, 0x01, 0x01); /* set_ddvdhm */
+
+ panel_dbi_command(priv, 0xb9, 0x0a, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x01); /* set_vgh */
+ panel_dbi_command(priv, 0xba, 0x0f, 0x01, 0x01, 0x00,
+ 0x00, 0x00, 0x02, 0x00, 0x02, 0x01); /* set_vgl */
+ panel_dbi_command(priv, 0xbb, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x02, 0x01); /* set_vcl */
+
+ panel_dbi_command(priv, 0xc1, 0x01); /* number of lines */
+ panel_dbi_command(priv, 0xc2, 0x08); /* number of fp lines */
+ panel_dbi_command(priv, 0xc3, 0x04); /* gateset(1) */
+ panel_dbi_command(priv, 0xc4, 0x4c); /* 1h period */
+ panel_dbi_command(priv, 0xc5, 0x03); /* source precharge */
+ panel_dbi_command(priv, 0xc6, 0xc4, 0x04); /* source precharge timing */
+ panel_dbi_command(priv, 0xc7, 0x00); /* source level */
+ panel_dbi_command(priv, 0xc8, 0x02); /* number of bp lines */
+ panel_dbi_command(priv, 0xc9, 0x10); /* gateset(2) */
+ panel_dbi_command(priv, 0xca, 0x04, 0x04); /* gateset(3) */
+ panel_dbi_command(priv, 0xcb, 0x03); /* gateset(4) */
+ panel_dbi_command(priv, 0xcc, 0x12); /* gateset(5) */
+ panel_dbi_command(priv, 0xcd, 0x12); /* gateset(6) */
+ panel_dbi_command(priv, 0xce, 0x30); /* gateset(7) */
+ panel_dbi_command(priv, 0xcf, 0x30); /* gateset(8) */
+ panel_dbi_command(priv, 0xd0, 0x40); /* gateset(9) */
+ panel_dbi_command(priv, 0xd1, 0x22); /* flhw */
+ panel_dbi_command(priv, 0xd2, 0x22); /* vckhw */
+ panel_dbi_command(priv, 0xd3, 0x04); /* flt */
+ panel_dbi_command(priv, 0xd4, 0x14); /* tctrl */
+ panel_dbi_command(priv, 0xd6, 0x02); /* dotinv */
+ panel_dbi_command(priv, 0xd7, 0x00); /* on/off sequence period */
+
+ panel_dbi_command(priv, 0xd8, 0x01, 0x05, 0x06, 0x0d,
+ 0x18, 0x09, 0x22, 0x23, 0x00); /* ponseqa */
+ panel_dbi_command(priv, 0xd9, 0x24, 0x01); /* ponseqb */
+ panel_dbi_command(priv, 0xde, 0x09, 0x0f, 0x21, 0x12,
+ 0x04); /* ponseqc */
+
+ panel_dbi_command(priv, 0xdf, 0x02, 0x06, 0x06, 0x06,
+ 0x06, 0x00); /* pofseqa */
+ panel_dbi_command(priv, 0xe0, 0x01); /* pofseqb */
+
+ panel_dbi_command(priv, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, 0xff);
+ panel_dbi_command(priv, MIPI_DCS_WRITE_CONTROL_DISPLAY, 0x40);
+
+ panel_dbi_command(priv, 0xe2, 0x00, 0x00); /* cabc pwm */
+ panel_dbi_command(priv, 0xe3, 0x03); /* cabc */
+ panel_dbi_command(priv, 0xe4, 0x66, 0x7b, 0x90, 0xa5,
+ 0xbb, 0xc7, 0xe1, 0xe5); /* cabc brightness */
+ panel_dbi_command(priv, 0xe5, 0xc5, 0xc5, 0xc9, 0xc9,
+ 0xd1, 0xe1, 0xf1, 0xfe); /* cabc brightness */
+ panel_dbi_command(priv, 0xe7, 0x2a); /* cabc */
+ panel_dbi_command(priv, 0xe8, 0x00); /* brt_rev */
+ panel_dbi_command(priv, 0xe9, 0x00); /* tefreq */
+
+ panel_dbi_command(priv, 0xea, 0x01); /* high speed ram */
+
+ panel_dbi_command(priv, 0xeb, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting r pos */
+ panel_dbi_command(priv, 0xec, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting r neg */
+ panel_dbi_command(priv, 0xed, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting g pos */
+ panel_dbi_command(priv, 0xee, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting g neg */
+ panel_dbi_command(priv, 0xef, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting b pos */
+ panel_dbi_command(priv, 0xf0, 0x00, 0x33, 0x0e, 0x15,
+ 0xb7, 0x78, 0x88, 0x0f); /* gamma setting b neg */
+
+ panel_dbi_command(priv, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(110);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_DISPLAY_ON);
+
+ return 0;
+}
+
+static int hitachi_tx10d07vm0baa_disable(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_DISPLAY_OFF);
+ msleep(35);
+
+ panel_dbi_command(priv, MIPI_DCS_ENTER_SLEEP_MODE);
+ msleep(50);
+
+ return 0;
+}
+
+static int hitachi_tx10d07vm0baa_unprepare(struct drm_panel *panel)
+{
+ struct hitachi_tx10d07vm0baa *priv = to_hitachi_tx10d07vm0baa(panel);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies), priv->supplies);
+
+ msleep(50);
+
+ return 0;
+}
+
+static const struct drm_display_mode hitachi_tx10d07vm0baa_mode = {
+ .clock = (480 + 10 + 10 + 10) * (800 + 4 + 4 + 4) * 60 / 1000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 10,
+ .hsync_end = 480 + 10 + 10,
+ .htotal = 480 + 10 + 10 + 10,
+ .vdisplay = 800,
+ .vsync_start = 800 + 4,
+ .vsync_end = 800 + 4 + 4,
+ .vtotal = 800 + 4 + 4 + 4,
+ .width_mm = 86,
+ .height_mm = 52,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int hitachi_tx10d07vm0baa_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+
+ connector->display_info.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_LSB_TO_MSB;
+
+ return drm_connector_helper_get_modes_fixed(connector, &hitachi_tx10d07vm0baa_mode);
+}
+
+static const struct drm_panel_funcs hitachi_tx10d07vm0baa_panel_funcs = {
+ .prepare = hitachi_tx10d07vm0baa_prepare,
+ .enable = hitachi_tx10d07vm0baa_enable,
+ .disable = hitachi_tx10d07vm0baa_disable,
+ .unprepare = hitachi_tx10d07vm0baa_unprepare,
+ .get_modes = hitachi_tx10d07vm0baa_get_modes,
+};
+
+static int hitachi_tx10d07vm0baa_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct hitachi_tx10d07vm0baa *priv;
+ int ret;
+
+ priv = devm_drm_panel_alloc(dev, struct hitachi_tx10d07vm0baa, panel,
+ &hitachi_tx10d07vm0baa_panel_funcs, DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(hitachi_tx10d07vm0baa_supplies),
+ hitachi_tx10d07vm0baa_supplies, &priv->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ret = drm_panel_of_backlight(&priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ ret = devm_drm_panel_add(dev, &priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add panel\n");
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static const struct of_device_id hitachi_tx10d07vm0baa_of_match[] = {
+ { .compatible = "hit,tx10d07vm0baa" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, hitachi_tx10d07vm0baa_of_match);
+
+static struct platform_driver hitachi_tx10d07vm0baa_driver = {
+ .driver = {
+ .name = "panel-hitachi-tx10d07vm0baa",
+ .of_match_table = hitachi_tx10d07vm0baa_of_match,
+ },
+ .probe = hitachi_tx10d07vm0baa_probe,
+};
+module_platform_driver(hitachi_tx10d07vm0baa_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("HITACHI TX10D07VM0BAA MIPI DBI Type B panel driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* [PATCH v2 7/7] drm/panel: Add LG LH400WV3-SD04 MIPI DBI Type B panel driver
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
` (5 preceding siblings ...)
2026-10-04 16:31 ` [PATCH v2 6/7] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver Svyatoslav Ryhel
@ 2026-10-04 16:31 ` Svyatoslav Ryhel
6 siblings, 0 replies; 11+ messages in thread
From: Svyatoslav Ryhel @ 2026-10-04 16:31 UTC (permalink / raw)
To: Neil Armstrong, Jessica Zhang, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, David Airlie, Simona Vetter, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Thierry Reding,
Jonathan Hunter, Mikko Perttunen, Svyatoslav Ryhel
Cc: dri-devel, devicetree, linux-kernel, linux-tegra
Add a driver for panel used in LG Optimus 2X P990. Panel is 4" WVGA MIPI
DBI Type B linked to DRM encoder via RGB to DBI bridge.
Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
---
drivers/gpu/drm/panel/Kconfig | 13 ++
drivers/gpu/drm/panel/Makefile | 1 +
drivers/gpu/drm/panel/panel-lg-lh400wv3.c | 236 ++++++++++++++++++++++
3 files changed, 250 insertions(+)
create mode 100644 drivers/gpu/drm/panel/panel-lg-lh400wv3.c
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index f9e4441dad1c0..0d3845c9bd477 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -553,6 +553,19 @@ config DRM_PANEL_LG_LG4573
Say Y here if you want to enable support for LG4573 RGB panel.
To compile this driver as a module, choose M here.
+config DRM_PANEL_LG_LH400WV3
+ tristate "LG LH400WV3 MIPI DBI Type B panel"
+ depends on OF
+ depends on BACKLIGHT_CLASS_DEVICE
+ select DRM_MIPI_DBI
+ select VIDEOMODE_HELPERS
+ help
+ Say Y here if you want to enable support for the LG LH400WV3 MIPI
+ DBI Type B panel found in the LG Optimus 2X P990 smartphone.
+
+ To compile this driver as a module, choose M here: the module will
+ be called panel-lg-lh400wv3.
+
config DRM_PANEL_LG_SW43408
tristate "LG SW43408 panel"
depends on GPIOLIB
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
index 414267a49d922..842a2a973777f 100644
--- a/drivers/gpu/drm/panel/Makefile
+++ b/drivers/gpu/drm/panel/Makefile
@@ -54,6 +54,7 @@ obj-$(CONFIG_DRM_PANEL_LINCOLNTECH_LCD197) += panel-lincolntech-lcd197.o
obj-$(CONFIG_DRM_PANEL_LG_LB035Q02) += panel-lg-lb035q02.o
obj-$(CONFIG_DRM_PANEL_LG_LD070WX3) += panel-lg-ld070wx3.o
obj-$(CONFIG_DRM_PANEL_LG_LG4573) += panel-lg-lg4573.o
+obj-$(CONFIG_DRM_PANEL_LG_LH400WV3) += panel-lg-lh400wv3.o
obj-$(CONFIG_DRM_PANEL_LG_SW43408) += panel-lg-sw43408.o
obj-$(CONFIG_DRM_PANEL_LXD_M9189A) += panel-lxd-m9189a.o
obj-$(CONFIG_DRM_PANEL_MAGNACHIP_D53E6EA8966) += panel-magnachip-d53e6ea8966.o
diff --git a/drivers/gpu/drm/panel/panel-lg-lh400wv3.c b/drivers/gpu/drm/panel/panel-lg-lh400wv3.c
new file mode 100644
index 0000000000000..cb2a09699fc6d
--- /dev/null
+++ b/drivers/gpu/drm/panel/panel-lg-lh400wv3.c
@@ -0,0 +1,236 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include <linux/array_size.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/media-bus-format.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+
+#include <video/mipi_display.h>
+
+#include <drm/drm_mipi_dbi.h>
+#include <drm/drm_modes.h>
+#include <drm/drm_of.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_probe_helper.h>
+
+static const struct regulator_bulk_data lg_lh400wv3_supplies[] = {
+ { .supply = "avci" }, { .supply = "iovcc" },
+};
+
+struct lg_lh400wv3 {
+ struct drm_panel panel;
+ struct mipi_dbi *dbi;
+
+ struct regulator_bulk_data *supplies;
+ struct gpio_desc *reset_gpio;
+};
+
+static inline struct lg_lh400wv3 *to_lg_lh400wv3(struct drm_panel *panel)
+{
+ return container_of(panel, struct lg_lh400wv3, panel);
+}
+
+#define panel_dbi_command(priv, cmd, seq...) \
+({ \
+ const u8 d[] = { seq }; \
+ struct drm_panel *panel = &(priv)->panel; \
+ struct device *dev = panel->dev; \
+ int ret; \
+ ret = mipi_dbi_command_stackbuf((priv)->dbi, cmd, d, ARRAY_SIZE(d)); \
+ if (ret) \
+ dev_err_ratelimited(dev, "error %d when sending command %#02x\n", ret, cmd); \
+ ret; \
+})
+
+static int lg_lh400wv3_prepare(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+ struct device *dev = panel->dev;
+ int ret;
+
+ priv->dbi = dev_get_drvdata(dev->parent);
+ if (!priv->dbi)
+ return -ENODEV;
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(lg_lh400wv3_supplies), priv->supplies);
+ if (ret) {
+ dev_err(dev, "failed to enable power supplies: %d\n", ret);
+ return ret;
+ }
+
+ usleep_range(1000, 2000);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 0);
+
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int lg_lh400wv3_enable(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ panel_dbi_command(priv, MIPI_DCS_EXIT_INVERT_MODE);
+ panel_dbi_command(priv, MIPI_DCS_SET_TEAR_ON);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_24BIT |
+ MIPI_DCS_PIXEL_FMT_24BIT << 4);
+
+ panel_dbi_command(priv, 0xb2, 0x00, 0xc8);
+ panel_dbi_command(priv, 0xb3, 0x00);
+ panel_dbi_command(priv, 0xb4, 0x04);
+ panel_dbi_command(priv, 0xb5, 0x42, 0x10, 0x10, 0x00, 0x20);
+ panel_dbi_command(priv, 0xb6, 0x0b, 0x0f, 0x3c, 0x13, 0x13, 0xe8);
+ panel_dbi_command(priv, 0xb7, 0x4c, 0x06, 0x0c, 0x00, 0x00);
+
+ panel_dbi_command(priv, 0xc0, 0x01, 0x11);
+ panel_dbi_command(priv, 0xc3, 0x07, 0x03, 0x04, 0x04, 0x04);
+ panel_dbi_command(priv, 0xc4, 0x12, 0x24, 0x18, 0x18, 0x02, 0x49);
+ panel_dbi_command(priv, 0xc5, 0x65);
+ panel_dbi_command(priv, 0xc6, 0x41, 0x63);
+
+ panel_dbi_command(priv, 0xd0, 0x00, 0x46, 0x74, 0x32, 0x1d, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv, 0xd1, 0x00, 0x46, 0x74, 0x32, 0x1d, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv, 0xd2, 0x00, 0x46, 0x74, 0x32, 0x1f, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv, 0xd3, 0x00, 0x46, 0x74, 0x32, 0x1f, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv, 0xd4, 0x01, 0x46, 0x74, 0x25, 0x00, 0x03, 0x51, 0x15, 0x04);
+ panel_dbi_command(priv, 0xd5, 0x01, 0x46, 0x74, 0x25, 0x00, 0x03, 0x51, 0x15, 0x04);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_COLUMN_ADDRESS, 0x00, 0x00, 0x01, 0xdf);
+ panel_dbi_command(priv, MIPI_DCS_SET_PAGE_ADDRESS, 0x00, 0x00, 0x03, 0x1f);
+
+ panel_dbi_command(priv, MIPI_DCS_EXIT_SLEEP_MODE);
+ msleep(120);
+
+ panel_dbi_command(priv, MIPI_DCS_WRITE_MEMORY_START);
+ panel_dbi_command(priv, MIPI_DCS_SET_DISPLAY_ON);
+
+ return 0;
+}
+
+static int lg_lh400wv3_disable(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ panel_dbi_command(priv, MIPI_DCS_SET_DISPLAY_OFF);
+ panel_dbi_command(priv, MIPI_DCS_ENTER_SLEEP_MODE);
+ msleep(150);
+
+ panel_dbi_command(priv, 0xc1, 0x01);
+ usleep_range(10000, 11000);
+
+ return 0;
+};
+
+static int lg_lh400wv3_unprepare(struct drm_panel *panel)
+{
+ struct lg_lh400wv3 *priv = to_lg_lh400wv3(panel);
+
+ gpiod_set_value_cansleep(priv->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(lg_lh400wv3_supplies), priv->supplies);
+
+ msleep(50);
+
+ return 0;
+}
+
+static const struct drm_display_mode lg_lh400wv3_mode = {
+ .clock = (480 + 10 + 10 + 10) * (800 + 4 + 4 + 4) * 60 / 1000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 10,
+ .hsync_end = 480 + 10 + 10,
+ .htotal = 480 + 10 + 10 + 10,
+ .vdisplay = 800,
+ .vsync_start = 800 + 4,
+ .vsync_end = 800 + 4 + 4,
+ .vtotal = 800 + 4 + 4 + 4,
+ .width_mm = 86,
+ .height_mm = 52,
+ .type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED,
+};
+
+static int lg_lh400wv3_get_modes(struct drm_panel *panel,
+ struct drm_connector *connector)
+{
+ u32 bus_format = MEDIA_BUS_FMT_RGB888_1X24;
+
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &bus_format, 1);
+
+ connector->display_info.bus_flags = DRM_BUS_FLAG_PIXDATA_SAMPLE_POSEDGE |
+ DRM_BUS_FLAG_SYNC_SAMPLE_NEGEDGE |
+ DRM_BUS_FLAG_DE_HIGH |
+ DRM_BUS_FLAG_DATA_LSB_TO_MSB;
+
+ return drm_connector_helper_get_modes_fixed(connector, &lg_lh400wv3_mode);
+}
+
+static const struct drm_panel_funcs lg_lh400wv3_panel_funcs = {
+ .prepare = lg_lh400wv3_prepare,
+ .enable = lg_lh400wv3_enable,
+ .disable = lg_lh400wv3_disable,
+ .unprepare = lg_lh400wv3_unprepare,
+ .get_modes = lg_lh400wv3_get_modes,
+};
+
+static int lg_lh400wv3_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct lg_lh400wv3 *priv;
+ int ret;
+
+ priv = devm_drm_panel_alloc(dev, struct lg_lh400wv3, panel,
+ &lg_lh400wv3_panel_funcs, DRM_MODE_CONNECTOR_DPI);
+ if (IS_ERR(priv))
+ return PTR_ERR(priv);
+
+ ret = devm_regulator_bulk_get_const(dev, ARRAY_SIZE(lg_lh400wv3_supplies),
+ lg_lh400wv3_supplies, &priv->supplies);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get supplies\n");
+
+ priv->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->reset_gpio),
+ "Failed to get reset gpio\n");
+
+ ret = drm_panel_of_backlight(&priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to get backlight\n");
+
+ ret = devm_drm_panel_add(dev, &priv->panel);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to add panel\n");
+
+ platform_set_drvdata(pdev, priv);
+
+ return 0;
+}
+
+static const struct of_device_id lg_lh400wv3_of_match[] = {
+ { .compatible = "lg,lh400wv3-sd04" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, lg_lh400wv3_of_match);
+
+static struct platform_driver lg_lh400wv3_driver = {
+ .driver = {
+ .name = "panel-lg-lh400wv3",
+ .of_match_table = lg_lh400wv3_of_match,
+ },
+ .probe = lg_lh400wv3_probe,
+};
+module_platform_driver(lg_lh400wv3_driver);
+
+MODULE_AUTHOR("Svyatoslav Ryhel <clamor95@gmail.com>");
+MODULE_DESCRIPTION("LG LH400WV3-SD04 MIPI DBI Type B panel driver");
+MODULE_LICENSE("GPL");
--
2.53.0
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface
2026-10-04 16:31 ` [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
@ 2026-10-05 13:30 ` Rob Herring (Arm)
0 siblings, 0 replies; 11+ messages in thread
From: Rob Herring (Arm) @ 2026-10-05 13:30 UTC (permalink / raw)
To: Svyatoslav Ryhel
Cc: Mikko Perttunen, Thierry Reding, Neil Armstrong, Jessica Zhang,
Simona Vetter, Jonathan Hunter, Conor Dooley, Maarten Lankhorst,
Krzysztof Kozlowski, Maxime Ripard, David Airlie,
Thomas Zimmermann, devicetree, linux-kernel, linux-tegra,
dri-devel
On Sun, 04 Oct 2026 19:31:10 +0300, Svyatoslav Ryhel wrote:
> Document 8-bit CPU parallel MIPI DBI Type B interface provided by
> Tegra20/30 SoCs display controller.
>
> Signed-off-by: Svyatoslav Ryhel <clamor95@gmail.com>
> ---
> .../display/tegra/nvidia,tegra-dbi.yaml | 143 ++++++++++++++++++
> .../display/tegra/nvidia,tegra20-dc.yaml | 3 +
> 2 files changed, 146 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.yaml
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
dtschema/dtc warnings/errors:
Documentation/devicetree/bindings/display/tegra/nvidia,tegra-dbi.example.dtb: /example-0/dc@54200000/dbi/panel: failed to match any schema with compatible: ['hit,tx10d07vm0baa']
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20261004163114.181800-4-clamor95@gmail.com
The base for the series is generally the latest rc1. A different dependency
should be noted in *this* patch.
If you already ran 'make dt_binding_check' and didn't see the above
error(s), then make sure 'yamllint' is installed and dt-schema is up to
date:
pip3 install dtschema --upgrade
Please check and re-submit after running the above command yourself. Note
that DT_SCHEMA_FILES can be set to your schema file to speed up checking
your schema. However, it must be unset to test all examples with your schema.
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface
2026-10-04 16:31 ` [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
@ 2026-10-05 14:29 ` kernel test robot
2026-10-06 3:42 ` kernel test robot
1 sibling, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-10-05 14:29 UTC (permalink / raw)
To: Svyatoslav Ryhel, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thierry Reding, Jonathan Hunter, Mikko Perttunen
Cc: oe-kbuild-all, dri-devel, devicetree, linux-kernel, linux-tegra
Hi Svyatoslav,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on drm/drm-next linus/master v7.3-rc6 next-20261002]
[cannot apply to tegra/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Svyatoslav-Ryhel/drm-tegra-dc-Expand-available-registers-layouts/20261004-193108
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20261004163114.181800-5-clamor95%40gmail.com
patch subject: [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface
config: nios2-allmodconfig (https://download.01.org/0day-ci/archive/20261005/202610052204.NAPy4kxK-lkp@intel.com/config)
compiler: nios2-linux-gcc (GCC) 11.5.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261005/202610052204.NAPy4kxK-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202610052204.NAPy4kxK-lkp@intel.com/
All errors (new ones prefixed by >>):
nios2-linux-ld: drivers/gpu/drm/tegra/dbi.o: in function `tegra_dbi_driver_init':
>> dbi.c:(.init.text+0x0): multiple definition of `init_module'; drivers/gpu/drm/tegra/drm.o:drm.c:(.init.text+0x0): first defined here
nios2-linux-ld: drivers/gpu/drm/tegra/dbi.o: in function `tegra_dbi_driver_exit':
>> dbi.c:(.exit.text+0x0): multiple definition of `cleanup_module'; drivers/gpu/drm/tegra/drm.o:drm.c:(.exit.text+0x0): first defined here
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
* Re: [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface
2026-10-04 16:31 ` [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
2026-10-05 14:29 ` kernel test robot
@ 2026-10-06 3:42 ` kernel test robot
1 sibling, 0 replies; 11+ messages in thread
From: kernel test robot @ 2026-10-06 3:42 UTC (permalink / raw)
To: Svyatoslav Ryhel, Neil Armstrong, Jessica Zhang,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
David Airlie, Simona Vetter, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Thierry Reding, Jonathan Hunter, Mikko Perttunen
Cc: oe-kbuild-all, dri-devel, devicetree, linux-kernel, linux-tegra
Hi Svyatoslav,
kernel test robot noticed the following build errors:
[auto build test ERROR on drm-misc/drm-misc-next]
[also build test ERROR on drm/drm-next linus/master v7.3-rc6 next-20261005]
[cannot apply to tegra/for-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Svyatoslav-Ryhel/drm-tegra-dc-Expand-available-registers-layouts/20261004-193108
base: https://gitlab.freedesktop.org/drm/misc/kernel.git drm-misc-next
patch link: https://lore.kernel.org/r/20261004163114.181800-5-clamor95%40gmail.com
patch subject: [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface
config: parisc-allmodconfig (https://download.01.org/0day-ci/archive/20261006/202610061119.aQ5vg3Ez-lkp@intel.com/config)
compiler: hppa-linux-gcc (GCC) 16.1.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20261006/202610061119.aQ5vg3Ez-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202610061119.aQ5vg3Ez-lkp@intel.com/
All errors (new ones prefixed by >>):
hppa-linux-ld: drivers/gpu/drm/tegra/dbi.o: in function `tegra_dbi_driver_init':
>> (.init.text+0x10): multiple definition of `init_module'; drivers/gpu/drm/tegra/drm.o:(.init.text+0x10): first defined here
hppa-linux-ld: drivers/gpu/drm/tegra/dbi.o: in function `tegra_dbi_driver_exit':
>> (.exit.text+0x0): multiple definition of `cleanup_module'; drivers/gpu/drm/tegra/drm.o:(.exit.text+0x0): first defined here
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 11+ messages in thread
end of thread, other threads:[~2026-10-06 3:43 UTC | newest]
Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-04 16:31 [PATCH v2 0/7] drm/tegra: Add support for Tegra20/Tegra30 8-bit CPU interface Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 1/7] drm/tegra: dc: Expand available registers layouts Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 2/7] drm/tegra: rgb: Parameterize configuration based on bus flags Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 3/7] dt-bindings: display: tegra: Document 8-bit CPU parallel interface Svyatoslav Ryhel
2026-10-05 13:30 ` Rob Herring (Arm)
2026-10-04 16:31 ` [PATCH v2 4/7] drm/tegra: Add support for 8-bit CPU interface Svyatoslav Ryhel
2026-10-05 14:29 ` kernel test robot
2026-10-06 3:42 ` kernel test robot
2026-10-04 16:31 ` [PATCH v2 5/7] dt-bindings: display: panel: Document Hitachi TX10D07VM0BAA and LG LH400WV3 panels Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 6/7] drm/panel: Add Hitachi TX10D07VM0BAA MIPI DBI Type B panel driver Svyatoslav Ryhel
2026-10-04 16:31 ` [PATCH v2 7/7] drm/panel: Add LG LH400WV3-SD04 " Svyatoslav Ryhel
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®