* [PATCH v2 0/2] Add ITE IT6162 MIPI DSI to HDMI bridge driver
@ 2026-03-09 9:42 Hermes Wu via B4 Relay
2026-03-09 9:42 ` [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge Hermes Wu via B4 Relay
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
0 siblings, 2 replies; 10+ messages in thread
From: Hermes Wu via B4 Relay @ 2026-03-09 9:42 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Pet.Weng, Kenneth.Hung, Hermes Wu, dri-devel, devicetree,
linux-kernel, Hermes Wu
This patch series adds support for the ITE IT6162 MIPI DSI to HDMI
bridge chip. The IT6162 is an I2C-controlled bridge that receives MIPI
DSI input and outputs HDMI signals.
The device supports the following configurations:
- Single MIPI DSI input: up to 4K @ 30Hz
- Dual MIPI DSI input (combined): up to 4K @ 60Hz
This series introduces:
- dt-bindings: Add YAML binding document for ITE IT6162
- drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
---
Changes in v2:
- dt-bindings:
* Add property "ite,spport-hdcp" to enable HDCP
* Add property "lane-polarities" and "clock-noncontinuous" for DSI
setting
- drm/bridge:
* Drop unused element in struct it6162
* Remove regmap wrappers
* Use FIELD_PREP for bitfield operations
* Update HDCP status with drm_hdcp_update_content_protection()
* Add AVI, AUDIO, and SPD infoframe control
* Remove conversion from drm_display_mode to videomode
* Fix regulator/gpio error handling in it6162_init_pdata() to return proper error codes
- MAINTAINERS
* squash to driver patch
- Link to v1: https://lore.kernel.org/r/20260223-upstream-6162-v1-0-ebcc66ccb1fe@ite.com.tw
---
Hermes Wu (2):
dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
.../bindings/display/bridge/ite,it6162.yaml | 216 +++
MAINTAINERS | 7 +
drivers/gpu/drm/bridge/Kconfig | 17 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/ite-it6162.c | 1847 ++++++++++++++++++++
5 files changed, 2088 insertions(+)
---
base-commit: 2622649ad6cdbb3e77bfafc8c0fe686090b77f70
change-id: 20260223-upstream-6162-3751e78dfcad
Best regards,
--
Hermes Wu <Hermes.wu@ite.com.tw>
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
2026-03-09 9:42 [PATCH v2 0/2] Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
@ 2026-03-09 9:42 ` Hermes Wu via B4 Relay
2026-03-09 10:30 ` Rob Herring (Arm)
2026-03-10 8:08 ` Krzysztof Kozlowski
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
1 sibling, 2 replies; 10+ messages in thread
From: Hermes Wu via B4 Relay @ 2026-03-09 9:42 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Pet.Weng, Kenneth.Hung, Hermes Wu, dri-devel, devicetree,
linux-kernel, Hermes Wu
From: Hermes Wu <Hermes.wu@ite.com.tw>
Add device tree binding documentation for the ITE IT6162 MIPI DSI to
HDMI 2.0 bridge chip. The IT6162 is an I2C-controlled bridge that
supports the following configurations:
- Single MIPI DSI input: up to 4K @ 30Hz
- Dual MIPI DSI input (combined): up to 4K @ 60Hz
The chip also supports up to 8-channel audio output via 4 I2S data
channels.
Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
---
.../bindings/display/bridge/ite,it6162.yaml | 216 +++++++++++++++++++++
1 file changed, 216 insertions(+)
diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..01aa33110a20b8ad5e2946ab5e01229dcb4cb5d3
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
@@ -0,0 +1,216 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/display/bridge/ite,it6162.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ITE IT6162 MIPI DSI to HDMI 2.0 Bridge
+
+maintainers:
+ - Hermes Wu <Hermes.Wu@ite.com.tw>
+
+description: |
+ The ITE IT6162 is a high-performance, low-power HDMI bridge that converts
+ 2 MIPI DSI signals to 1 HDMI 2.0 output. It supports dual MIPI D-PHY 2.0
+ links up to 10 Gbps each (20 Gbps total), compatible with DSI-2 v2.0.
+
+ The HDMI transmitter supports resolutions up to 4Kx2K@60Hz and is compliant
+ with HDMI 2.0 specifications.
+
+ For audio, it supports up to 8-channel LPCM via I2S (multi-line or TDM mode),
+ with optional S/PDIF or DSD (for SACD). Audio sampling rates up to 192 kHz
+ are supported.
+
+allOf:
+ - $ref: /schemas/sound/dai-common.yaml#
+
+properties:
+ compatible:
+ const: ite,it6162
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ reset-gpios:
+ maxItems: 1
+
+ ivdd-supply:
+ description: Core voltage supply
+
+ ovdd-supply:
+ description: I/O voltage supply
+
+ ovdd1833-supply:
+ description: Flexible I/O voltage supply (1.8V domain)
+
+ "#sound-dai-cells":
+ const: 0
+
+ ite,support-hdcp:
+ description: >
+ Boolean property indicating that HDCP (High-bandwidth Digital Content
+ Protection) is supported and enabled on this board/hardware instance.
+
+ When present, the driver may initialize and enable HDCP functionality
+ (typically HDCP 1.4 or higher depending on chip/firmware). If absent,
+ HDCP support is considered disabled or not implemented/wired.
+
+ Presence enables support; the property value is ignored (use as flag:
+ `ite,support-hdcp;`).
+ type: boolean
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Input port for MIPI DSI-0 (first DSI lane pair; optional)
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+ lane-polarities:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ maxItems: 5
+ items:
+ enum: [0, 1]
+ description: >
+ Array of lane polarities starting with clock lane, followed by
+ data lanes in the order given in data-lanes.
+ 0 = normal (active high), 1 = inverted (active low).
+ If omitted, all lanes are assumed normal (0).
+ clock-noncontinuous:
+ type: boolean
+ description: >
+ If present, allows MIPI DSI non-continuous clock mode
+ (clock lane can be stopped between transmissions for power saving).
+ required:
+ - data-lanes
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: Input port for MIPI DSI-1 (second DSI lane pair; required)
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+ lane-polarities:
+ $ref: /schemas/types.yaml#/definitions/uint32-array
+ minItems: 1
+ maxItems: 5
+ items:
+ enum: [0, 1]
+ description: >
+ Array of lane polarities starting with clock lane, followed by
+ data lanes in the order given in data-lanes.
+ 0 = normal (active high), 1 = inverted (active low).
+ If omitted, all lanes are assumed normal (0).
+ clock-noncontinuous:
+ type: boolean
+ description: >
+ If present, allows MIPI DSI non-continuous clock mode
+ (clock lane can be stopped between transmissions for power saving).
+ required:
+ - data-lanes
+
+ port@2:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: Audio input port (I2S; optional)
+
+ port@3:
+ $ref: /schemas/graph.yaml#/properties/port
+ description: HDMI output port (optional)
+
+ required:
+ - port@1 # Only DSI-1 port is mandatory per your request
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - ports
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ bridge@58 {
+ compatible = "ite,it6162";
+ reg = <0x58>;
+
+ #sound-dai-cells = <0>;
+
+ interrupt-parent = <&pio>;
+ interrupts = <128 IRQ_TYPE_LEVEL_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&it6162_pins>;
+
+ reset-gpios = <&pio 127 GPIO_ACTIVE_LOW>;
+
+ ivdd-supply = <&pp1000_hdmi_x>;
+ ovdd-supply = <&pp3300_vio28_x>;
+ ovdd1833-supply = <&pp1800_vcamio_x>;
+
+ ite,support-hdcp; // HDCP enabled on this board
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ it6162_dsi0: endpoint {
+ data-lanes = < 1 2 3 4>;
+ remote-endpoint = <&dsi_0_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ it6162_dsi1: endpoint {
+ data-lanes = < 1 2 3 4>;
+ remote-endpoint = <&dsi_1_out>;
+ };
+ };
+
+ port@2 {
+ reg = <2>;
+ it6162_audio_in: endpoint {
+ remote-endpoint = <&i2s0_out>;
+ };
+ };
+
+ port@3 {
+ reg = <3>;
+ it6162_hdmi_out: endpoint {
+ remote-endpoint = <&hdmi_connector_in>;
+ };
+ };
+ };
+ };
+ };
\ No newline at end of file
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
2026-03-09 9:42 [PATCH v2 0/2] Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
2026-03-09 9:42 ` [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge Hermes Wu via B4 Relay
@ 2026-03-09 9:42 ` Hermes Wu via B4 Relay
2026-03-09 15:23 ` kernel test robot
` (2 more replies)
1 sibling, 3 replies; 10+ messages in thread
From: Hermes Wu via B4 Relay @ 2026-03-09 9:42 UTC (permalink / raw)
To: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley
Cc: Pet.Weng, Kenneth.Hung, Hermes Wu, dri-devel, devicetree,
linux-kernel, Hermes Wu
From: Hermes Wu <Hermes.wu@ite.com.tw>
Add support for the ITE IT6162 MIPI DSI to HDMI 2.0 bridge chip.
The IT6162 is an I2C-controlled bridge that supports the following
configurations:
- Single MIPI DSI input: up to 4K @ 30Hz
- Dual MIPI DSI input (combined): up to 4K @ 60Hz
The driver implements the DRM bridge and connector frameworks,
including mode setting, EDID retrieval, and HPD support.
Also add a MAINTAINERS entry for the newly introduced ITE IT6162 MIPI DSI
to HDMI bridge driver, covering the driver source file and the
device tree binding document.
Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
---
MAINTAINERS | 7 +
drivers/gpu/drm/bridge/Kconfig | 17 +
drivers/gpu/drm/bridge/Makefile | 1 +
drivers/gpu/drm/bridge/ite-it6162.c | 1847 +++++++++++++++++++++++++++++++++++
4 files changed, 1872 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 30f3472c72933c93b9237d93ad35802d6dda75f1..9c6e7c02227e810f280d2bfaa73e0eb572db0119 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13640,6 +13640,13 @@ W: https://linuxtv.org
Q: http://patchwork.linuxtv.org/project/linux-media/list/
F: drivers/media/tuners/it913x*
+ITE IT6162 MIPI DSI TO HDMI BRIDGE DRIVER
+M: Hermes Wu <Hermes.wu@ite.com.tw>
+L: dri-devel@lists.freedesktop.org
+S: Maintained
+F: Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
+F: drivers/gpu/drm/bridge/ite-it6162.c
+
ITE IT6263 LVDS TO HDMI BRIDGE DRIVER
M: Liu Ying <victor.liu@nxp.com>
L: dri-devel@lists.freedesktop.org
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 1cabfa1d2b2efc6fca68619eea6050fe96a892e8..1a8fe59506cf60958babb48429b842ca3aecc755 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -107,6 +107,23 @@ config DRM_INNO_HDMI
select DRM_DISPLAY_HELPER
select DRM_KMS_HELPER
+config DRM_ITE_IT6162
+ tristate "iTE IT6162 DSI to HDMI bridge"
+ depends on OF
+ select REGMAP_I2C
+ select DRM_MIPI_DSI
+ select DRM_PANEL_BRIDGE
+ select DRM_KMS_HELPER
+ select DRM_HDMI_HELPER
+ select DRM_DISPLAY_HDMI_HELPER
+ select DRM_DISPLAY_HDCP_HELPER
+ select DRM_DISPLAY_HELPER
+ help
+ Driver for iTE IT6162 DSI to HDMI bridge
+ chip driver that converts DSI to HDMI signals
+ support up to 4k60 with 2 MIPI DSI
+ Please say Y if you have such hardware.
+
config DRM_ITE_IT6263
tristate "ITE IT6263 LVDS/HDMI bridge"
depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index fb0cf0bf88756bed8323830c80f3f1d066b51e36..3a199b27b3bbe8294a5bef6c82cfee4cd7b8a34e 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -11,6 +11,7 @@ tda998x-y := tda998x_drv.o
obj-$(CONFIG_DRM_I2C_NXP_TDA998X) += tda998x.o
obj-$(CONFIG_DRM_INNO_HDMI) += inno-hdmi.o
+obj-$(CONFIG_DRM_ITE_IT6162) += ite-it6162.o
obj-$(CONFIG_DRM_ITE_IT6263) += ite-it6263.o
obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o
obj-$(CONFIG_DRM_LONTIUM_LT8912B) += lontium-lt8912b.o
diff --git a/drivers/gpu/drm/bridge/ite-it6162.c b/drivers/gpu/drm/bridge/ite-it6162.c
new file mode 100644
index 0000000000000000000000000000000000000000..7491df8726e2af26478ab9784e76af1a124d5038
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ite-it6162.c
@@ -0,0 +1,1847 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright 2024 ITE
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ */
+#include <linux/bitfield.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+
+#include <drm/display/drm_hdcp_helper.h>
+#include <drm/display/drm_hdmi_helper.h>
+#include <drm/display/drm_hdmi_state_helper.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_bridge.h>
+#include <drm/drm_bridge_connector.h>
+#include <drm/drm_drv.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_of.h>
+#include <drm/drm_probe_helper.h>
+#include <drm/drm_print.h>
+
+#include <video/videomode.h>
+#include <sound/hdmi-codec.h>
+
+#define DATA_BUFFER_DEPTH 32
+
+#define OFFSET_CHIP_ID_L 0x00
+#define OFFSET_CHIP_ID_M 0x01
+#define OFFSET_CHIP_ID_H 0x02
+#define OFFSET_VERSION_L 0x03
+#define OFFSET_VERSION_M 0x04
+#define OFFSET_VERSION_H 0x03
+
+#define OFFSET_MIPI_CONFIG_L 0x06
+#define MIPI_CLOCK_MODE_MASK BIT(6)
+#define MIPI_PORT1_EN_MASK BIT(5)
+#define MIPI_PORT0_EN_MASK BIT(4)
+#define MIPI_LANE_SWAP_MASK BIT(3)
+#define MIPI_PN_SWAP_MASK BIT(2)
+#define MIPI_LANE_NUM_MASK 0x3
+
+#define OFFSET_MIPI_CONFIG_H 0x07
+#define OFFSET_TX_CONFIG 0x08
+
+#define OFFSET_TX_SETTING 0x09
+#define TX_HDCP_VER_MASK 0xC0
+#define TX_HDCP_ENCRYP_MASK BIT(5)
+#define TX_STREAM_TYPE_MASK BIT(4)
+
+#define OFFSET_MIPI_STATUS 0x0A
+#define OFFSET_TX_STATUS 0x0C
+#define B_TX_STATUS_HPD 7
+#define B_TX_STATUS_VIDEO_STB 6
+#define B_TX_STATUS_HDCP 4
+#define M_TX_STATUS_HDCP 0x30
+
+#define TX_VIDEO_STB BIT(B_TX_STATUS_VIDEO_STB)
+#define TX_STATUS_HPD BIT(B_TX_STATUS_HPD)
+
+#define GET_TX_HPD_STATUS(x) (((x) & TX_STATUS_HPD) >> B_TX_STATUS_HPD)
+#define GET_TX_VIDEO_STATUS(x) (((x) & TX_VIDEO_STB) >> B_TX_STATUS_VIDEO_STB)
+#define GET_TX_HDCP_STATUS(x) (((x) & M_TX_STATUS_HDCP) >> B_TX_STATUS_HDCP)
+
+#define OFFSET_SINK_CAP 0x0D
+#define B_SINK_CAP_HDCP_VER 4
+#define M_SINK_CAP_HDCP_VER 0x30
+
+#define GET_SINK_CAP_HDCP_VER(x) (((x) & M_SINK_CAP_HDCP_VER) >> B_SINK_CAP_HDCP_VER)
+
+#define OFFSET_DRIVER_DATA 0x0E
+
+#define OFFSET_DATA_TYPE_IDX 0x0F
+#define OFFSET_DATA_BUFFER 0x20
+
+#define OFFSET_AUDIO_CTRL0 0x3C
+#define MASK_AUDIO_CHANNEL_NUM 0x0F
+#define MASK_AUDIO_SELECT 0x30
+#define MASK_AUDIO_TYPE 0xC0
+
+#define OFFSET_AUDIO_CTRL1 0x3D
+#define OFFSET_AUDIO_CTRL2 0x3E
+#define MASK_I2S_BUS_MODE 0x1F
+#define MASK_I2S_WORD_LEN 0x60
+#define MASK_I2S_VALID 0x80
+
+#define OFFSET_HOST_SET 0xFE
+#define B_CONFIG_CHG BIT(7)
+#define B_SET_CHG BIT(6)
+#define HOST_SET_VIDEO_INFO (1)
+#define HOST_SET_AUDIO_INFO (2)
+#define HOST_SET_VIDEO_AUDIO_INFO (3)
+#define HOST_SET_EDID_R (0x04)
+#define HOST_SET_HDCP_R (0x05)
+#define HOST_SET_CEA_INFOFRAME (0x0E)
+
+#define OFFSET_EVENT_CHG 0xFF
+#define B_EVENT_CHG_BUFFER 4
+#define M_EVENT_CHG_BUFFER_STS (0x30)
+
+#define B_EVENT_CHG 1
+#define B_EVENT_IC_READY 0
+
+#define EVENT_CHG BIT(B_EVENT_CHG)
+#define EVENT_READY BIT(B_EVENT_IC_READY)
+
+#define GET_BUFFER_STATUS(x) (((x) & M_EVENT_CHG_BUFFER_STS) >> B_EVENT_CHG_BUFFER)
+
+#define TIMEOUT_INFOBLOCK_MS 1800
+
+enum it6162_audio_select {
+ I2S = 0,
+ SPDIF,
+};
+
+enum it6162_audio_word_length {
+ WORD_LENGTH_16BIT = 0x0,
+ WORD_LENGTH_18BIT = 0x1,
+ WORD_LENGTH_20BIT = 0x2,
+ WORD_LENGTH_24BIT = 0x3,
+};
+
+enum it6162_audio_sample_rate {
+ SAMPLE_RATE_32K = 0x3,
+ SAMPLE_RATE_48K = 0x2,
+ SAMPLE_RATE_64K = 0xB,
+ SAMPLE_RATE_96K = 0xA,
+ SAMPLE_RATE_192K = 0xE,
+ SAMPLE_RATE_44_1K = 0x0,
+ SAMPLE_RATE_88_2K = 0x8,
+ SAMPLE_RATE_176_4K = 0xC,
+};
+
+enum it6162_audio_type {
+ LPCM = 0,
+ NLPCM,
+};
+
+enum data_buf_sts {
+ NO_STS = 0x00,
+ BUF_READY = 0x01,
+ BUF_FAIL = 0x02,
+};
+
+enum hdcp_state {
+ NO_HDCP_STATE = 0x00,
+ AUTH_DONE = 0x01,
+ AUTH_FAIL = 0x02,
+};
+
+enum hdcp_ver {
+ NO_HDCP = 0x0,
+ HDCP_14 = 0x1,
+ HDCP_23 = 0x2,
+};
+
+struct it6162_chip_info {
+ u32 chip_id;
+ u32 version;
+};
+
+struct it6162_audio {
+ enum it6162_audio_select select;
+ enum it6162_audio_type type;
+ enum it6162_audio_sample_rate sample_rate;
+ unsigned int audio_enable;
+ unsigned int sample_width;
+ unsigned int channel_number;
+ unsigned int user_cts;
+};
+
+struct it6162_video_settings {
+ u8 vic;
+ u32 clock;
+ u16 htotal;
+ u16 hfp;
+ u16 hsw;
+ u16 hbp;
+ u16 hdew;
+ u16 vtotal;
+ u16 vfp;
+ u16 vsw;
+ u16 vbp;
+ u16 vdew;
+ u8 hpol;
+ u8 vpol;
+ u8 prog;
+ u16 v_aspect;
+ u16 h_aspect;
+ u8 pix_rep;
+ u8 colorspace;
+};
+
+enum sync_mode {
+ SYNC_EVENT = 0x0,
+ SYNC_PULSE = 0x1,
+ SYNC_AUTO = 0x2,
+};
+
+struct it6162_mipi_cfg {
+ bool en_port[2];
+ u8 lane_num;
+ bool pn_swap;
+ bool lane_swap;
+ bool continuous_clk;
+ enum sync_mode mode;
+ enum mipi_dsi_pixel_format format;
+ unsigned long mode_flags;
+};
+
+struct it6162_hdcp_cfg {
+ enum hdcp_ver hdcp_version;
+ bool hdcp_encyption;
+ u8 stream_ID;
+};
+
+struct it6162_infoblock_msg {
+ u8 action;
+ int len;
+ u8 msg[32];
+};
+
+struct it6162 {
+ struct drm_bridge bridge;
+ struct device *dev;
+ struct drm_connector *connector;
+ enum drm_connector_status connector_status;
+ struct drm_device *drm;
+
+ struct i2c_client *it6162_i2c;
+ struct regmap *regmap;
+
+ struct regulator *pwr1833;
+ struct regulator *ovdd;
+ struct regulator *ivdd;
+ struct gpio_desc *gpiod_reset;
+
+ bool power_on;
+ bool en_hdcp;
+
+ /*lock the infoblock write setting and buffer access*/
+ struct mutex lock;
+
+ enum data_buf_sts data_buf_sts;
+
+ /* it6162 DSI RX related params */
+ struct mipi_dsi_device *dsi;
+ struct it6162_mipi_cfg mipi_cfg;
+
+ struct delayed_work hdcp_work;
+ enum hdcp_state hdcp_sts;
+ enum hdcp_ver hdcp_version;
+ struct it6162_hdcp_cfg hdcp_cfg;
+
+ unsigned int content_protection;
+};
+
+static struct it6162 *bridge_to_it6162(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct it6162, bridge);
+}
+
+static const struct regmap_config it6162_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 0xff,
+ .cache_type = REGCACHE_NONE,
+};
+
+static inline int it6162_i2c_regmap_init(struct i2c_client *client,
+ struct it6162 *it6162)
+{
+ it6162->it6162_i2c = client;
+ i2c_set_clientdata(client, it6162);
+ it6162->regmap = devm_regmap_init_i2c(it6162->it6162_i2c,
+ &it6162_regmap_config);
+
+ if (IS_ERR(it6162->regmap))
+ return PTR_ERR(it6162->regmap);
+
+ return 0;
+}
+
+static int it6162_infoblock_complete(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ struct regmap *regmap = it6162->regmap;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(regmap, OFFSET_HOST_SET, &val);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "read failed rx reg[0x%x]",
+ OFFSET_HOST_SET);
+
+ return val;
+}
+
+static int it6162_infoblock_host_set(struct it6162 *it6162, u8 setting)
+{
+ struct device *dev = it6162->dev;
+ int status;
+ int val;
+
+ regmap_write(it6162->regmap, OFFSET_HOST_SET, setting);
+ /*wait command complete*/
+ status = readx_poll_timeout(it6162_infoblock_complete,
+ it6162,
+ val,
+ val <= 0,
+ 50 * 1000,
+ TIMEOUT_INFOBLOCK_MS * 1000);
+
+ if (status < 0 || val != 0) {
+ dev_err(dev, "%s err status = %d, val = %d", __func__,
+ status, val);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int it6162_infoblock_request_data(struct it6162 *it6162,
+ u8 setting, u8 index, u8 *buf)
+{
+ struct device *dev = it6162->dev;
+ int status;
+ bool val = 0;
+
+ it6162->data_buf_sts = NO_STS;
+ regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, index);
+ regmap_write(it6162->regmap, OFFSET_HOST_SET, setting);
+
+ status = readx_poll_timeout(it6162_infoblock_complete,
+ it6162,
+ val,
+ val <= 0 && it6162->data_buf_sts == BUF_READY,
+ 50 * 1000,
+ TIMEOUT_INFOBLOCK_MS * 1000);
+
+ if (status < 0 || val != 0) {
+ dev_err(dev,
+ "%s err status = %d %d",
+ __func__,
+ status,
+ it6162->data_buf_sts);
+ return -ETIMEDOUT;
+ }
+
+ dev_dbg(dev, "%s [0x%x] 0x%x", __func__, setting, it6162->data_buf_sts);
+ if (it6162->data_buf_sts != BUF_READY)
+ return -EIO;
+
+ regmap_bulk_read(it6162->regmap,
+ OFFSET_DATA_BUFFER, buf, DATA_BUFFER_DEPTH);
+ return 0;
+}
+
+static void it6162_infoblock_mipi_config(struct it6162 *it6162)
+{
+ struct it6162_mipi_cfg *cfg = &it6162->mipi_cfg;
+ u8 cfg_val = 0;
+
+ cfg_val = FIELD_PREP(MIPI_CLOCK_MODE_MASK, cfg->continuous_clk) |
+ FIELD_PREP(MIPI_LANE_SWAP_MASK, cfg->lane_swap) |
+ FIELD_PREP(MIPI_PN_SWAP_MASK, cfg->pn_swap) |
+ FIELD_PREP(MIPI_LANE_NUM_MASK, cfg->lane_num - 1);
+
+ dev_dbg(it6162->dev, "%s 0x%02x 0x%02x", __func__,
+ cfg_val, cfg->mode);
+
+ regmap_write(it6162->regmap, OFFSET_MIPI_CONFIG_L, cfg_val);
+ regmap_write(it6162->regmap, OFFSET_MIPI_CONFIG_H, cfg->mode);
+}
+
+static inline void it6162_infoblock_write_msg(struct it6162 *it6162,
+ struct it6162_infoblock_msg *msg)
+{
+ regmap_bulk_write(it6162->regmap,
+ OFFSET_DATA_BUFFER, msg->msg, msg->len);
+ it6162_infoblock_host_set(it6162, msg->action);
+}
+
+static void it6162_set_default_config(struct it6162 *it6162)
+{
+ guard(mutex)(&it6162->lock);
+ it6162_infoblock_mipi_config(it6162);
+ regmap_write(it6162->regmap, OFFSET_TX_CONFIG, 0x00);
+ regmap_write(it6162->regmap, OFFSET_TX_SETTING, 0x00);
+ it6162_infoblock_host_set(it6162, B_CONFIG_CHG | B_SET_CHG);
+}
+
+static void it6162_mipi_disable(struct it6162 *it6162)
+{
+ guard(mutex)(&it6162->lock);
+ regmap_update_bits(it6162->regmap,
+ OFFSET_MIPI_CONFIG_L,
+ MIPI_PORT1_EN_MASK | MIPI_PORT0_EN_MASK,
+ 0x00);
+ it6162_infoblock_host_set(it6162, B_CONFIG_CHG);
+}
+
+static void it6162_mipi_enable(struct it6162 *it6162)
+{
+ unsigned int cfg_val = 0;
+
+ cfg_val = FIELD_PREP(MIPI_PORT1_EN_MASK, it6162->mipi_cfg.en_port[1]) |
+ FIELD_PREP(MIPI_PORT0_EN_MASK, it6162->mipi_cfg.en_port[0]);
+
+ guard(mutex)(&it6162->lock);
+ regmap_update_bits(it6162->regmap,
+ OFFSET_MIPI_CONFIG_L,
+ MIPI_PORT1_EN_MASK |
+ MIPI_PORT0_EN_MASK,
+ cfg_val);
+ it6162_infoblock_host_set(it6162, B_CONFIG_CHG);
+}
+
+static void it6162_tx_hdcp_enable(struct it6162 *it6162,
+ struct it6162_hdcp_cfg *tx_out)
+{
+ int val;
+ struct regmap *regmap = it6162->regmap;
+
+ guard(mutex)(&it6162->lock);
+ it6162->hdcp_sts = NO_HDCP_STATE;
+ regmap_read(regmap, OFFSET_TX_SETTING, &val);
+ val &= 0x0F;
+
+ val |= FIELD_PREP(TX_HDCP_VER_MASK, tx_out->hdcp_version) |
+ FIELD_PREP(TX_HDCP_ENCRYP_MASK, tx_out->hdcp_encyption) |
+ FIELD_PREP(TX_STREAM_TYPE_MASK, tx_out->stream_ID);
+
+ regmap_write(regmap, OFFSET_TX_SETTING, val);
+ it6162_infoblock_host_set(it6162, B_SET_CHG);
+ drm_dbg(it6162->drm, "%s 0x%02x", __func__, val);
+}
+
+static void it6162_tx_hdcp_disable(struct it6162 *it6162)
+{
+ int val;
+ struct regmap *regmap = it6162->regmap;
+
+ it6162->hdcp_sts = NO_HDCP_STATE;
+ it6162->hdcp_version = NO_HDCP;
+
+ guard(mutex)(&it6162->lock);
+ regmap_read(regmap, OFFSET_TX_SETTING, &val);
+ regmap_write(it6162->regmap, OFFSET_TX_SETTING, val & 0x0F);
+ it6162_infoblock_host_set(it6162, B_SET_CHG);
+
+ drm_dbg(it6162->drm, "%s 0x%02x", __func__, val);
+}
+
+static void it6162_tx_hdcp_setup(struct it6162 *it6162,
+ u8 ver,
+ bool encription)
+{
+ struct it6162_hdcp_cfg tx_out;
+
+ drm_dbg(it6162->drm, "%s ver %x enc %d", __func__, ver, encription);
+
+ if (ver != NO_HDCP) {
+ tx_out.hdcp_version = ver;
+ tx_out.hdcp_encyption = encription;
+ tx_out.stream_ID = 0;
+ it6162_tx_hdcp_enable(it6162, &tx_out);
+ } else {
+ it6162_tx_hdcp_disable(it6162);
+ }
+}
+
+static void it6162_tx_enable(struct it6162 *it6162)
+{
+ if (!it6162->en_hdcp)
+ it6162->hdcp_version = NO_HDCP;
+ else
+ it6162->hdcp_version = it6162->hdcp_cfg.hdcp_version;
+
+ drm_dbg(it6162->drm, "%s %d", __func__, it6162->hdcp_version);
+}
+
+static void it6162_tx_disable(struct it6162 *it6162)
+{
+ if (it6162->en_hdcp) {
+ cancel_delayed_work_sync(&it6162->hdcp_work);
+ it6162_tx_hdcp_setup(it6162, NO_HDCP, false);
+ }
+ drm_dbg(it6162->drm, "%s %d", __func__, it6162->hdcp_version);
+}
+
+static inline void
+it6162_pack_video_setting(struct it6162 *it6162,
+ struct it6162_video_settings *settings,
+ struct it6162_infoblock_msg *msg)
+{
+ msg->msg[0x00] = settings->hdew & 0xFF;
+ msg->msg[0x01] = (settings->hdew >> 8) & 0x3F;
+ msg->msg[0x02] = settings->vdew & 0xFF;
+ msg->msg[0x03] = (settings->vdew >> 8) & 0x3F;
+ msg->msg[0x04] = settings->clock & 0xFF;
+ msg->msg[0x05] = (settings->clock >> 8) & 0xFF;
+ msg->msg[0x06] = (settings->clock >> 16) & 0xFF;
+ msg->msg[0x07] = (settings->clock >> 24) & 0xFF;
+ msg->msg[0x08] = settings->hfp & 0xFF;
+ msg->msg[0x09] = (settings->hfp >> 8) & 0x3F;
+ msg->msg[0x0A] = settings->hsw & 0xFF;
+ msg->msg[0x0B] = (settings->hsw >> 8) & 0x3F;
+ msg->msg[0x0C] = settings->hbp & 0xFF;
+ msg->msg[0x0D] = (settings->hbp >> 8) & 0x3F;
+ msg->msg[0x0E] = settings->vfp & 0xFF;
+ msg->msg[0x0F] = (settings->vfp >> 8) & 0x3F;
+ msg->msg[0x10] = settings->vsw & 0xFF;
+ msg->msg[0x11] = (settings->vsw >> 8) & 0x3F;
+ msg->msg[0x12] = settings->vbp & 0xFF;
+ msg->msg[0x13] = (settings->vbp >> 8) & 0x3F;
+ msg->msg[0x14] = (settings->prog << 2) |
+ (settings->vpol << 1) |
+ settings->hpol;
+
+ msg->msg[0x15] = settings->v_aspect;
+ msg->msg[0x16] = settings->h_aspect & 0xFF;
+ msg->msg[0x17] = settings->h_aspect >> 8;
+ msg->msg[0x18] = settings->pix_rep;
+ msg->msg[0x19] = settings->vic;
+ msg->msg[0x1A] = settings->colorspace;
+ msg->msg[0x1B] = 1;
+
+ msg->len = 0x1C;
+ msg->action = HOST_SET_VIDEO_INFO;
+}
+
+static void it6162_mipi_set_video_timing(struct it6162 *it6162,
+ struct it6162_video_settings *mode)
+{
+ struct it6162_infoblock_msg msg;
+
+ it6162_pack_video_setting(it6162, mode, &msg);
+ guard(mutex)(&it6162->lock);
+ it6162_infoblock_write_msg(it6162, &msg);
+}
+
+static int it6162_hdcp_read_infomation(struct it6162 *it6162,
+ u8 *status, u8 *bksv)
+{
+ u8 buf[DATA_BUFFER_DEPTH];
+ int ret;
+
+ guard(mutex)(&it6162->lock);
+ ret = it6162_infoblock_request_data(it6162,
+ HOST_SET_HDCP_R,
+ 0x00,
+ buf);
+ if (ret < 0)
+ return ret;
+
+ if (status)
+ memcpy(status, buf, 2);
+
+ if (bksv)
+ memcpy(bksv, buf + 2, 5);
+
+ return 0;
+}
+
+static int it6162_hdcp_read_list(struct it6162 *it6162,
+ u8 *ksv_list,
+ int dev_count)
+{
+ u8 buf[DATA_BUFFER_DEPTH];
+ int i, j, ret;
+
+ if (!ksv_list || dev_count <= 0)
+ return -EINVAL;
+
+ guard(mutex)(&it6162->lock);
+
+ for (i = 0; i < (dev_count / 6 + 1); i++) {
+ /* KsV lists */
+ ret = it6162_infoblock_request_data(it6162,
+ HOST_SET_HDCP_R,
+ i + 1,
+ buf);
+
+ if (ret < 0)
+ return ret;
+
+ for (j = 0; j < 30; j += 5) {
+ if ((i * 6 + j / 5) >= dev_count)
+ break;
+
+ memcpy(&ksv_list[(i * 6 + j / 5) * 5], &buf[j], 5);
+ }
+ }
+
+ return dev_count;
+}
+
+static void it6162_update_hdcp14(struct it6162 *it6162)
+{
+ struct drm_device *drm = it6162->drm;
+ int dev_count;
+ u8 bksv[5];
+ u8 bstatus[2];
+ u8 ksvlist[5 * 30];
+ int ret;
+
+ ret = it6162_hdcp_read_infomation(it6162, bstatus, bksv);
+
+ if (ret < 0) {
+ drm_err(drm, "read Bstatus fail!!!!");
+ return;
+ }
+ drm_dbg(drm, "status = 0x%02X%02X", bstatus[1], bstatus[0]);
+
+ if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
+ DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
+ drm_err(drm, "HDCP14 Max Topology Limit Exceeded");
+ return;
+ }
+
+ dev_count = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
+ drm_dbg(drm, "dev_count %d", dev_count);
+ if (dev_count == 0)
+ return;
+
+ dev_count = dev_count > 30 ? 30 : dev_count;
+ ret = it6162_hdcp_read_list(it6162, ksvlist, dev_count);
+
+ if (ret < 0) {
+ drm_err(drm, "read KSV list fail!!!!");
+ return;
+ }
+}
+
+static void it6162_update_hdcp23(struct it6162 *it6162)
+{
+ struct drm_device *drm = it6162->drm;
+ int dev_count;
+ u8 rxid[5];
+ u8 rxinfo[2];
+ u8 rxid_list[5 * 30];
+ int ret;
+
+ ret = it6162_hdcp_read_infomation(it6162, rxinfo, rxid);
+
+ if (ret < 0) {
+ drm_err(drm, "read Rxinfo fail!!!!");
+ return;
+ }
+ drm_dbg(drm, "Rxinfo 0x%02X%02X", rxinfo[1], rxinfo[0]);
+
+ if (HDCP_2_2_MAX_CASCADE_EXCEEDED(rxinfo[1]) ||
+ HDCP_2_2_MAX_DEVS_EXCEEDED(rxinfo[1])) {
+ drm_err(drm, "Topology Max Size Exceeded");
+ return;
+ }
+
+ dev_count = (HDCP_2_2_DEV_COUNT_HI(rxinfo[0]) << 4 |
+ HDCP_2_2_DEV_COUNT_LO(rxinfo[1]));
+ dev_count = dev_count > 30 ? 30 : dev_count;
+ if (dev_count == 0)
+ return;
+
+ ret = it6162_hdcp_read_list(it6162, rxid_list, dev_count);
+ if (ret < 0) {
+ drm_err(drm, "read RxID list fail!!!!");
+ return;
+ }
+}
+
+static void it6162_update_hdcp(struct it6162 *it6162)
+{
+ if (it6162->hdcp_version == HDCP_23)
+ it6162_update_hdcp23(it6162);
+ else
+ it6162_update_hdcp14(it6162);
+}
+
+static void it6162_hdcp_handler(struct it6162 *it6162)
+{
+ struct regmap *regmap = it6162->regmap;
+ unsigned int tx_status, sink_cap;
+ enum hdcp_state hdcp_sts;
+ struct it6162_hdcp_cfg *hdcp_cfg = &it6162->hdcp_cfg;
+ u8 hdcp_ver;
+ u64 cp_status;
+
+ if (hdcp_cfg->hdcp_version == NO_HDCP || !it6162->en_hdcp) {
+ drm_dbg(it6162->drm, "HDCP not enabled, skip hdcp check");
+ return;
+ }
+
+ regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
+ regmap_read(regmap, OFFSET_SINK_CAP, &sink_cap);
+
+ drm_dbg(it6162->drm, "Tx status %x", tx_status);
+ drm_dbg(it6162->drm, "SINK capability %x", sink_cap);
+
+ if (!GET_TX_VIDEO_STATUS(tx_status)) {
+ drm_dbg(it6162->drm, "video not stable, skip hdcp check");
+ return;
+ }
+
+ hdcp_sts = GET_TX_HDCP_STATUS(tx_status);
+ hdcp_ver = GET_SINK_CAP_HDCP_VER(sink_cap);
+ drm_dbg(it6162->drm, "hdcp status: %x->%x, version: %x-%x",
+ it6162->hdcp_sts, hdcp_sts,
+ it6162->hdcp_version, hdcp_ver);
+
+ if (it6162->hdcp_version != NO_HDCP) {
+ if (it6162->hdcp_sts != hdcp_sts ||
+ it6162->hdcp_sts == NO_HDCP_STATE) {
+ it6162->hdcp_sts = hdcp_sts;
+ cp_status = DRM_MODE_CONTENT_PROTECTION_DESIRED;
+ switch (hdcp_sts) {
+ case AUTH_DONE:
+ drm_dbg(it6162->drm, "HDCP AUTH DONE");
+ it6162_update_hdcp(it6162);
+ cp_status = DRM_MODE_CONTENT_PROTECTION_ENABLED;
+ break;
+ case AUTH_FAIL:
+ drm_dbg(it6162->drm, "HDCP AUTH FAIL");
+ if (hdcp_ver == HDCP_23) {
+ drm_dbg(it6162->drm,
+ "HDCP 2.3 auth fail, change to HDCP 1.4");
+ it6162_tx_hdcp_setup(it6162,
+ HDCP_14,
+ true);
+ } else {
+ it6162_tx_hdcp_disable(it6162);
+ }
+
+ break;
+ default:
+ drm_dbg(it6162->drm, "HDCP NO AUTH");
+ it6162_tx_hdcp_setup(it6162,
+ it6162->hdcp_version,
+ true);
+ break;
+ }
+ }
+ drm_hdcp_update_content_protection(it6162->connector, cp_status);
+ }
+}
+
+static void it6162_interrupt_handler(struct it6162 *it6162)
+{
+ unsigned int int_status, tx_status;
+ enum drm_connector_status connector_status;
+ struct device *dev = it6162->dev;
+ struct regmap *regmap = it6162->regmap;
+ int err;
+
+ err = regmap_read(regmap, OFFSET_EVENT_CHG, &int_status);
+ if (err < 0) {
+ dev_err(dev, "read failed rx reg[0x%x] err: %d",
+ OFFSET_EVENT_CHG, err);
+ return;
+ }
+
+ regmap_write(it6162->regmap, OFFSET_EVENT_CHG, 0xFF);
+
+ if (!!GET_BUFFER_STATUS(int_status)) {
+ regmap_write(it6162->regmap, OFFSET_DRIVER_DATA, int_status);
+ it6162->data_buf_sts = GET_BUFFER_STATUS(int_status);
+ }
+
+ if (!(int_status & EVENT_CHG))
+ return;
+
+ drm_dbg(it6162->drm, "evnet change 0x%X", int_status);
+
+ err = regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
+ if (err < 0) {
+ dev_err(dev, "read failed rx reg[0x%x] err: %d",
+ OFFSET_TX_STATUS, err);
+ return;
+ }
+ drm_dbg(it6162->drm, "Tx status %x", tx_status);
+
+ connector_status = GET_TX_HPD_STATUS(tx_status) ?
+ connector_status_connected :
+ connector_status_disconnected;
+
+ if (it6162->connector_status != connector_status) {
+ it6162->connector_status = connector_status;
+ drm_bridge_hpd_notify(&it6162->bridge,
+ it6162->connector_status);
+ }
+
+ if (it6162->en_hdcp && GET_TX_VIDEO_STATUS(tx_status) &&
+ connector_status == connector_status_connected)
+ queue_delayed_work(system_wq,
+ &it6162->hdcp_work,
+ msecs_to_jiffies(2000));
+}
+
+static int it6162_wait_ready_event(struct it6162 *it6162)
+{
+ unsigned int val;
+ int ret;
+ struct device *dev = it6162->dev;
+ struct regmap *regmap = it6162->regmap;
+
+ ret = regmap_read(regmap, OFFSET_EVENT_CHG, &val);
+ if (ret < 0) {
+ dev_err(dev, "read failed rx reg[0x%x] err: %d",
+ OFFSET_EVENT_CHG, ret);
+ return ret;
+ }
+ dev_dbg(dev, "%s val %x ret %d", __func__, val, ret);
+ if (val & EVENT_READY)
+ return EVENT_READY;
+
+ ret = regmap_read(regmap, 0x00, &val);
+ if (ret < 0) {
+ dev_err(dev, "read failed rx reg[0x%x] err: %d",
+ OFFSET_EVENT_CHG, ret);
+ return ret;
+ }
+
+ if (val == 0x61) {
+ dev_warn(dev, "MCU ready event missed, but reg[0x00] is 0x61, consider MCU ready");
+ return EVENT_READY;
+ }
+
+ return 0;
+}
+
+static bool it6162_wait_mcu_ready(struct it6162 *it6162)
+{
+ struct device *dev = &it6162->it6162_i2c->dev;
+ unsigned int status;
+ int val;
+
+ status = readx_poll_timeout(it6162_wait_ready_event,
+ it6162,
+ val,
+ val == EVENT_READY,
+ 100 * 1000,
+ 1500 * 1000);
+
+ dev_dbg(dev, "%s status %d val %x", __func__, status, val);
+ return val == EVENT_READY ? true : false;
+}
+
+static void it6162_reset_init(struct it6162 *it6162)
+{
+ it6162_set_default_config(it6162);
+}
+
+static int it6162_platform_set_power(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ int err;
+
+ err = regulator_enable(it6162->ivdd);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable IVDD");
+
+ err = regulator_enable(it6162->pwr1833);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable VDD1833");
+
+ err = regulator_enable(it6162->ovdd);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to enable OVDD");
+
+ usleep_range(10000, 20000);
+ gpiod_set_value_cansleep(it6162->gpiod_reset, 1);
+ usleep_range(1000, 2000);
+ gpiod_set_value_cansleep(it6162->gpiod_reset, 0);
+ usleep_range(10000, 20000);
+
+ return 0;
+}
+
+static int it6162_platform_clear_power(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ int err;
+
+ err = regulator_disable(it6162->ivdd);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to disable IVDD");
+
+ usleep_range(2000, 3000);
+
+ err = regulator_disable(it6162->pwr1833);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to disable VDD1833");
+
+ err = regulator_disable(it6162->ovdd);
+ if (err)
+ return dev_err_probe(dev, err, "Failed to disable OVDD");
+
+ return 0;
+}
+
+static int it6162_detect_devices(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ const struct it6162_chip_info *chip_info;
+ u32 chip_id, version;
+ u8 buf[6];
+
+ if (it6162_platform_set_power(it6162) < 0)
+ return -ENODEV;
+ /*wait MCU ready event after power on*/
+ if (!it6162_wait_mcu_ready(it6162))
+ return -ENODEV;
+
+ chip_info = of_device_get_match_data(dev);
+
+ regmap_bulk_read(it6162->regmap,
+ OFFSET_CHIP_ID_L, &buf[0], 6);
+
+ dev_info(dev, "chip id %02x %02x %02X", buf[0], buf[1], buf[2]);
+ dev_info(dev, "chip VER %02x %02x %02x", buf[3], buf[4], buf[5]);
+
+ chip_id = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
+ version = (buf[3] << 16) | (buf[4] << 8) | (buf[5]);
+ dev_info(dev, "chip id 0x%06x, version 0x%06x", chip_id, version);
+
+ if (chip_id != chip_info->chip_id || version < chip_info->version) {
+ dev_err(dev, "chip_id 0x%06x != 0x%06x",
+ chip_id, chip_info->chip_id);
+ dev_err(dev, "version 0x%06x != 0x%06x",
+ version, chip_info->version);
+
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused it6162_poweron(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ int err;
+
+ dev_dbg(dev, "powered on Start");
+
+ err = it6162_platform_set_power(it6162);
+ if (err < 0)
+ return err;
+ /*wait MCU ready event after power on*/
+ if (!it6162_wait_mcu_ready(it6162))
+ return -ENODEV;
+
+ it6162->connector_status = connector_status_disconnected;
+ it6162_reset_init(it6162);
+
+ enable_irq(it6162->it6162_i2c->irq);
+ dev_dbg(dev, "enable irq %d",
+ it6162->it6162_i2c->irq);
+
+ it6162->power_on = true;
+ dev_info(dev, "it6162 poweron end");
+ return 0;
+}
+
+static int __maybe_unused it6162_poweroff(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ int err;
+
+ dev_dbg(dev, "powered off start");
+ disable_irq(it6162->it6162_i2c->irq);
+ dev_dbg(dev, "disable irq %d", it6162->it6162_i2c->irq);
+
+ err = it6162_platform_clear_power(it6162);
+ if (err < 0)
+ return err;
+
+ it6162->power_on = false;
+ dev_dbg(dev, "it6162 poweroff");
+ return 0;
+}
+
+static void it6162_config_default(struct it6162 *it6162)
+{
+ struct it6162_mipi_cfg *mipi_cfg = &it6162->mipi_cfg;
+ struct it6162_hdcp_cfg *hdcp_cfg = &it6162->hdcp_cfg;
+
+ mipi_cfg->lane_num = 4;
+ mipi_cfg->pn_swap = false;
+ mipi_cfg->lane_swap = false;
+ mipi_cfg->en_port[0] = false;
+ mipi_cfg->en_port[1] = false;
+ mipi_cfg->continuous_clk = true;
+ mipi_cfg->mode = SYNC_EVENT;
+ mipi_cfg->format = MIPI_DSI_FMT_RGB888;
+ mipi_cfg->mode_flags = MIPI_DSI_MODE_VIDEO;
+
+ it6162->en_hdcp = false;
+ hdcp_cfg->hdcp_version = HDCP_23;
+ hdcp_cfg->hdcp_encyption = true;
+ hdcp_cfg->stream_ID = 0;
+
+ it6162->connector_status = connector_status_disconnected;
+}
+
+static enum drm_connector_status it6162_detect(struct it6162 *it6162)
+{
+ struct regmap *regmap = it6162->regmap;
+ unsigned int tx_status;
+
+ regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
+
+ it6162->connector_status = GET_TX_HPD_STATUS(tx_status) ?
+ connector_status_connected :
+ connector_status_disconnected;
+
+ drm_dbg(it6162->drm, "%s connector_status %x", __func__,
+ it6162->connector_status);
+ return it6162->connector_status;
+}
+
+static int it6162_get_edid_block(void *data, u8 *buf, unsigned int block,
+ size_t len)
+{
+ struct it6162 *it6162 = data;
+ unsigned int cnt;
+ unsigned int i;
+ u8 config;
+
+ if (len > EDID_LENGTH)
+ return -EINVAL;
+
+ guard(mutex)(&it6162->lock);
+
+ cnt = 0;
+ for (i = 0; i < EDID_LENGTH; i += DATA_BUFFER_DEPTH, cnt++) {
+ config = (block << 2) | (cnt);
+ if (it6162_infoblock_request_data(it6162,
+ HOST_SET_EDID_R,
+ config, buf + i) < 0)
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static void it6162_enable_audio(struct it6162 *it6162,
+ struct it6162_audio *config)
+{
+ unsigned int val;
+
+ guard(mutex)(&it6162->lock);
+ val = FIELD_PREP(MASK_AUDIO_CHANNEL_NUM, config->channel_number) |
+ FIELD_PREP(MASK_AUDIO_SELECT, config->select) |
+ FIELD_PREP(MASK_AUDIO_TYPE, config->type);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL0, val);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL1, config->sample_rate);
+ /* Standard i2s 16bit, 24bit */
+ val = FIELD_PREP(MASK_I2S_BUS_MODE, 0) |
+ FIELD_PREP(MASK_I2S_WORD_LEN, config->sample_width) |
+ FIELD_PREP(MASK_I2S_VALID, 1);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL2, val);
+ it6162_infoblock_host_set(it6162, HOST_SET_AUDIO_INFO);
+}
+
+static void it6162_disable_audio(struct it6162 *it6162)
+{
+ guard(mutex)(&it6162->lock);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL0, 0x00);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL1, 0x00);
+ regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL2, 0x00);
+ it6162_infoblock_host_set(it6162, HOST_SET_AUDIO_INFO);
+}
+
+static irqreturn_t it6162_int_threaded_handler(int unused, void *data)
+{
+ struct it6162 *it6162 = data;
+
+ it6162_interrupt_handler(it6162);
+
+ return IRQ_HANDLED;
+}
+
+static void it6162_hdcp_work(struct work_struct *work)
+{
+ struct it6162 *it6162 = container_of(work,
+ struct it6162,
+ hdcp_work.work);
+
+ it6162_hdcp_handler(it6162);
+}
+
+static struct mipi_dsi_host *it6162_of_get_dsi_host_by_port(struct it6162 *it6162,
+ int port)
+{
+ struct device_node *of = it6162->dev->of_node;
+ struct device_node *host_node;
+ struct device_node *endpoint;
+ struct mipi_dsi_host *dsi_host;
+
+ endpoint = of_graph_get_endpoint_by_regs(of, port, -1);
+ if (!endpoint)
+ return ERR_PTR(-ENODEV);
+
+ host_node = of_graph_get_remote_port_parent(endpoint);
+ of_node_put(endpoint);
+ if (!host_node)
+ return ERR_PTR(-ENODEV);
+
+ dsi_host = of_find_mipi_dsi_host_by_node(host_node);
+ of_node_put(host_node);
+
+ if (!dsi_host)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return dsi_host;
+}
+
+static int it6162_of_get_dsi_host(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ struct mipi_dsi_host *dsi_host;
+ int port, host_count = 0;
+
+ for (port = 0; port < 2; port++) {
+ dsi_host = it6162_of_get_dsi_host_by_port(it6162, port);
+
+ if (PTR_ERR(dsi_host) == -EPROBE_DEFER) {
+ dev_info(dev,
+ "DSI host for port %d not ready, defer probe",
+ port);
+ return -EPROBE_DEFER;
+ }
+
+ if (IS_ERR(dsi_host)) {
+ dev_info(dev, "DSI host for port %d not found", port);
+ continue;
+ }
+
+ host_count++;
+ }
+
+ dev_info(dev, "%s = %d", __func__, host_count);
+ if (host_count == 0)
+ return -ENODEV;
+
+ return 0;
+}
+
+static int it6162_load_mipi_pars_from_port(struct it6162 *it6162, int port)
+{
+ struct device_node *of = it6162->dev->of_node;
+ struct device_node *endpoint;
+ struct device *dev = it6162->dev;
+ struct it6162_mipi_cfg *mipicfg = &it6162->mipi_cfg;
+ u32 data_lanes[4] = {1};
+ u32 lane_polarities[5] = {0};
+ int dsi_lanes, i;
+
+ endpoint = of_graph_get_endpoint_by_regs(of, port, -1);
+
+ if (!endpoint)
+ return 0;
+
+ dsi_lanes = drm_of_get_data_lanes_count(endpoint, 1, 4);
+
+ if (dsi_lanes < 0)
+ return dsi_lanes;
+
+ mipicfg->lane_num = dsi_lanes;
+
+ of_property_read_u32_array(endpoint, "data-lanes",
+ data_lanes, dsi_lanes);
+ /* Support lane swapping [1 2 3 4] => [4 3 2 1] */
+ if (data_lanes[0] == 4)
+ mipicfg->lane_swap = true;
+
+ of_property_read_u32_array(endpoint, "lane-polarities",
+ lane_polarities, dsi_lanes + 1);
+ /* Support Dp/Dn swapping all data lanes and clock lane must have same polarity */
+ if (lane_polarities[0] != 0)
+ mipicfg->pn_swap = true;
+
+ for (i = 1; i <= dsi_lanes; i++)
+ if (lane_polarities[i] != lane_polarities[0])
+ dev_warn_once(dev, "invalid lane-polarities configuration");
+
+ if (of_property_present(endpoint, "clock-noncontinuous")) {
+ mipicfg->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
+ mipicfg->continuous_clk = false;
+ }
+
+ of_node_put(endpoint);
+
+ dev_info(dev, "lanes: %d pn_swap: %d, lane_swap: %d, mode_flags: %lu",
+ mipicfg->lane_num, mipicfg->pn_swap,
+ mipicfg->lane_swap, mipicfg->mode_flags);
+
+ return dsi_lanes;
+}
+
+static int it6162_attach_dsi(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+ struct device_node *np = dev->of_node;
+ const struct mipi_dsi_device_info info = {"it6162-mipi", 0, np};
+ struct mipi_dsi_device *dsi;
+ struct mipi_dsi_host *dsi_host;
+ struct it6162_mipi_cfg *mipi_cfg = &it6162->mipi_cfg;
+ int ret = 0;
+
+ for (int port = 0; port < 2; port++) {
+ dsi_host = it6162_of_get_dsi_host_by_port(it6162, port);
+ if (IS_ERR(dsi_host))
+ continue;
+
+ mipi_cfg->en_port[port] = true;
+
+ if (!it6162->dsi) {
+ ret = it6162_load_mipi_pars_from_port(it6162, port);
+ if (ret <= 0)
+ return ret;
+ dev_info(dev, "DSI host loaded paras for port %d", port);
+ it6162->dsi = dsi;
+ }
+
+ dsi = devm_mipi_dsi_device_register_full(dev, dsi_host, &info);
+ if (IS_ERR(dsi)) {
+ dev_err(dev, "failed to create dsi device");
+ return PTR_ERR(dsi);
+ }
+
+ dsi->lanes = mipi_cfg->lane_num;
+ dsi->format = mipi_cfg->format;
+ dsi->mode_flags = mipi_cfg->mode_flags;
+ dev_info(dev, "dsi lanes %d, format %d, mode_flags %lu",
+ dsi->lanes, dsi->format, dsi->mode_flags);
+ ret = devm_mipi_dsi_attach(dev, dsi);
+
+ if (ret) {
+ dev_err(dev, "failed to attach dsi device %d", port);
+ return ret;
+ }
+ }
+
+ it6162_poweron(it6162);
+ return 0;
+}
+
+static bool it6162_of_get_audio(struct it6162 *it6162)
+{
+ struct device_node *np = it6162->dev->of_node;
+ struct device_node *audio_port;
+
+ audio_port = of_graph_get_port_by_id(np, 2);
+ if (audio_port) {
+ of_node_put(audio_port);
+ return true;
+ }
+
+ return false;
+}
+
+static void it6162_parse_dt(struct it6162 *it6162)
+{
+ struct device_node *np = it6162->dev->of_node;
+
+ /* get hdcp support*/
+ it6162->en_hdcp = of_property_present(np, "ite,support-hdcp");
+}
+
+static int it6162_init_pdata(struct it6162 *it6162)
+{
+ struct device *dev = it6162->dev;
+
+ it6162->ivdd = devm_regulator_get(dev, "ivdd");
+ if (IS_ERR(it6162->ivdd))
+ return dev_err_probe(dev, PTR_ERR(it6162->ivdd),
+ "failed to get ivdd regulator");
+
+ it6162->pwr1833 = devm_regulator_get(dev, "ovdd1833");
+ if (IS_ERR(it6162->pwr1833))
+ return dev_err_probe(dev, PTR_ERR(it6162->pwr1833),
+ "failed to get ovdd1833 regulator");
+
+ it6162->ovdd = devm_regulator_get(dev, "ovdd");
+ if (IS_ERR(it6162->ovdd))
+ return dev_err_probe(dev, PTR_ERR(it6162->ovdd),
+ "failed to get ovdd regulator");
+
+ it6162->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(it6162->gpiod_reset))
+ return dev_err_probe(dev, PTR_ERR(it6162->gpiod_reset),
+ "failed to get reset gpio\n");
+
+ return 0;
+}
+
+static int it6162_bridge_attach(struct drm_bridge *bridge,
+ struct drm_encoder *encoder,
+ enum drm_bridge_attach_flags flags)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+ struct drm_device *drm = bridge->dev;
+
+ it6162->drm = drm;
+
+ if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
+ drm_dbg(drm,
+ "it6162 driver only copes with atomic updates");
+ return -EOPNOTSUPP;
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+it6162_bridge_mode_valid(struct drm_bridge *bridge,
+ const struct drm_display_info *info,
+ const struct drm_display_mode *mode)
+{
+ unsigned long long rate;
+
+ rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
+ if (rate == 0)
+ return MODE_NOCLOCK;
+
+ return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
+}
+
+static enum drm_connector_status
+it6162_bridge_detect(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162->power_on ? it6162_detect(it6162) :
+ connector_status_disconnected;
+}
+
+static void
+it6162_avi_to_video_setting(struct it6162 *it6162,
+ struct hdmi_avi_infoframe *avi_info,
+ struct it6162_video_settings *video)
+{
+ video->vic = avi_info->video_code;
+
+ switch (avi_info->picture_aspect) {
+ case HDMI_PICTURE_ASPECT_4_3:
+ video->h_aspect = 4;
+ video->v_aspect = 3;
+ break;
+ case HDMI_PICTURE_ASPECT_16_9:
+ video->h_aspect = 16;
+ video->v_aspect = 9;
+ break;
+ case HDMI_PICTURE_ASPECT_64_27:
+ video->h_aspect = 64;
+ video->v_aspect = 27;
+ break;
+ case HDMI_PICTURE_ASPECT_256_135:
+ video->h_aspect = 256;
+ video->v_aspect = 135;
+ break;
+ default:
+ video->h_aspect = 4;
+ video->v_aspect = 3;
+ break;
+ }
+
+ video->pix_rep = avi_info->pixel_repeat + 1;
+}
+
+static void
+it6162_display_mode_to_settings(struct it6162 *it6162,
+ struct drm_display_mode *mode,
+ struct it6162_video_settings *settings)
+{
+ struct drm_device *drm = it6162->drm;
+
+ if (mode->flags & DRM_MODE_FLAG_PHSYNC)
+ settings->hpol = 1;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ settings->vpol = 1;
+
+ if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+ settings->prog = 0;
+
+ settings->clock = mode->clock;
+ settings->hdew = mode->hdisplay;
+ settings->hfp = mode->hsync_start - mode->hdisplay;
+ settings->hsw = mode->hsync_end - mode->hsync_start;
+ settings->hbp = mode->htotal - mode->hsync_end;
+ settings->htotal = mode->htotal;
+
+ settings->vdew = mode->vdisplay;
+ settings->vfp = mode->vsync_start - mode->vdisplay;
+ settings->vsw = mode->vsync_end - mode->vsync_start;
+ settings->vbp = mode->vtotal - mode->vsync_end;
+ settings->vtotal = mode->vtotal;
+
+ drm_dbg(drm, "HActive = %u", settings->hdew);
+ drm_dbg(drm, "VActive = %u", settings->vdew);
+ drm_dbg(drm, "HTotal = %u", settings->htotal);
+ drm_dbg(drm, "VTotal = %u", settings->vtotal);
+ drm_dbg(drm, "PCLK = %ukhz", settings->clock);
+ drm_dbg(drm, "HFP = %u", settings->hfp);
+ drm_dbg(drm, "HSW = %u", settings->hsw);
+ drm_dbg(drm, "HBP = %u", settings->hbp);
+ drm_dbg(drm, "VFP = %u", settings->vfp);
+ drm_dbg(drm, "VSW = %u", settings->vsw);
+ drm_dbg(drm, "VBP = %u", settings->vbp);
+ drm_dbg(drm, "HPOL = %d", settings->hpol);
+ drm_dbg(drm, "VPOL = %d", settings->vpol);
+ drm_dbg(drm, "Progressive = %d", settings->prog);
+}
+
+static void it6162_bridge_atomic_enable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+ struct drm_crtc_state *crtc_state;
+ struct drm_connector_state *conn_state;
+ struct drm_connector *connector;
+ struct hdmi_avi_infoframe *avi;
+ struct it6162_video_settings video_setting;
+
+ drm_dbg(it6162->drm, "it6162_bridge_atomic_enable");
+ connector = drm_atomic_get_new_connector_for_encoder(state,
+ bridge->encoder);
+
+ if (!connector)
+ return;
+
+ conn_state = drm_atomic_get_new_connector_state(state, connector);
+ if (!conn_state)
+ return;
+
+ crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
+ if (!crtc_state)
+ return;
+
+ it6162->connector = connector;
+ it6162->content_protection = conn_state->content_protection;
+
+ drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
+ avi = &conn_state->hdmi.infoframes.avi.data.avi;
+ video_setting.colorspace = conn_state->hdmi.output_format;
+
+ it6162_avi_to_video_setting(it6162, avi, &video_setting);
+ it6162_display_mode_to_settings(it6162,
+ &crtc_state->mode,
+ &video_setting);
+
+ it6162_mipi_set_video_timing(it6162, &video_setting);
+
+ it6162_tx_enable(it6162);
+ it6162_mipi_enable(it6162);
+}
+
+static int it6162_bridge_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 *adj = &crtc_state->adjusted_mode;
+ struct drm_display_mode *mode = &crtc_state->mode;
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+ u32 hfp, hsw, hbp;
+ u32 clock;
+ u32 hfp_check;
+
+ clock = mode->clock;
+ hfp = mode->hsync_start - mode->hdisplay;
+ hsw = mode->hsync_end - mode->hsync_start;
+ hbp = mode->htotal - mode->hsync_end;
+
+ hfp_check = DIV_ROUND_UP(65 * clock, 1000000) + 4;
+ if (hfp >= hfp_check)
+ return 0;
+
+ drm_dbg(it6162->drm, "hfp_check %d", hfp_check);
+ if (hbp > hfp_check - hfp) {
+ adj->hsync_start = adj->hdisplay + hfp_check;
+ adj->hsync_end = adj->hsync_start + hsw;
+ }
+
+ return 0;
+}
+
+static void it6162_bridge_atomic_disable(struct drm_bridge *bridge,
+ struct drm_atomic_state *state)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ drm_dbg(it6162->drm, "it6162_bridge_atomic_disable");
+ it6162_tx_disable(it6162);
+ it6162_mipi_disable(it6162);
+}
+
+static const struct drm_edid *
+it6162_bridge_read_edid(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return drm_edid_read_custom(connector, it6162_get_edid_block, it6162);
+}
+
+static int it6162_audio_update_hw_params(struct it6162 *it6162,
+ struct it6162_audio *config,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *hparms)
+{
+ config->channel_number = hparms->channels;
+ config->type = LPCM;
+
+ switch (hparms->sample_rate) {
+ case 32000:
+ config->sample_rate = SAMPLE_RATE_32K;
+ break;
+ case 44100:
+ config->sample_rate = SAMPLE_RATE_44_1K;
+ break;
+ case 48000:
+ config->sample_rate = SAMPLE_RATE_48K;
+ break;
+ case 88200:
+ config->sample_rate = SAMPLE_RATE_88_2K;
+ break;
+ case 96000:
+ config->sample_rate = SAMPLE_RATE_96K;
+ break;
+ case 176400:
+ config->sample_rate = SAMPLE_RATE_176_4K;
+ break;
+ case 192000:
+ config->sample_rate = SAMPLE_RATE_192K;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (hparms->sample_width) {
+ case 16:
+ config->sample_width = WORD_LENGTH_16BIT;
+ break;
+ case 24:
+ config->sample_width = WORD_LENGTH_18BIT;
+ break;
+ case 20:
+ config->sample_width = WORD_LENGTH_24BIT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt->fmt) {
+ case HDMI_I2S:
+ config->select = I2S;
+ break;
+ case HDMI_SPDIF:
+ config->select = SPDIF;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int it6162_bridge_hdmi_audio_prepare(struct drm_bridge *bridge,
+ struct drm_connector *connector,
+ struct hdmi_codec_daifmt *fmt,
+ struct hdmi_codec_params *params)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+ struct it6162_audio config;
+
+ it6162_audio_update_hw_params(it6162, &config, fmt, params);
+ it6162_enable_audio(it6162, &config);
+
+ return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
+ ¶ms->cea);
+}
+
+static int it6162_bridge_hdmi_audio_startup(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ return 0;
+}
+
+static void it6162_bridge_hdmi_audio_shutdown(struct drm_bridge *bridge,
+ struct drm_connector *connector)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ it6162_disable_audio(it6162);
+}
+
+static enum drm_mode_status
+it6162_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ unsigned long long tmds_rate)
+{
+ /*IT6162 hdmi supports HDMI2.0 600Mhz*/
+ if (tmds_rate > 600000000)
+ return MODE_CLOCK_HIGH;
+
+ return MODE_OK;
+}
+
+static inline int it6162_write_infoframe(struct it6162 *it6162,
+ const u8 *buffer, size_t len)
+{
+ if (len > DATA_BUFFER_DEPTH)
+ return -EINVAL;
+
+ regmap_bulk_write(it6162->regmap,
+ OFFSET_DATA_BUFFER, buffer, len);
+ regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, len);
+ it6162_infoblock_host_set(it6162, HOST_SET_CEA_INFOFRAME);
+
+ return 0;
+}
+
+static inline int it6162_clear_infoframe(struct it6162 *it6162, u8 type)
+{
+ regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, 3);
+ regmap_write(it6162->regmap, OFFSET_DATA_BUFFER, type);
+ regmap_write(it6162->regmap, OFFSET_DATA_BUFFER + 1, 0x00);
+ regmap_write(it6162->regmap, OFFSET_DATA_BUFFER + 2, 0x00);
+ it6162_infoblock_host_set(it6162, HOST_SET_CEA_INFOFRAME);
+
+ return 0;
+}
+
+static int
+it6162_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
+ const u8 *buffer, size_t len)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_write_infoframe(it6162, buffer, len);
+}
+
+static int
+it6162_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_AVI);
+}
+
+static int
+it6162_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
+ const u8 *buffer, size_t len)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_write_infoframe(it6162, buffer, len);
+}
+
+static int
+it6162_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_AUDIO);
+}
+
+static int
+it6162_bridge_hdmi_write_spd_infoframe(struct drm_bridge *bridge,
+ const u8 *buffer, size_t len)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_write_infoframe(it6162, buffer, len);
+}
+
+static int
+it6162_bridge_hdmi_clear_spd_infoframe(struct drm_bridge *bridge)
+{
+ struct it6162 *it6162 = bridge_to_it6162(bridge);
+
+ return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_SPD);
+}
+
+static const struct drm_bridge_funcs it6162_bridge_funcs = {
+ .attach = it6162_bridge_attach,
+ .mode_valid = it6162_bridge_mode_valid,
+ .detect = it6162_bridge_detect,
+
+ .atomic_enable = it6162_bridge_atomic_enable,
+ .atomic_disable = it6162_bridge_atomic_disable,
+ .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
+ .atomic_reset = drm_atomic_helper_bridge_reset,
+ .atomic_check = it6162_bridge_atomic_check,
+
+ .edid_read = it6162_bridge_read_edid,
+
+ .hdmi_clear_avi_infoframe = it6162_bridge_hdmi_clear_avi_infoframe,
+ .hdmi_write_avi_infoframe = it6162_bridge_hdmi_write_avi_infoframe,
+ .hdmi_clear_spd_infoframe = it6162_bridge_hdmi_clear_spd_infoframe,
+ .hdmi_write_spd_infoframe = it6162_bridge_hdmi_write_spd_infoframe,
+ .hdmi_clear_audio_infoframe = it6162_bridge_hdmi_clear_audio_infoframe,
+ .hdmi_write_audio_infoframe = it6162_bridge_hdmi_write_audio_infoframe,
+
+ .hdmi_tmds_char_rate_valid = it6162_hdmi_tmds_char_rate_valid,
+ .hdmi_audio_prepare = it6162_bridge_hdmi_audio_prepare,
+ .hdmi_audio_startup = it6162_bridge_hdmi_audio_startup,
+ .hdmi_audio_shutdown = it6162_bridge_hdmi_audio_shutdown,
+};
+
+static int it6162_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = dev->of_node;
+ struct it6162 *it6162;
+ int ret;
+
+ it6162 = devm_drm_bridge_alloc(dev, struct it6162, bridge,
+ &it6162_bridge_funcs);
+ if (IS_ERR(it6162))
+ return PTR_ERR(it6162);
+
+ it6162->dev = dev;
+
+ ret = it6162_of_get_dsi_host(it6162);
+ if (ret < 0)
+ return ret;
+
+ ret = it6162_i2c_regmap_init(client, it6162);
+ if (ret != 0)
+ return ret;
+
+ ret = it6162_init_pdata(it6162);
+ if (ret) {
+ dev_err(dev, "Failed to init_pdata %d", ret);
+ return ret;
+ }
+
+ it6162_config_default(it6162);
+ it6162_parse_dt(it6162);
+
+ if (it6162_detect_devices(it6162) < 0)
+ return -ENODEV;
+
+ if (!client->irq) {
+ dev_err(dev, "Failed to get INTP IRQ");
+ return -ENODEV;
+ }
+
+ ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
+ it6162_int_threaded_handler,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT |
+ IRQF_NO_AUTOEN,
+ "it6162-intp", it6162);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to request INTP threaded IRQ");
+
+ INIT_DELAYED_WORK(&it6162->hdcp_work, it6162_hdcp_work);
+
+ mutex_init(&it6162->lock);
+
+ it6162->bridge.of_node = np;
+ it6162->bridge.ops = DRM_BRIDGE_OP_DETECT | DRM_BRIDGE_OP_EDID |
+ DRM_BRIDGE_OP_MODES;
+
+ it6162->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
+
+ it6162->bridge.vendor = "ITE";
+ it6162->bridge.product = "IT6162";
+
+ if (it6162_of_get_audio(it6162)) {
+ /* enable audio support */
+ it6162->bridge.ops |= DRM_BRIDGE_OP_HDMI_AUDIO;
+ it6162->bridge.hdmi_audio_dev = dev;
+ it6162->bridge.hdmi_audio_max_i2s_playback_channels = 8;
+ it6162->bridge.hdmi_audio_dai_port = 2;
+ }
+
+ devm_drm_bridge_add(dev, &it6162->bridge);
+
+ return it6162_attach_dsi(it6162);
+}
+
+static void it6162_remove(struct i2c_client *client)
+{
+ struct it6162 *it6162 = i2c_get_clientdata(client);
+
+ disable_irq(client->irq);
+ cancel_delayed_work_sync(&it6162->hdcp_work);
+ mutex_destroy(&it6162->lock);
+}
+
+static const struct it6162_chip_info it6162_chip_info = {
+ .chip_id = 0x616200,
+ .version = 0x006500,
+};
+
+static const struct of_device_id it6162_dt_ids[] = {
+ { .compatible = "ite,it6162", .data = &it6162_chip_info},
+ { }
+};
+MODULE_DEVICE_TABLE(of, it6162_dt_ids);
+
+static const struct i2c_device_id it6162_i2c_ids[] = {
+ { "it6162", 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, it6162_i2c_ids);
+
+static struct i2c_driver it6162_driver = {
+ .driver = {
+ .name = "it6162",
+ .of_match_table = it6162_dt_ids,
+ },
+ .probe = it6162_probe,
+ .remove = it6162_remove,
+ .id_table = it6162_i2c_ids,
+};
+
+module_i2c_driver(it6162_driver);
+
+MODULE_AUTHOR("Pet Weng <pet.weng@ite.com.tw>");
+MODULE_AUTHOR("Hermes Wu <Hermes.Wu@ite.com.tw>");
+MODULE_DESCRIPTION("it6162 MIPI to HDMI driver");
+MODULE_LICENSE("GPL");
--
2.34.1
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
2026-03-09 9:42 ` [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge Hermes Wu via B4 Relay
@ 2026-03-09 10:30 ` Rob Herring (Arm)
2026-03-10 8:08 ` Krzysztof Kozlowski
1 sibling, 0 replies; 10+ messages in thread
From: Rob Herring (Arm) @ 2026-03-09 10:30 UTC (permalink / raw)
To: Hermes Wu
Cc: Jonas Karlman, Robert Foss, Simona Vetter, Hermes Wu,
Neil Armstrong, Krzysztof Kozlowski, Maxime Ripard,
Laurent Pinchart, Thomas Zimmermann, Maarten Lankhorst,
devicetree, linux-kernel, Kenneth.Hung, David Airlie,
Conor Dooley, dri-devel, Jernej Skrabec, Andrzej Hajda, Pet.Weng
On Mon, 09 Mar 2026 17:42:01 +0800, Hermes Wu wrote:
> Add device tree binding documentation for the ITE IT6162 MIPI DSI to
> HDMI 2.0 bridge chip. The IT6162 is an I2C-controlled bridge that
> supports the following configurations:
>
> - Single MIPI DSI input: up to 4K @ 30Hz
> - Dual MIPI DSI input (combined): up to 4K @ 60Hz
>
> The chip also supports up to 8-channel audio output via 4 I2S data
> channels.
>
> Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
> ---
> .../bindings/display/bridge/ite,it6162.yaml | 216 +++++++++++++++++++++
> 1 file changed, 216 insertions(+)
>
My bot found errors running 'make dt_binding_check' on your patch:
yamllint warnings/errors:
./Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml:216:7: [error] no new line character at the end of file (new-line-at-end-of-file)
dtschema/dtc warnings/errors:
doc reference errors (make refcheckdocs):
See https://patchwork.kernel.org/project/devicetree/patch/20260309-upstream-6162-v2-1-debdb6c88030@ite.com.tw
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] 10+ messages in thread
* Re: [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
@ 2026-03-09 15:23 ` kernel test robot
2026-03-09 22:26 ` kernel test robot
2026-03-10 8:18 ` Krzysztof Kozlowski
2 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2026-03-09 15:23 UTC (permalink / raw)
To: Hermes Wu via B4 Relay, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: llvm, oe-kbuild-all, Pet.Weng, Kenneth.Hung, Hermes Wu, dri-devel,
devicetree, linux-kernel
Hi Hermes,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 2622649ad6cdbb3e77bfafc8c0fe686090b77f70]
url: https://github.com/intel-lab-lkp/linux/commits/Hermes-Wu-via-B4-Relay/dt-bindings-display-bridge-Add-ITE-IT6162-MIPI-DSI-to-HDMI-bridge/20260309-174457
base: 2622649ad6cdbb3e77bfafc8c0fe686090b77f70
patch link: https://lore.kernel.org/r/20260309-upstream-6162-v2-2-debdb6c88030%40ite.com.tw
patch subject: [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
config: hexagon-allmodconfig (https://download.01.org/0day-ci/archive/20260309/202603092305.W1fFHKL5-lkp@intel.com/config)
compiler: clang version 17.0.6 (https://github.com/llvm/llvm-project 6009708b4367171ccdbf4b5905cb6a803753fe18)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260309/202603092305.W1fFHKL5-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/202603092305.W1fFHKL5-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/gpu/drm/bridge/ite-it6162.c:728:7: warning: variable 'cp_status' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
728 | if (it6162->hdcp_sts != hdcp_sts ||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
729 | it6162->hdcp_sts == NO_HDCP_STATE) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/gpu/drm/bridge/ite-it6162.c:759:57: note: uninitialized use occurs here
759 | drm_hdcp_update_content_protection(it6162->connector, cp_status);
| ^~~~~~~~~
drivers/gpu/drm/bridge/ite-it6162.c:728:3: note: remove the 'if' if its condition is always true
728 | if (it6162->hdcp_sts != hdcp_sts ||
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
729 | it6162->hdcp_sts == NO_HDCP_STATE) {
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/gpu/drm/bridge/ite-it6162.c:703:15: note: initialize the variable 'cp_status' to silence this warning
703 | u64 cp_status;
| ^
| = 0
1 warning generated.
vim +728 drivers/gpu/drm/bridge/ite-it6162.c
695
696 static void it6162_hdcp_handler(struct it6162 *it6162)
697 {
698 struct regmap *regmap = it6162->regmap;
699 unsigned int tx_status, sink_cap;
700 enum hdcp_state hdcp_sts;
701 struct it6162_hdcp_cfg *hdcp_cfg = &it6162->hdcp_cfg;
702 u8 hdcp_ver;
703 u64 cp_status;
704
705 if (hdcp_cfg->hdcp_version == NO_HDCP || !it6162->en_hdcp) {
706 drm_dbg(it6162->drm, "HDCP not enabled, skip hdcp check");
707 return;
708 }
709
710 regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
711 regmap_read(regmap, OFFSET_SINK_CAP, &sink_cap);
712
713 drm_dbg(it6162->drm, "Tx status %x", tx_status);
714 drm_dbg(it6162->drm, "SINK capability %x", sink_cap);
715
716 if (!GET_TX_VIDEO_STATUS(tx_status)) {
717 drm_dbg(it6162->drm, "video not stable, skip hdcp check");
718 return;
719 }
720
721 hdcp_sts = GET_TX_HDCP_STATUS(tx_status);
722 hdcp_ver = GET_SINK_CAP_HDCP_VER(sink_cap);
723 drm_dbg(it6162->drm, "hdcp status: %x->%x, version: %x-%x",
724 it6162->hdcp_sts, hdcp_sts,
725 it6162->hdcp_version, hdcp_ver);
726
727 if (it6162->hdcp_version != NO_HDCP) {
> 728 if (it6162->hdcp_sts != hdcp_sts ||
729 it6162->hdcp_sts == NO_HDCP_STATE) {
730 it6162->hdcp_sts = hdcp_sts;
731 cp_status = DRM_MODE_CONTENT_PROTECTION_DESIRED;
732 switch (hdcp_sts) {
733 case AUTH_DONE:
734 drm_dbg(it6162->drm, "HDCP AUTH DONE");
735 it6162_update_hdcp(it6162);
736 cp_status = DRM_MODE_CONTENT_PROTECTION_ENABLED;
737 break;
738 case AUTH_FAIL:
739 drm_dbg(it6162->drm, "HDCP AUTH FAIL");
740 if (hdcp_ver == HDCP_23) {
741 drm_dbg(it6162->drm,
742 "HDCP 2.3 auth fail, change to HDCP 1.4");
743 it6162_tx_hdcp_setup(it6162,
744 HDCP_14,
745 true);
746 } else {
747 it6162_tx_hdcp_disable(it6162);
748 }
749
750 break;
751 default:
752 drm_dbg(it6162->drm, "HDCP NO AUTH");
753 it6162_tx_hdcp_setup(it6162,
754 it6162->hdcp_version,
755 true);
756 break;
757 }
758 }
759 drm_hdcp_update_content_protection(it6162->connector, cp_status);
760 }
761 }
762
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
2026-03-09 15:23 ` kernel test robot
@ 2026-03-09 22:26 ` kernel test robot
2026-03-10 8:18 ` Krzysztof Kozlowski
2 siblings, 0 replies; 10+ messages in thread
From: kernel test robot @ 2026-03-09 22:26 UTC (permalink / raw)
To: Hermes Wu via B4 Relay, Andrzej Hajda, Neil Armstrong,
Robert Foss, Laurent Pinchart, Jonas Karlman, Jernej Skrabec,
David Airlie, Simona Vetter, Maarten Lankhorst, Maxime Ripard,
Thomas Zimmermann, Rob Herring, Krzysztof Kozlowski, Conor Dooley
Cc: oe-kbuild-all, Pet.Weng, Kenneth.Hung, Hermes Wu, dri-devel,
devicetree, linux-kernel
Hi Hermes,
kernel test robot noticed the following build warnings:
[auto build test WARNING on 2622649ad6cdbb3e77bfafc8c0fe686090b77f70]
url: https://github.com/intel-lab-lkp/linux/commits/Hermes-Wu-via-B4-Relay/dt-bindings-display-bridge-Add-ITE-IT6162-MIPI-DSI-to-HDMI-bridge/20260309-174457
base: 2622649ad6cdbb3e77bfafc8c0fe686090b77f70
patch link: https://lore.kernel.org/r/20260309-upstream-6162-v2-2-debdb6c88030%40ite.com.tw
patch subject: [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
config: xtensa-randconfig-r053-20260310 (https://download.01.org/0day-ci/archive/20260310/202603100655.k9Q6otfR-lkp@intel.com/config)
compiler: xtensa-linux-gcc (GCC) 13.4.0
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/202603100655.k9Q6otfR-lkp@intel.com/
cocci warnings: (new ones prefixed by >>)
>> drivers/gpu/drm/bridge/ite-it6162.c:861:36-41: WARNING: conversion to bool not needed here
vim +861 drivers/gpu/drm/bridge/ite-it6162.c
846
847 static bool it6162_wait_mcu_ready(struct it6162 *it6162)
848 {
849 struct device *dev = &it6162->it6162_i2c->dev;
850 unsigned int status;
851 int val;
852
853 status = readx_poll_timeout(it6162_wait_ready_event,
854 it6162,
855 val,
856 val == EVENT_READY,
857 100 * 1000,
858 1500 * 1000);
859
860 dev_dbg(dev, "%s status %d val %x", __func__, status, val);
> 861 return val == EVENT_READY ? true : false;
862 }
863
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
2026-03-09 9:42 ` [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge Hermes Wu via B4 Relay
2026-03-09 10:30 ` Rob Herring (Arm)
@ 2026-03-10 8:08 ` Krzysztof Kozlowski
2026-03-10 8:57 ` Hermes.Wu
1 sibling, 1 reply; 10+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-10 8:08 UTC (permalink / raw)
To: Hermes Wu
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Pet.Weng, Kenneth.Hung,
dri-devel, devicetree, linux-kernel
On Mon, Mar 09, 2026 at 05:42:01PM +0800, Hermes Wu wrote:
> Add device tree binding documentation for the ITE IT6162 MIPI DSI to
> HDMI 2.0 bridge chip. The IT6162 is an I2C-controlled bridge that
> supports the following configurations:
>
> - Single MIPI DSI input: up to 4K @ 30Hz
> - Dual MIPI DSI input (combined): up to 4K @ 60Hz
>
> The chip also supports up to 8-channel audio output via 4 I2S data
> channels.
<form letter>
This is a friendly reminder during the review process.
It looks like you received a tag and forgot to add it.
If you do not know the process, here is a short explanation:
Please add Acked-by/Reviewed-by/Tested-by tags when posting new
versions of patchset, under or above your Signed-off-by tag, unless
patch changed significantly (e.g. new properties added to the DT
bindings). Tag is "received", when provided in a message replied to you
on the mailing list. Tools like b4 can help here. However, there's no
need to repost patches *only* to add the tags. The upstream maintainer
will do that for tags received on the version they apply.
Please read:
https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
If a tag was not added on purpose, please state why and what changed.
</form letter>
>
> Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
> ---
> .../bindings/display/bridge/ite,it6162.yaml | 216 +++++++++++++++++++++
> 1 file changed, 216 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
> new file mode 100644
> index 0000000000000000000000000000000000000000..01aa33110a20b8ad5e2946ab5e01229dcb4cb5d3
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
> @@ -0,0 +1,216 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/display/bridge/ite,it6162.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ITE IT6162 MIPI DSI to HDMI 2.0 Bridge
> +
> +maintainers:
> + - Hermes Wu <Hermes.Wu@ite.com.tw>
> +
> +description: |
> + The ITE IT6162 is a high-performance, low-power HDMI bridge that converts
> + 2 MIPI DSI signals to 1 HDMI 2.0 output. It supports dual MIPI D-PHY 2.0
> + links up to 10 Gbps each (20 Gbps total), compatible with DSI-2 v2.0.
> +
> + The HDMI transmitter supports resolutions up to 4Kx2K@60Hz and is compliant
> + with HDMI 2.0 specifications.
> +
> + For audio, it supports up to 8-channel LPCM via I2S (multi-line or TDM mode),
> + with optional S/PDIF or DSD (for SACD). Audio sampling rates up to 192 kHz
> + are supported.
> +
> +allOf:
> + - $ref: /schemas/sound/dai-common.yaml#
> +
> +properties:
> + compatible:
> + const: ite,it6162
> +
> + reg:
> + maxItems: 1
> +
> + interrupts:
> + maxItems: 1
> +
> + reset-gpios:
> + maxItems: 1
> +
> + ivdd-supply:
> + description: Core voltage supply
> +
> + ovdd-supply:
> + description: I/O voltage supply
> +
> + ovdd1833-supply:
> + description: Flexible I/O voltage supply (1.8V domain)
> +
> + "#sound-dai-cells":
> + const: 0
> +
> + ite,support-hdcp:
> + description: >
> + Boolean property indicating that HDCP (High-bandwidth Digital Content
> + Protection) is supported and enabled on this board/hardware instance.
> +
> + When present, the driver may initialize and enable HDCP functionality
> + (typically HDCP 1.4 or higher depending on chip/firmware). If absent,
> + HDCP support is considered disabled or not implemented/wired.
How HDCP is being disabled in this chip? This does not look like
property for this device.
> +
> + Presence enables support; the property value is ignored (use as flag:
> + `ite,support-hdcp;`).
Drop, do not explain us how the DTS works.
> + type: boolean
> +
> + ports:
> + $ref: /schemas/graph.yaml#/properties/ports
> +
> + properties:
> + port@0:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + unevaluatedProperties: false
> + description: Input port for MIPI DSI-0 (first DSI lane pair; optional)
schema defines what is optional or not. Don't repeat constraints in free form text.
> +
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> + properties:
> + data-lanes:
> + minItems: 1
> + maxItems: 4
> + lane-polarities:
> + $ref: /schemas/types.yaml#/definitions/uint32-array
No, what is happening with this patch? It wasn't here.
None of these are correct, don't make random changes to the binding.
> + minItems: 1
> + maxItems: 5
> + items:
> + enum: [0, 1]
> + description: >
> + Array of lane polarities starting with clock lane, followed by
> + data lanes in the order given in data-lanes.
> + 0 = normal (active high), 1 = inverted (active low).
> + If omitted, all lanes are assumed normal (0).
> + clock-noncontinuous:
> + type: boolean
> + description: >
> + If present, allows MIPI DSI non-continuous clock mode
> + (clock lane can be stopped between transmissions for power saving).
> + required:
> + - data-lanes
> +
> + port@1:
> + $ref: /schemas/graph.yaml#/$defs/port-base
> + unevaluatedProperties: false
> + description: Input port for MIPI DSI-1 (second DSI lane pair; required)
> +
> + properties:
> + endpoint:
> + $ref: /schemas/media/video-interfaces.yaml#
> + unevaluatedProperties: false
> + properties:
> + data-lanes:
> + minItems: 1
> + maxItems: 4
> + lane-polarities:
> + $ref: /schemas/types.yaml#/definitions/uint32-array
> + minItems: 1
> + maxItems: 5
> + items:
> + enum: [0, 1]
> + description: >
> + Array of lane polarities starting with clock lane, followed by
> + data lanes in the order given in data-lanes.
> + 0 = normal (active high), 1 = inverted (active low).
> + If omitted, all lanes are assumed normal (0).
> + clock-noncontinuous:
> + type: boolean
> + description: >
> + If present, allows MIPI DSI non-continuous clock mode
> + (clock lane can be stopped between transmissions for power saving).
> + required:
> + - data-lanes
> +
> + port@2:
> + $ref: /schemas/graph.yaml#/properties/port
> + description: Audio input port (I2S; optional)
> +
> + port@3:
> + $ref: /schemas/graph.yaml#/properties/port
> + description: HDMI output port (optional)
> +
> + required:
> + - port@1 # Only DSI-1 port is mandatory per your request
per my request? What?
Again, Don't repeat constraints in free form text.
> +
> +required:
> + - compatible
> + - reg
> + - interrupts
> + - ports
> +
> +unevaluatedProperties: false
> +
> +examples:
> + - |
> + #include <dt-bindings/gpio/gpio.h>
> + #include <dt-bindings/interrupt-controller/irq.h>
> +
> + i2c {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + bridge@58 {
> + compatible = "ite,it6162";
> + reg = <0x58>;
> +
> + #sound-dai-cells = <0>;
> +
> + interrupt-parent = <&pio>;
> + interrupts = <128 IRQ_TYPE_LEVEL_LOW>;
> +
> + pinctrl-names = "default";
> + pinctrl-0 = <&it6162_pins>;
> +
> + reset-gpios = <&pio 127 GPIO_ACTIVE_LOW>;
> +
> + ivdd-supply = <&pp1000_hdmi_x>;
> + ovdd-supply = <&pp3300_vio28_x>;
> + ovdd1833-supply = <&pp1800_vcamio_x>;
> +
> + ite,support-hdcp; // HDCP enabled on this board
> +
> + ports {
> + #address-cells = <1>;
> + #size-cells = <0>;
> +
> + port@0 {
> + reg = <0>;
> + it6162_dsi0: endpoint {
> + data-lanes = < 1 2 3 4>;
> + remote-endpoint = <&dsi_0_out>;
> + };
> + };
> +
> + port@1 {
> + reg = <1>;
> + it6162_dsi1: endpoint {
> + data-lanes = < 1 2 3 4>;
> + remote-endpoint = <&dsi_1_out>;
> + };
> + };
> +
> + port@2 {
> + reg = <2>;
> + it6162_audio_in: endpoint {
> + remote-endpoint = <&i2s0_out>;
> + };
> + };
> +
> + port@3 {
> + reg = <3>;
> + it6162_hdmi_out: endpoint {
> + remote-endpoint = <&hdmi_connector_in>;
> + };
> + };
> + };
> + };
> + };
> \ No newline at end of file
You have patch warnings.
Write detailed changelog explaining WHY you ignore or drop people's
review and WHY you are doing these changes.
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
2026-03-09 15:23 ` kernel test robot
2026-03-09 22:26 ` kernel test robot
@ 2026-03-10 8:18 ` Krzysztof Kozlowski
2 siblings, 0 replies; 10+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-10 8:18 UTC (permalink / raw)
To: Hermes Wu
Cc: Andrzej Hajda, Neil Armstrong, Robert Foss, Laurent Pinchart,
Jonas Karlman, Jernej Skrabec, David Airlie, Simona Vetter,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Pet.Weng, Kenneth.Hung,
dri-devel, devicetree, linux-kernel
On Mon, Mar 09, 2026 at 05:42:02PM +0800, Hermes Wu wrote:
> +
> +static int it6162_infoblock_complete(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + struct regmap *regmap = it6162->regmap;
> + unsigned int val;
> + int ret;
> +
> + ret = regmap_read(regmap, OFFSET_HOST_SET, &val);
> + if (ret < 0)
> + return dev_err_probe(dev, ret,
> + "read failed rx reg[0x%x]",
> + OFFSET_HOST_SET);
How is this probe path?
> +
> + return val;
> +}
> +
> +static int it6162_infoblock_host_set(struct it6162 *it6162, u8 setting)
> +{
> + struct device *dev = it6162->dev;
> + int status;
> + int val;
> +
> + regmap_write(it6162->regmap, OFFSET_HOST_SET, setting);
> + /*wait command complete*/
> + status = readx_poll_timeout(it6162_infoblock_complete,
> + it6162,
> + val,
> + val <= 0,
> + 50 * 1000,
> + TIMEOUT_INFOBLOCK_MS * 1000);
> +
> + if (status < 0 || val != 0) {
> + dev_err(dev, "%s err status = %d, val = %d", __func__,
> + status, val);
> + return -ETIMEDOUT;
> + }
> +
> + return 0;
> +}
> +
> +static int it6162_infoblock_request_data(struct it6162 *it6162,
> + u8 setting, u8 index, u8 *buf)
> +{
> + struct device *dev = it6162->dev;
> + int status;
> + bool val = 0;
> +
> + it6162->data_buf_sts = NO_STS;
> + regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, index);
> + regmap_write(it6162->regmap, OFFSET_HOST_SET, setting);
> +
> + status = readx_poll_timeout(it6162_infoblock_complete,
> + it6162,
> + val,
> + val <= 0 && it6162->data_buf_sts == BUF_READY,
> + 50 * 1000,
> + TIMEOUT_INFOBLOCK_MS * 1000);
> +
> + if (status < 0 || val != 0) {
> + dev_err(dev,
> + "%s err status = %d %d",
> + __func__,
> + status,
> + it6162->data_buf_sts);
Completely messed formatting / wrapping. Please follow Linux coding style.
> + return -ETIMEDOUT;
> + }
> +
> + dev_dbg(dev, "%s [0x%x] 0x%x", __func__, setting, it6162->data_buf_sts);
> + if (it6162->data_buf_sts != BUF_READY)
> + return -EIO;
> +
> + regmap_bulk_read(it6162->regmap,
> + OFFSET_DATA_BUFFER, buf, DATA_BUFFER_DEPTH);
> + return 0;
> +}
> +
> +static void it6162_infoblock_mipi_config(struct it6162 *it6162)
> +{
> + struct it6162_mipi_cfg *cfg = &it6162->mipi_cfg;
> + u8 cfg_val = 0;
> +
> + cfg_val = FIELD_PREP(MIPI_CLOCK_MODE_MASK, cfg->continuous_clk) |
> + FIELD_PREP(MIPI_LANE_SWAP_MASK, cfg->lane_swap) |
> + FIELD_PREP(MIPI_PN_SWAP_MASK, cfg->pn_swap) |
> + FIELD_PREP(MIPI_LANE_NUM_MASK, cfg->lane_num - 1);
> +
> + dev_dbg(it6162->dev, "%s 0x%02x 0x%02x", __func__,
> + cfg_val, cfg->mode);
So here dev_dbg but in all other places drm_dbg - decide on one.
...
> +
> + drm_dbg(it6162->drm, "%s ver %x enc %d", __func__, ver, encription);
Look.
And what is "encription"?
> +
> + if (ver != NO_HDCP) {
> + tx_out.hdcp_version = ver;
> + tx_out.hdcp_encyption = encription;
> + tx_out.stream_ID = 0;
> + it6162_tx_hdcp_enable(it6162, &tx_out);
> + } else {
> + it6162_tx_hdcp_disable(it6162);
> + }
> +}
> +
> +static void it6162_tx_enable(struct it6162 *it6162)
> +{
> + if (!it6162->en_hdcp)
> + it6162->hdcp_version = NO_HDCP;
> + else
> + it6162->hdcp_version = it6162->hdcp_cfg.hdcp_version;
> +
> + drm_dbg(it6162->drm, "%s %d", __func__, it6162->hdcp_version);
Nope, that's pretty useless debug. You will be printing this on every
enable/disable.
> +}
> +
> +static void it6162_tx_disable(struct it6162 *it6162)
> +{
> + if (it6162->en_hdcp) {
> + cancel_delayed_work_sync(&it6162->hdcp_work);
> + it6162_tx_hdcp_setup(it6162, NO_HDCP, false);
> + }
> + drm_dbg(it6162->drm, "%s %d", __func__, it6162->hdcp_version);
> +}
> +
> +static inline void
> +it6162_pack_video_setting(struct it6162 *it6162,
> + struct it6162_video_settings *settings,
> + struct it6162_infoblock_msg *msg)
> +{
> + msg->msg[0x00] = settings->hdew & 0xFF;
> + msg->msg[0x01] = (settings->hdew >> 8) & 0x3F;
> + msg->msg[0x02] = settings->vdew & 0xFF;
> + msg->msg[0x03] = (settings->vdew >> 8) & 0x3F;
> + msg->msg[0x04] = settings->clock & 0xFF;
> + msg->msg[0x05] = (settings->clock >> 8) & 0xFF;
> + msg->msg[0x06] = (settings->clock >> 16) & 0xFF;
> + msg->msg[0x07] = (settings->clock >> 24) & 0xFF;
> + msg->msg[0x08] = settings->hfp & 0xFF;
> + msg->msg[0x09] = (settings->hfp >> 8) & 0x3F;
> + msg->msg[0x0A] = settings->hsw & 0xFF;
> + msg->msg[0x0B] = (settings->hsw >> 8) & 0x3F;
> + msg->msg[0x0C] = settings->hbp & 0xFF;
> + msg->msg[0x0D] = (settings->hbp >> 8) & 0x3F;
> + msg->msg[0x0E] = settings->vfp & 0xFF;
> + msg->msg[0x0F] = (settings->vfp >> 8) & 0x3F;
> + msg->msg[0x10] = settings->vsw & 0xFF;
> + msg->msg[0x11] = (settings->vsw >> 8) & 0x3F;
> + msg->msg[0x12] = settings->vbp & 0xFF;
> + msg->msg[0x13] = (settings->vbp >> 8) & 0x3F;
> + msg->msg[0x14] = (settings->prog << 2) |
> + (settings->vpol << 1) |
> + settings->hpol;
> +
> + msg->msg[0x15] = settings->v_aspect;
> + msg->msg[0x16] = settings->h_aspect & 0xFF;
> + msg->msg[0x17] = settings->h_aspect >> 8;
> + msg->msg[0x18] = settings->pix_rep;
> + msg->msg[0x19] = settings->vic;
> + msg->msg[0x1A] = settings->colorspace;
> + msg->msg[0x1B] = 1;
> +
> + msg->len = 0x1C;
> + msg->action = HOST_SET_VIDEO_INFO;
> +}
> +
> +static void it6162_mipi_set_video_timing(struct it6162 *it6162,
> + struct it6162_video_settings *mode)
> +{
> + struct it6162_infoblock_msg msg;
> +
> + it6162_pack_video_setting(it6162, mode, &msg);
> + guard(mutex)(&it6162->lock);
> + it6162_infoblock_write_msg(it6162, &msg);
> +}
> +
> +static int it6162_hdcp_read_infomation(struct it6162 *it6162,
> + u8 *status, u8 *bksv)
> +{
> + u8 buf[DATA_BUFFER_DEPTH];
> + int ret;
> +
> + guard(mutex)(&it6162->lock);
> + ret = it6162_infoblock_request_data(it6162,
> + HOST_SET_HDCP_R,
> + 0x00,
> + buf);
> + if (ret < 0)
> + return ret;
> +
> + if (status)
> + memcpy(status, buf, 2);
> +
> + if (bksv)
> + memcpy(bksv, buf + 2, 5);
> +
> + return 0;
> +}
> +
> +static int it6162_hdcp_read_list(struct it6162 *it6162,
> + u8 *ksv_list,
> + int dev_count)
> +{
> + u8 buf[DATA_BUFFER_DEPTH];
> + int i, j, ret;
> +
> + if (!ksv_list || dev_count <= 0)
> + return -EINVAL;
> +
> + guard(mutex)(&it6162->lock);
> +
> + for (i = 0; i < (dev_count / 6 + 1); i++) {
> + /* KsV lists */
> + ret = it6162_infoblock_request_data(it6162,
> + HOST_SET_HDCP_R,
> + i + 1,
> + buf);
> +
> + if (ret < 0)
> + return ret;
> +
> + for (j = 0; j < 30; j += 5) {
> + if ((i * 6 + j / 5) >= dev_count)
> + break;
> +
> + memcpy(&ksv_list[(i * 6 + j / 5) * 5], &buf[j], 5);
> + }
> + }
> +
> + return dev_count;
> +}
> +
> +static void it6162_update_hdcp14(struct it6162 *it6162)
> +{
> + struct drm_device *drm = it6162->drm;
> + int dev_count;
> + u8 bksv[5];
> + u8 bstatus[2];
> + u8 ksvlist[5 * 30];
> + int ret;
> +
> + ret = it6162_hdcp_read_infomation(it6162, bstatus, bksv);
> +
> + if (ret < 0) {
> + drm_err(drm, "read Bstatus fail!!!!");
Why errors are so screaming!!!!
> + return;
> + }
> + drm_dbg(drm, "status = 0x%02X%02X", bstatus[1], bstatus[0]);
> +
> + if (DRM_HDCP_MAX_DEVICE_EXCEEDED(bstatus[0]) ||
> + DRM_HDCP_MAX_CASCADE_EXCEEDED(bstatus[1])) {
> + drm_err(drm, "HDCP14 Max Topology Limit Exceeded");
> + return;
> + }
> +
> + dev_count = DRM_HDCP_NUM_DOWNSTREAM(bstatus[0]);
> + drm_dbg(drm, "dev_count %d", dev_count);
> + if (dev_count == 0)
> + return;
> +
> + dev_count = dev_count > 30 ? 30 : dev_count;
> + ret = it6162_hdcp_read_list(it6162, ksvlist, dev_count);
> +
Drop, there is never blank line between cmd and check of return value.
> + if (ret < 0) {
> + drm_err(drm, "read KSV list fail!!!!");
No need to stress the user!!!
> + return;
> + }
> +}
> +
> +static void it6162_update_hdcp23(struct it6162 *it6162)
> +{
> + struct drm_device *drm = it6162->drm;
> + int dev_count;
> + u8 rxid[5];
> + u8 rxinfo[2];
> + u8 rxid_list[5 * 30];
> + int ret;
> +
> + ret = it6162_hdcp_read_infomation(it6162, rxinfo, rxid);
> +
> + if (ret < 0) {
> + drm_err(drm, "read Rxinfo fail!!!!");
> + return;
> + }
> + drm_dbg(drm, "Rxinfo 0x%02X%02X", rxinfo[1], rxinfo[0]);
Do you debug every single register access?
> +
> + if (HDCP_2_2_MAX_CASCADE_EXCEEDED(rxinfo[1]) ||
> + HDCP_2_2_MAX_DEVS_EXCEEDED(rxinfo[1])) {
> + drm_err(drm, "Topology Max Size Exceeded");
> + return;
> + }
> +
> + dev_count = (HDCP_2_2_DEV_COUNT_HI(rxinfo[0]) << 4 |
> + HDCP_2_2_DEV_COUNT_LO(rxinfo[1]));
> + dev_count = dev_count > 30 ? 30 : dev_count;
> + if (dev_count == 0)
> + return;
> +
> + ret = it6162_hdcp_read_list(it6162, rxid_list, dev_count);
> + if (ret < 0) {
> + drm_err(drm, "read RxID list fail!!!!");
> + return;
> + }
> +}
> +
> +static void it6162_update_hdcp(struct it6162 *it6162)
> +{
> + if (it6162->hdcp_version == HDCP_23)
> + it6162_update_hdcp23(it6162);
> + else
> + it6162_update_hdcp14(it6162);
> +}
> +
> +static void it6162_hdcp_handler(struct it6162 *it6162)
> +{
> + struct regmap *regmap = it6162->regmap;
> + unsigned int tx_status, sink_cap;
> + enum hdcp_state hdcp_sts;
> + struct it6162_hdcp_cfg *hdcp_cfg = &it6162->hdcp_cfg;
> + u8 hdcp_ver;
> + u64 cp_status;
> +
> + if (hdcp_cfg->hdcp_version == NO_HDCP || !it6162->en_hdcp) {
> + drm_dbg(it6162->drm, "HDCP not enabled, skip hdcp check");
> + return;
> + }
> +
> + regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
> + regmap_read(regmap, OFFSET_SINK_CAP, &sink_cap);
> +
> + drm_dbg(it6162->drm, "Tx status %x", tx_status);
> + drm_dbg(it6162->drm, "SINK capability %x", sink_cap);
> +
> + if (!GET_TX_VIDEO_STATUS(tx_status)) {
> + drm_dbg(it6162->drm, "video not stable, skip hdcp check");
> + return;
> + }
> +
> + hdcp_sts = GET_TX_HDCP_STATUS(tx_status);
> + hdcp_ver = GET_SINK_CAP_HDCP_VER(sink_cap);
> + drm_dbg(it6162->drm, "hdcp status: %x->%x, version: %x-%x",
> + it6162->hdcp_sts, hdcp_sts,
> + it6162->hdcp_version, hdcp_ver);
> +
> + if (it6162->hdcp_version != NO_HDCP) {
> + if (it6162->hdcp_sts != hdcp_sts ||
> + it6162->hdcp_sts == NO_HDCP_STATE) {
> + it6162->hdcp_sts = hdcp_sts;
> + cp_status = DRM_MODE_CONTENT_PROTECTION_DESIRED;
> + switch (hdcp_sts) {
> + case AUTH_DONE:
> + drm_dbg(it6162->drm, "HDCP AUTH DONE");
> + it6162_update_hdcp(it6162);
> + cp_status = DRM_MODE_CONTENT_PROTECTION_ENABLED;
> + break;
> + case AUTH_FAIL:
> + drm_dbg(it6162->drm, "HDCP AUTH FAIL");
> + if (hdcp_ver == HDCP_23) {
> + drm_dbg(it6162->drm,
> + "HDCP 2.3 auth fail, change to HDCP 1.4");
> + it6162_tx_hdcp_setup(it6162,
> + HDCP_14,
> + true);
> + } else {
> + it6162_tx_hdcp_disable(it6162);
> + }
> +
> + break;
> + default:
> + drm_dbg(it6162->drm, "HDCP NO AUTH");
> + it6162_tx_hdcp_setup(it6162,
> + it6162->hdcp_version,
> + true);
> + break;
> + }
> + }
> + drm_hdcp_update_content_protection(it6162->connector, cp_status);
> + }
> +}
> +
> +static void it6162_interrupt_handler(struct it6162 *it6162)
> +{
> + unsigned int int_status, tx_status;
> + enum drm_connector_status connector_status;
> + struct device *dev = it6162->dev;
> + struct regmap *regmap = it6162->regmap;
> + int err;
> +
> + err = regmap_read(regmap, OFFSET_EVENT_CHG, &int_status);
> + if (err < 0) {
> + dev_err(dev, "read failed rx reg[0x%x] err: %d",
> + OFFSET_EVENT_CHG, err);
> + return;
> + }
> +
> + regmap_write(it6162->regmap, OFFSET_EVENT_CHG, 0xFF);
> +
> + if (!!GET_BUFFER_STATUS(int_status)) {
> + regmap_write(it6162->regmap, OFFSET_DRIVER_DATA, int_status);
> + it6162->data_buf_sts = GET_BUFFER_STATUS(int_status);
> + }
> +
> + if (!(int_status & EVENT_CHG))
> + return;
> +
> + drm_dbg(it6162->drm, "evnet change 0x%X", int_status);
> +
> + err = regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
> + if (err < 0) {
> + dev_err(dev, "read failed rx reg[0x%x] err: %d",
> + OFFSET_TX_STATUS, err);
> + return;
> + }
> + drm_dbg(it6162->drm, "Tx status %x", tx_status);
> +
> + connector_status = GET_TX_HPD_STATUS(tx_status) ?
> + connector_status_connected :
> + connector_status_disconnected;
> +
> + if (it6162->connector_status != connector_status) {
> + it6162->connector_status = connector_status;
> + drm_bridge_hpd_notify(&it6162->bridge,
> + it6162->connector_status);
> + }
> +
> + if (it6162->en_hdcp && GET_TX_VIDEO_STATUS(tx_status) &&
> + connector_status == connector_status_connected)
> + queue_delayed_work(system_wq,
> + &it6162->hdcp_work,
> + msecs_to_jiffies(2000));
> +}
> +
> +static int it6162_wait_ready_event(struct it6162 *it6162)
> +{
> + unsigned int val;
> + int ret;
> + struct device *dev = it6162->dev;
> + struct regmap *regmap = it6162->regmap;
> +
> + ret = regmap_read(regmap, OFFSET_EVENT_CHG, &val);
> + if (ret < 0) {
> + dev_err(dev, "read failed rx reg[0x%x] err: %d",
> + OFFSET_EVENT_CHG, ret);
> + return ret;
> + }
> + dev_dbg(dev, "%s val %x ret %d", __func__, val, ret);
Drop
> + if (val & EVENT_READY)
> + return EVENT_READY;
> +
> + ret = regmap_read(regmap, 0x00, &val);
> + if (ret < 0) {
> + dev_err(dev, "read failed rx reg[0x%x] err: %d",
> + OFFSET_EVENT_CHG, ret);
> + return ret;
> + }
> +
> + if (val == 0x61) {
> + dev_warn(dev, "MCU ready event missed, but reg[0x00] is 0x61, consider MCU ready");
> + return EVENT_READY;
> + }
> +
> + return 0;
> +}
> +
> +static bool it6162_wait_mcu_ready(struct it6162 *it6162)
> +{
> + struct device *dev = &it6162->it6162_i2c->dev;
> + unsigned int status;
> + int val;
> +
> + status = readx_poll_timeout(it6162_wait_ready_event,
> + it6162,
> + val,
> + val == EVENT_READY,
> + 100 * 1000,
> + 1500 * 1000);
> +
> + dev_dbg(dev, "%s status %d val %x", __func__, status, val);
Drop, start writing useful and informative debug messages, not junk of
register outputs overflowing dmesg.
> + return val == EVENT_READY ? true : false;
> +}
> +
> +static void it6162_reset_init(struct it6162 *it6162)
> +{
> + it6162_set_default_config(it6162);
> +}
> +
> +static int it6162_platform_set_power(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + int err;
> +
> + err = regulator_enable(it6162->ivdd);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to enable IVDD");
> +
> + err = regulator_enable(it6162->pwr1833);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to enable VDD1833");
> +
> + err = regulator_enable(it6162->ovdd);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to enable OVDD");
> +
> + usleep_range(10000, 20000);
> + gpiod_set_value_cansleep(it6162->gpiod_reset, 1);
> + usleep_range(1000, 2000);
> + gpiod_set_value_cansleep(it6162->gpiod_reset, 0);
> + usleep_range(10000, 20000);
> +
> + return 0;
> +}
> +
> +static int it6162_platform_clear_power(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + int err;
> +
> + err = regulator_disable(it6162->ivdd);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to disable IVDD");
> +
> + usleep_range(2000, 3000);
> +
> + err = regulator_disable(it6162->pwr1833);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to disable VDD1833");
> +
> + err = regulator_disable(it6162->ovdd);
> + if (err)
> + return dev_err_probe(dev, err, "Failed to disable OVDD");
> +
> + return 0;
> +}
> +
> +static int it6162_detect_devices(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + const struct it6162_chip_info *chip_info;
> + u32 chip_id, version;
> + u8 buf[6];
> +
> + if (it6162_platform_set_power(it6162) < 0)
> + return -ENODEV;
> + /*wait MCU ready event after power on*/
> + if (!it6162_wait_mcu_ready(it6162))
> + return -ENODEV;
> +
> + chip_info = of_device_get_match_data(dev);
> +
> + regmap_bulk_read(it6162->regmap,
> + OFFSET_CHIP_ID_L, &buf[0], 6);
> +
> + dev_info(dev, "chip id %02x %02x %02X", buf[0], buf[1], buf[2]);
> + dev_info(dev, "chip VER %02x %02x %02x", buf[3], buf[4], buf[5]);
Drop both. Driver must be silent on success.
> +
> + chip_id = (buf[0] << 16) | (buf[1] << 8) | (buf[2]);
> + version = (buf[3] << 16) | (buf[4] << 8) | (buf[5]);
> + dev_info(dev, "chip id 0x%06x, version 0x%06x", chip_id, version);
How many times you need to print it?
Driver must be silent on success.
> +
> + if (chip_id != chip_info->chip_id || version < chip_info->version) {
> + dev_err(dev, "chip_id 0x%06x != 0x%06x",
> + chip_id, chip_info->chip_id);
> + dev_err(dev, "version 0x%06x != 0x%06x",
> + version, chip_info->version);
And again here?
> +
> + return -ENODEV;
> + }
> +
> + return 0;
> +}
> +
> +static int __maybe_unused it6162_poweron(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + int err;
> +
> + dev_dbg(dev, "powered on Start");
No, drop. Don't debug standard kernel code paths. Kernel already gives
you tools to debug this.
> +
> + err = it6162_platform_set_power(it6162);
> + if (err < 0)
> + return err;
> + /*wait MCU ready event after power on*/
> + if (!it6162_wait_mcu_ready(it6162))
> + return -ENODEV;
> +
> + it6162->connector_status = connector_status_disconnected;
> + it6162_reset_init(it6162);
> +
> + enable_irq(it6162->it6162_i2c->irq);
> + dev_dbg(dev, "enable irq %d",
> + it6162->it6162_i2c->irq);
Drop
> +
> + it6162->power_on = true;
> + dev_info(dev, "it6162 poweron end");
Drop
> + return 0;
> +}
> +
> +static int __maybe_unused it6162_poweroff(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + int err;
> +
> + dev_dbg(dev, "powered off start");
Drop
> + disable_irq(it6162->it6162_i2c->irq);
> + dev_dbg(dev, "disable irq %d", it6162->it6162_i2c->irq);
Drop
> +
> + err = it6162_platform_clear_power(it6162);
> + if (err < 0)
> + return err;
> +
> + it6162->power_on = false;
> + dev_dbg(dev, "it6162 poweroff");
Drop. Your code is really unreadable. In so many places.
> + return 0;
> +}
> +
> +static void it6162_config_default(struct it6162 *it6162)
> +{
> + struct it6162_mipi_cfg *mipi_cfg = &it6162->mipi_cfg;
> + struct it6162_hdcp_cfg *hdcp_cfg = &it6162->hdcp_cfg;
> +
> + mipi_cfg->lane_num = 4;
> + mipi_cfg->pn_swap = false;
> + mipi_cfg->lane_swap = false;
> + mipi_cfg->en_port[0] = false;
> + mipi_cfg->en_port[1] = false;
> + mipi_cfg->continuous_clk = true;
> + mipi_cfg->mode = SYNC_EVENT;
> + mipi_cfg->format = MIPI_DSI_FMT_RGB888;
> + mipi_cfg->mode_flags = MIPI_DSI_MODE_VIDEO;
> +
> + it6162->en_hdcp = false;
> + hdcp_cfg->hdcp_version = HDCP_23;
> + hdcp_cfg->hdcp_encyption = true;
> + hdcp_cfg->stream_ID = 0;
> +
> + it6162->connector_status = connector_status_disconnected;
> +}
> +
> +static enum drm_connector_status it6162_detect(struct it6162 *it6162)
> +{
> + struct regmap *regmap = it6162->regmap;
> + unsigned int tx_status;
> +
> + regmap_read(regmap, OFFSET_TX_STATUS, &tx_status);
> +
> + it6162->connector_status = GET_TX_HPD_STATUS(tx_status) ?
> + connector_status_connected :
> + connector_status_disconnected;
> +
> + drm_dbg(it6162->drm, "%s connector_status %x", __func__,
> + it6162->connector_status);
> + return it6162->connector_status;
> +}
> +
> +static int it6162_get_edid_block(void *data, u8 *buf, unsigned int block,
> + size_t len)
> +{
> + struct it6162 *it6162 = data;
> + unsigned int cnt;
> + unsigned int i;
> + u8 config;
> +
> + if (len > EDID_LENGTH)
> + return -EINVAL;
> +
> + guard(mutex)(&it6162->lock);
> +
> + cnt = 0;
> + for (i = 0; i < EDID_LENGTH; i += DATA_BUFFER_DEPTH, cnt++) {
> + config = (block << 2) | (cnt);
> + if (it6162_infoblock_request_data(it6162,
> + HOST_SET_EDID_R,
> + config, buf + i) < 0)
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static void it6162_enable_audio(struct it6162 *it6162,
> + struct it6162_audio *config)
> +{
> + unsigned int val;
> +
> + guard(mutex)(&it6162->lock);
> + val = FIELD_PREP(MASK_AUDIO_CHANNEL_NUM, config->channel_number) |
> + FIELD_PREP(MASK_AUDIO_SELECT, config->select) |
> + FIELD_PREP(MASK_AUDIO_TYPE, config->type);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL0, val);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL1, config->sample_rate);
> + /* Standard i2s 16bit, 24bit */
> + val = FIELD_PREP(MASK_I2S_BUS_MODE, 0) |
> + FIELD_PREP(MASK_I2S_WORD_LEN, config->sample_width) |
> + FIELD_PREP(MASK_I2S_VALID, 1);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL2, val);
> + it6162_infoblock_host_set(it6162, HOST_SET_AUDIO_INFO);
> +}
> +
> +static void it6162_disable_audio(struct it6162 *it6162)
> +{
> + guard(mutex)(&it6162->lock);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL0, 0x00);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL1, 0x00);
> + regmap_write(it6162->regmap, OFFSET_AUDIO_CTRL2, 0x00);
> + it6162_infoblock_host_set(it6162, HOST_SET_AUDIO_INFO);
> +}
> +
> +static irqreturn_t it6162_int_threaded_handler(int unused, void *data)
> +{
> + struct it6162 *it6162 = data;
> +
> + it6162_interrupt_handler(it6162);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void it6162_hdcp_work(struct work_struct *work)
> +{
> + struct it6162 *it6162 = container_of(work,
> + struct it6162,
> + hdcp_work.work);
> +
> + it6162_hdcp_handler(it6162);
> +}
> +
> +static struct mipi_dsi_host *it6162_of_get_dsi_host_by_port(struct it6162 *it6162,
> + int port)
> +{
> + struct device_node *of = it6162->dev->of_node;
> + struct device_node *host_node;
> + struct device_node *endpoint;
> + struct mipi_dsi_host *dsi_host;
> +
> + endpoint = of_graph_get_endpoint_by_regs(of, port, -1);
> + if (!endpoint)
> + return ERR_PTR(-ENODEV);
> +
> + host_node = of_graph_get_remote_port_parent(endpoint);
> + of_node_put(endpoint);
> + if (!host_node)
> + return ERR_PTR(-ENODEV);
> +
> + dsi_host = of_find_mipi_dsi_host_by_node(host_node);
> + of_node_put(host_node);
> +
> + if (!dsi_host)
> + return ERR_PTR(-EPROBE_DEFER);
> +
> + return dsi_host;
> +}
> +
> +static int it6162_of_get_dsi_host(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + struct mipi_dsi_host *dsi_host;
> + int port, host_count = 0;
> +
> + for (port = 0; port < 2; port++) {
> + dsi_host = it6162_of_get_dsi_host_by_port(it6162, port);
> +
> + if (PTR_ERR(dsi_host) == -EPROBE_DEFER) {
> + dev_info(dev,
> + "DSI host for port %d not ready, defer probe",
NAK, you never print messages on probe deferral.
> + port);
> + return -EPROBE_DEFER;
> + }
> +
> + if (IS_ERR(dsi_host)) {
> + dev_info(dev, "DSI host for port %d not found", port);
> + continue;
> + }
> +
> + host_count++;
> + }
> +
> + dev_info(dev, "%s = %d", __func__, host_count);
No, how many times you need to inform user on basic things happening?
> + if (host_count == 0)
> + return -ENODEV;
> +
> + return 0;
> +}
> +
> +static int it6162_load_mipi_pars_from_port(struct it6162 *it6162, int port)
> +{
> + struct device_node *of = it6162->dev->of_node;
> + struct device_node *endpoint;
> + struct device *dev = it6162->dev;
> + struct it6162_mipi_cfg *mipicfg = &it6162->mipi_cfg;
> + u32 data_lanes[4] = {1};
> + u32 lane_polarities[5] = {0};
> + int dsi_lanes, i;
> +
> + endpoint = of_graph_get_endpoint_by_regs(of, port, -1);
> +
> + if (!endpoint)
> + return 0;
> +
> + dsi_lanes = drm_of_get_data_lanes_count(endpoint, 1, 4);
> +
> + if (dsi_lanes < 0)
> + return dsi_lanes;
> +
> + mipicfg->lane_num = dsi_lanes;
> +
> + of_property_read_u32_array(endpoint, "data-lanes",
> + data_lanes, dsi_lanes);
> + /* Support lane swapping [1 2 3 4] => [4 3 2 1] */
> + if (data_lanes[0] == 4)
> + mipicfg->lane_swap = true;
> +
> + of_property_read_u32_array(endpoint, "lane-polarities",
> + lane_polarities, dsi_lanes + 1);
> + /* Support Dp/Dn swapping all data lanes and clock lane must have same polarity */
> + if (lane_polarities[0] != 0)
> + mipicfg->pn_swap = true;
> +
> + for (i = 1; i <= dsi_lanes; i++)
> + if (lane_polarities[i] != lane_polarities[0])
> + dev_warn_once(dev, "invalid lane-polarities configuration");
> +
> + if (of_property_present(endpoint, "clock-noncontinuous")) {
> + mipicfg->mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
> + mipicfg->continuous_clk = false;
> + }
> +
> + of_node_put(endpoint);
> +
> + dev_info(dev, "lanes: %d pn_swap: %d, lane_swap: %d, mode_flags: %lu",
> + mipicfg->lane_num, mipicfg->pn_swap,
> + mipicfg->lane_swap, mipicfg->mode_flags);
And one more info based on static information. This is from DTS? So
drop.
> +
> + return dsi_lanes;
> +}
> +
> +static int it6162_attach_dsi(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> + struct device_node *np = dev->of_node;
> + const struct mipi_dsi_device_info info = {"it6162-mipi", 0, np};
> + struct mipi_dsi_device *dsi;
> + struct mipi_dsi_host *dsi_host;
> + struct it6162_mipi_cfg *mipi_cfg = &it6162->mipi_cfg;
> + int ret = 0;
> +
> + for (int port = 0; port < 2; port++) {
> + dsi_host = it6162_of_get_dsi_host_by_port(it6162, port);
> + if (IS_ERR(dsi_host))
> + continue;
> +
> + mipi_cfg->en_port[port] = true;
> +
> + if (!it6162->dsi) {
> + ret = it6162_load_mipi_pars_from_port(it6162, port);
> + if (ret <= 0)
> + return ret;
> + dev_info(dev, "DSI host loaded paras for port %d", port);
And here
> + it6162->dsi = dsi;
> + }
> +
> + dsi = devm_mipi_dsi_device_register_full(dev, dsi_host, &info);
> + if (IS_ERR(dsi)) {
> + dev_err(dev, "failed to create dsi device");
> + return PTR_ERR(dsi);
> + }
> +
> + dsi->lanes = mipi_cfg->lane_num;
> + dsi->format = mipi_cfg->format;
> + dsi->mode_flags = mipi_cfg->mode_flags;
> + dev_info(dev, "dsi lanes %d, format %d, mode_flags %lu",
> + dsi->lanes, dsi->format, dsi->mode_flags);
And here
> + ret = devm_mipi_dsi_attach(dev, dsi);
> +
> + if (ret) {
> + dev_err(dev, "failed to attach dsi device %d", port);
> + return ret;
> + }
> + }
> +
> + it6162_poweron(it6162);
> + return 0;
> +}
> +
> +static bool it6162_of_get_audio(struct it6162 *it6162)
> +{
> + struct device_node *np = it6162->dev->of_node;
> + struct device_node *audio_port;
> +
> + audio_port = of_graph_get_port_by_id(np, 2);
> + if (audio_port) {
> + of_node_put(audio_port);
> + return true;
> + }
> +
> + return false;
> +}
> +
> +static void it6162_parse_dt(struct it6162 *it6162)
> +{
> + struct device_node *np = it6162->dev->of_node;
> +
> + /* get hdcp support*/
> + it6162->en_hdcp = of_property_present(np, "ite,support-hdcp");
> +}
> +
> +static int it6162_init_pdata(struct it6162 *it6162)
> +{
> + struct device *dev = it6162->dev;
> +
> + it6162->ivdd = devm_regulator_get(dev, "ivdd");
> + if (IS_ERR(it6162->ivdd))
> + return dev_err_probe(dev, PTR_ERR(it6162->ivdd),
> + "failed to get ivdd regulator");
> +
> + it6162->pwr1833 = devm_regulator_get(dev, "ovdd1833");
> + if (IS_ERR(it6162->pwr1833))
> + return dev_err_probe(dev, PTR_ERR(it6162->pwr1833),
> + "failed to get ovdd1833 regulator");
> +
> + it6162->ovdd = devm_regulator_get(dev, "ovdd");
> + if (IS_ERR(it6162->ovdd))
> + return dev_err_probe(dev, PTR_ERR(it6162->ovdd),
> + "failed to get ovdd regulator");
> +
> + it6162->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
> + if (IS_ERR(it6162->gpiod_reset))
> + return dev_err_probe(dev, PTR_ERR(it6162->gpiod_reset),
> + "failed to get reset gpio\n");
> +
> + return 0;
> +}
> +
> +static int it6162_bridge_attach(struct drm_bridge *bridge,
> + struct drm_encoder *encoder,
> + enum drm_bridge_attach_flags flags)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> + struct drm_device *drm = bridge->dev;
> +
> + it6162->drm = drm;
> +
> + if (!drm_core_check_feature(drm, DRIVER_ATOMIC)) {
> + drm_dbg(drm,
> + "it6162 driver only copes with atomic updates");
> + return -EOPNOTSUPP;
> + }
> +
> + return 0;
> +}
> +
> +static enum drm_mode_status
> +it6162_bridge_mode_valid(struct drm_bridge *bridge,
> + const struct drm_display_info *info,
> + const struct drm_display_mode *mode)
> +{
> + unsigned long long rate;
> +
> + rate = drm_hdmi_compute_mode_clock(mode, 8, HDMI_COLORSPACE_RGB);
> + if (rate == 0)
> + return MODE_NOCLOCK;
> +
> + return bridge->funcs->hdmi_tmds_char_rate_valid(bridge, mode, rate);
> +}
> +
> +static enum drm_connector_status
> +it6162_bridge_detect(struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162->power_on ? it6162_detect(it6162) :
> + connector_status_disconnected;
> +}
> +
> +static void
> +it6162_avi_to_video_setting(struct it6162 *it6162,
> + struct hdmi_avi_infoframe *avi_info,
> + struct it6162_video_settings *video)
> +{
> + video->vic = avi_info->video_code;
> +
> + switch (avi_info->picture_aspect) {
> + case HDMI_PICTURE_ASPECT_4_3:
> + video->h_aspect = 4;
> + video->v_aspect = 3;
> + break;
> + case HDMI_PICTURE_ASPECT_16_9:
> + video->h_aspect = 16;
> + video->v_aspect = 9;
> + break;
> + case HDMI_PICTURE_ASPECT_64_27:
> + video->h_aspect = 64;
> + video->v_aspect = 27;
> + break;
> + case HDMI_PICTURE_ASPECT_256_135:
> + video->h_aspect = 256;
> + video->v_aspect = 135;
> + break;
> + default:
> + video->h_aspect = 4;
> + video->v_aspect = 3;
> + break;
> + }
> +
> + video->pix_rep = avi_info->pixel_repeat + 1;
> +}
> +
> +static void
> +it6162_display_mode_to_settings(struct it6162 *it6162,
> + struct drm_display_mode *mode,
> + struct it6162_video_settings *settings)
> +{
> + struct drm_device *drm = it6162->drm;
> +
> + if (mode->flags & DRM_MODE_FLAG_PHSYNC)
> + settings->hpol = 1;
> +
> + if (mode->flags & DRM_MODE_FLAG_NVSYNC)
> + settings->vpol = 1;
> +
> + if (mode->flags & DRM_MODE_FLAG_INTERLACE)
> + settings->prog = 0;
> +
> + settings->clock = mode->clock;
> + settings->hdew = mode->hdisplay;
> + settings->hfp = mode->hsync_start - mode->hdisplay;
> + settings->hsw = mode->hsync_end - mode->hsync_start;
> + settings->hbp = mode->htotal - mode->hsync_end;
> + settings->htotal = mode->htotal;
> +
> + settings->vdew = mode->vdisplay;
> + settings->vfp = mode->vsync_start - mode->vdisplay;
> + settings->vsw = mode->vsync_end - mode->vsync_start;
> + settings->vbp = mode->vtotal - mode->vsync_end;
> + settings->vtotal = mode->vtotal;
> +
> + drm_dbg(drm, "HActive = %u", settings->hdew);
> + drm_dbg(drm, "VActive = %u", settings->vdew);
> + drm_dbg(drm, "HTotal = %u", settings->htotal);
> + drm_dbg(drm, "VTotal = %u", settings->vtotal);
> + drm_dbg(drm, "PCLK = %ukhz", settings->clock);
> + drm_dbg(drm, "HFP = %u", settings->hfp);
> + drm_dbg(drm, "HSW = %u", settings->hsw);
> + drm_dbg(drm, "HBP = %u", settings->hbp);
> + drm_dbg(drm, "VFP = %u", settings->vfp);
> + drm_dbg(drm, "VSW = %u", settings->vsw);
> + drm_dbg(drm, "VBP = %u", settings->vbp);
> + drm_dbg(drm, "HPOL = %d", settings->hpol);
> + drm_dbg(drm, "VPOL = %d", settings->vpol);
> + drm_dbg(drm, "Progressive = %d", settings->prog);
> +}
> +
> +static void it6162_bridge_atomic_enable(struct drm_bridge *bridge,
> + struct drm_atomic_state *state)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> + struct drm_crtc_state *crtc_state;
> + struct drm_connector_state *conn_state;
> + struct drm_connector *connector;
> + struct hdmi_avi_infoframe *avi;
> + struct it6162_video_settings video_setting;
> +
> + drm_dbg(it6162->drm, "it6162_bridge_atomic_enable");
> + connector = drm_atomic_get_new_connector_for_encoder(state,
> + bridge->encoder);
> +
> + if (!connector)
> + return;
> +
> + conn_state = drm_atomic_get_new_connector_state(state, connector);
> + if (!conn_state)
> + return;
> +
> + crtc_state = drm_atomic_get_new_crtc_state(state, conn_state->crtc);
> + if (!crtc_state)
> + return;
> +
> + it6162->connector = connector;
> + it6162->content_protection = conn_state->content_protection;
> +
> + drm_atomic_helper_connector_hdmi_update_infoframes(connector, state);
> + avi = &conn_state->hdmi.infoframes.avi.data.avi;
> + video_setting.colorspace = conn_state->hdmi.output_format;
> +
> + it6162_avi_to_video_setting(it6162, avi, &video_setting);
> + it6162_display_mode_to_settings(it6162,
> + &crtc_state->mode,
> + &video_setting);
> +
> + it6162_mipi_set_video_timing(it6162, &video_setting);
> +
> + it6162_tx_enable(it6162);
> + it6162_mipi_enable(it6162);
> +}
> +
> +static int it6162_bridge_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 *adj = &crtc_state->adjusted_mode;
> + struct drm_display_mode *mode = &crtc_state->mode;
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> + u32 hfp, hsw, hbp;
> + u32 clock;
> + u32 hfp_check;
> +
> + clock = mode->clock;
> + hfp = mode->hsync_start - mode->hdisplay;
> + hsw = mode->hsync_end - mode->hsync_start;
> + hbp = mode->htotal - mode->hsync_end;
> +
> + hfp_check = DIV_ROUND_UP(65 * clock, 1000000) + 4;
> + if (hfp >= hfp_check)
> + return 0;
> +
> + drm_dbg(it6162->drm, "hfp_check %d", hfp_check);
> + if (hbp > hfp_check - hfp) {
> + adj->hsync_start = adj->hdisplay + hfp_check;
> + adj->hsync_end = adj->hsync_start + hsw;
> + }
> +
> + return 0;
> +}
> +
> +static void it6162_bridge_atomic_disable(struct drm_bridge *bridge,
> + struct drm_atomic_state *state)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + drm_dbg(it6162->drm, "it6162_bridge_atomic_disable");
> + it6162_tx_disable(it6162);
> + it6162_mipi_disable(it6162);
> +}
> +
> +static const struct drm_edid *
> +it6162_bridge_read_edid(struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return drm_edid_read_custom(connector, it6162_get_edid_block, it6162);
> +}
> +
> +static int it6162_audio_update_hw_params(struct it6162 *it6162,
> + struct it6162_audio *config,
> + struct hdmi_codec_daifmt *fmt,
> + struct hdmi_codec_params *hparms)
> +{
> + config->channel_number = hparms->channels;
> + config->type = LPCM;
> +
> + switch (hparms->sample_rate) {
> + case 32000:
> + config->sample_rate = SAMPLE_RATE_32K;
> + break;
> + case 44100:
> + config->sample_rate = SAMPLE_RATE_44_1K;
> + break;
> + case 48000:
> + config->sample_rate = SAMPLE_RATE_48K;
> + break;
> + case 88200:
> + config->sample_rate = SAMPLE_RATE_88_2K;
> + break;
> + case 96000:
> + config->sample_rate = SAMPLE_RATE_96K;
> + break;
> + case 176400:
> + config->sample_rate = SAMPLE_RATE_176_4K;
> + break;
> + case 192000:
> + config->sample_rate = SAMPLE_RATE_192K;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + switch (hparms->sample_width) {
> + case 16:
> + config->sample_width = WORD_LENGTH_16BIT;
> + break;
> + case 24:
> + config->sample_width = WORD_LENGTH_18BIT;
> + break;
> + case 20:
> + config->sample_width = WORD_LENGTH_24BIT;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + switch (fmt->fmt) {
> + case HDMI_I2S:
> + config->select = I2S;
> + break;
> + case HDMI_SPDIF:
> + config->select = SPDIF;
> + break;
> + default:
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int it6162_bridge_hdmi_audio_prepare(struct drm_bridge *bridge,
> + struct drm_connector *connector,
> + struct hdmi_codec_daifmt *fmt,
> + struct hdmi_codec_params *params)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> + struct it6162_audio config;
> +
> + it6162_audio_update_hw_params(it6162, &config, fmt, params);
> + it6162_enable_audio(it6162, &config);
> +
> + return drm_atomic_helper_connector_hdmi_update_audio_infoframe(connector,
> + ¶ms->cea);
> +}
> +
> +static int it6162_bridge_hdmi_audio_startup(struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + return 0;
> +}
> +
> +static void it6162_bridge_hdmi_audio_shutdown(struct drm_bridge *bridge,
> + struct drm_connector *connector)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + it6162_disable_audio(it6162);
> +}
> +
> +static enum drm_mode_status
> +it6162_hdmi_tmds_char_rate_valid(const struct drm_bridge *bridge,
> + const struct drm_display_mode *mode,
> + unsigned long long tmds_rate)
> +{
> + /*IT6162 hdmi supports HDMI2.0 600Mhz*/
> + if (tmds_rate > 600000000)
> + return MODE_CLOCK_HIGH;
> +
> + return MODE_OK;
> +}
> +
> +static inline int it6162_write_infoframe(struct it6162 *it6162,
> + const u8 *buffer, size_t len)
> +{
> + if (len > DATA_BUFFER_DEPTH)
> + return -EINVAL;
> +
> + regmap_bulk_write(it6162->regmap,
> + OFFSET_DATA_BUFFER, buffer, len);
> + regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, len);
> + it6162_infoblock_host_set(it6162, HOST_SET_CEA_INFOFRAME);
> +
> + return 0;
> +}
> +
> +static inline int it6162_clear_infoframe(struct it6162 *it6162, u8 type)
> +{
> + regmap_write(it6162->regmap, OFFSET_DATA_TYPE_IDX, 3);
> + regmap_write(it6162->regmap, OFFSET_DATA_BUFFER, type);
> + regmap_write(it6162->regmap, OFFSET_DATA_BUFFER + 1, 0x00);
> + regmap_write(it6162->regmap, OFFSET_DATA_BUFFER + 2, 0x00);
> + it6162_infoblock_host_set(it6162, HOST_SET_CEA_INFOFRAME);
> +
> + return 0;
> +}
> +
> +static int
> +it6162_bridge_hdmi_write_avi_infoframe(struct drm_bridge *bridge,
> + const u8 *buffer, size_t len)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_write_infoframe(it6162, buffer, len);
> +}
> +
> +static int
> +it6162_bridge_hdmi_clear_avi_infoframe(struct drm_bridge *bridge)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_AVI);
> +}
> +
> +static int
> +it6162_bridge_hdmi_write_audio_infoframe(struct drm_bridge *bridge,
> + const u8 *buffer, size_t len)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_write_infoframe(it6162, buffer, len);
> +}
> +
> +static int
> +it6162_bridge_hdmi_clear_audio_infoframe(struct drm_bridge *bridge)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_AUDIO);
> +}
> +
> +static int
> +it6162_bridge_hdmi_write_spd_infoframe(struct drm_bridge *bridge,
> + const u8 *buffer, size_t len)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_write_infoframe(it6162, buffer, len);
> +}
> +
> +static int
> +it6162_bridge_hdmi_clear_spd_infoframe(struct drm_bridge *bridge)
> +{
> + struct it6162 *it6162 = bridge_to_it6162(bridge);
> +
> + return it6162_clear_infoframe(it6162, HDMI_INFOFRAME_TYPE_SPD);
> +}
> +
> +static const struct drm_bridge_funcs it6162_bridge_funcs = {
> + .attach = it6162_bridge_attach,
> + .mode_valid = it6162_bridge_mode_valid,
> + .detect = it6162_bridge_detect,
> +
> + .atomic_enable = it6162_bridge_atomic_enable,
> + .atomic_disable = it6162_bridge_atomic_disable,
> + .atomic_duplicate_state = drm_atomic_helper_bridge_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> + .atomic_reset = drm_atomic_helper_bridge_reset,
> + .atomic_check = it6162_bridge_atomic_check,
> +
> + .edid_read = it6162_bridge_read_edid,
> +
> + .hdmi_clear_avi_infoframe = it6162_bridge_hdmi_clear_avi_infoframe,
> + .hdmi_write_avi_infoframe = it6162_bridge_hdmi_write_avi_infoframe,
> + .hdmi_clear_spd_infoframe = it6162_bridge_hdmi_clear_spd_infoframe,
> + .hdmi_write_spd_infoframe = it6162_bridge_hdmi_write_spd_infoframe,
> + .hdmi_clear_audio_infoframe = it6162_bridge_hdmi_clear_audio_infoframe,
> + .hdmi_write_audio_infoframe = it6162_bridge_hdmi_write_audio_infoframe,
> +
> + .hdmi_tmds_char_rate_valid = it6162_hdmi_tmds_char_rate_valid,
> + .hdmi_audio_prepare = it6162_bridge_hdmi_audio_prepare,
> + .hdmi_audio_startup = it6162_bridge_hdmi_audio_startup,
> + .hdmi_audio_shutdown = it6162_bridge_hdmi_audio_shutdown,
> +};
> +
> +static int it6162_probe(struct i2c_client *client)
> +{
> + struct device *dev = &client->dev;
> + struct device_node *np = dev->of_node;
> + struct it6162 *it6162;
> + int ret;
> +
> + it6162 = devm_drm_bridge_alloc(dev, struct it6162, bridge,
> + &it6162_bridge_funcs);
> + if (IS_ERR(it6162))
> + return PTR_ERR(it6162);
> +
> + it6162->dev = dev;
> +
> + ret = it6162_of_get_dsi_host(it6162);
> + if (ret < 0)
> + return ret;
> +
> + ret = it6162_i2c_regmap_init(client, it6162);
> + if (ret != 0)
> + return ret;
> +
> + ret = it6162_init_pdata(it6162);
> + if (ret) {
> + dev_err(dev, "Failed to init_pdata %d", ret);
Why do you print error message TWICE? Once here and in called function?
> + return ret;
> + }
> +
> + it6162_config_default(it6162);
> + it6162_parse_dt(it6162);
> +
> + if (it6162_detect_devices(it6162) < 0)
> + return -ENODEV;
> +
> + if (!client->irq) {
> + dev_err(dev, "Failed to get INTP IRQ");
> + return -ENODEV;
> + }
> +
> + ret = devm_request_threaded_irq(&client->dev, client->irq, NULL,
> + it6162_int_threaded_handler,
> + IRQF_TRIGGER_LOW | IRQF_ONESHOT |
> + IRQF_NO_AUTOEN,
> + "it6162-intp", it6162);
> + if (ret)
> + return dev_err_probe(dev, ret,
> + "Failed to request INTP threaded IRQ");
Drop, just return ret;
> +
> + INIT_DELAYED_WORK(&it6162->hdcp_work, it6162_hdcp_work);
> +
> + mutex_init(&it6162->lock);
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 10+ messages in thread
* RE: [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
2026-03-10 8:08 ` Krzysztof Kozlowski
@ 2026-03-10 8:57 ` Hermes.Wu
2026-03-10 9:33 ` Krzysztof Kozlowski
0 siblings, 1 reply; 10+ messages in thread
From: Hermes.Wu @ 2026-03-10 8:57 UTC (permalink / raw)
To: krzk
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, airlied, simona, maarten.lankhorst, mripard,
tzimmermann, robh, krzk+dt, conor+dt, Pet.Weng, Kenneth.Hung,
dri-devel, devicetree, linux-kernel
Hi
>On Mon, Mar 09, 2026 at 05:42:01PM +0800, Hermes Wu wrote:
>> Add device tree binding documentation for the ITE IT6162 MIPI DSI to
>> HDMI 2.0 bridge chip. The IT6162 is an I2C-controlled bridge that
>> supports the following configurations:
>>
>> - Single MIPI DSI input: up to 4K @ 30Hz
>> - Dual MIPI DSI input (combined): up to 4K @ 60Hz
>>
>> The chip also supports up to 8-channel audio output via 4 I2S data
>> channels.
>
><form letter>
>This is a friendly reminder during the review process.
>
>It looks like you received a tag and forgot to add it.
>
>If you do not know the process, here is a short explanation:
>Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions of patchset, under or above your Signed-off-by tag, unless patch changed significantly (e.g. new properties added to the DT bindings). Tag is "received", when provided in a message replied to you on the mailing list. Tools like b4 can help here. However, there's no need to repost patches *only* to add the tags. The upstream maintainer will do that for tags received on the version they apply.
new properties are add in this patch, so I removed the reviewed tag add by b4 tool.
>
>Please read:
>https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
>
>If a tag was not added on purpose, please state why and what changed.
></form letter>
>
>>
>> Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
>> ---
>> .../bindings/display/bridge/ite,it6162.yaml | 216 +++++++++++++++++++++
>> 1 file changed, 216 insertions(+)
>>
>> diff --git
>> a/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>> b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>> new file mode 100644
>> index
>> 0000000000000000000000000000000000000000..01aa33110a20b8ad5e2946ab5e01
>> 229dcb4cb5d3
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>> @@ -0,0 +1,216 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6162.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: ITE IT6162 MIPI DSI to HDMI 2.0 Bridge
>> +
>> +maintainers:
>> + - Hermes Wu <Hermes.Wu@ite.com.tw>
>> +
>> +description: |
>> + The ITE IT6162 is a high-performance, low-power HDMI bridge that
>> +converts
>> + 2 MIPI DSI signals to 1 HDMI 2.0 output. It supports dual MIPI
>> +D-PHY 2.0
>> + links up to 10 Gbps each (20 Gbps total), compatible with DSI-2 v2.0.
>> +
>> + The HDMI transmitter supports resolutions up to 4Kx2K@60Hz and is
>> + compliant with HDMI 2.0 specifications.
>> +
>> + For audio, it supports up to 8-channel LPCM via I2S (multi-line or
>> + TDM mode), with optional S/PDIF or DSD (for SACD). Audio sampling
>> + rates up to 192 kHz are supported.
>> +
>> +allOf:
>> + - $ref: /schemas/sound/dai-common.yaml#
>> +
>> +properties:
>> + compatible:
>> + const: ite,it6162
>> +
>> + reg:
>> + maxItems: 1
>> +
>> + interrupts:
>> + maxItems: 1
>> +
>> + reset-gpios:
>> + maxItems: 1
>> +
>> + ivdd-supply:
>> + description: Core voltage supply
>> +
>> + ovdd-supply:
>> + description: I/O voltage supply
>> +
>> + ovdd1833-supply:
>> + description: Flexible I/O voltage supply (1.8V domain)
>> +
>> + "#sound-dai-cells":
>> + const: 0
>> +
>> + ite,support-hdcp:
>> + description: >
>> + Boolean property indicating that HDCP (High-bandwidth Digital Content
>> + Protection) is supported and enabled on this board/hardware instance.
>> +
>> + When present, the driver may initialize and enable HDCP functionality
>> + (typically HDCP 1.4 or higher depending on chip/firmware). If absent,
>> + HDCP support is considered disabled or not implemented/wired.
>
>How HDCP is being disabled in this chip? This does not look like property for this device.
The HDCP is handled by FW inside the chip, and can be disabled.
>> +
>> + Presence enables support; the property value is ignored (use as flag:
>> + `ite,support-hdcp;`).
>
>Drop, do not explain us how the DTS works.
>
>> + type: boolean
>> +
>> + ports:
>> + $ref: /schemas/graph.yaml#/properties/ports
>> +
>> + properties:
>> + port@0:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + unevaluatedProperties: false
>> + description: Input port for MIPI DSI-0 (first DSI lane pair;
>> + optional)
>
>schema defines what is optional or not. Don't repeat constraints in free form text.
>
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> + properties:
>> + data-lanes:
>> + minItems: 1
>> + maxItems: 4
>> + lane-polarities:
>> + $ref: /schemas/types.yaml#/definitions/uint32-array
>
>No, what is happening with this patch? It wasn't here.
>
>None of these are correct, don't make random changes to the binding.
this line will remove in v3
the lane-polarities in video-interfaces.yaml, was use for Dn/Dp swap in driver
should I also removed the description of properties that already exist in video-interfaces.yaml?
>> + minItems: 1
>> + maxItems: 5
>> + items:
>> + enum: [0, 1]
>> + description: >
>> + Array of lane polarities starting with clock lane, followed by
>> + data lanes in the order given in data-lanes.
>> + 0 = normal (active high), 1 = inverted (active low).
>> + If omitted, all lanes are assumed normal (0).
>> + clock-noncontinuous:
>> + type: boolean
>> + description: >
>> + If present, allows MIPI DSI non-continuous clock mode
>> + (clock lane can be stopped between transmissions for power saving).
>> + required:
>> + - data-lanes
>> +
>> + port@1:
>> + $ref: /schemas/graph.yaml#/$defs/port-base
>> + unevaluatedProperties: false
>> + description: Input port for MIPI DSI-1 (second DSI lane pair;
>> + required)
>> +
>> + properties:
>> + endpoint:
>> + $ref: /schemas/media/video-interfaces.yaml#
>> + unevaluatedProperties: false
>> + properties:
>> + data-lanes:
>> + minItems: 1
>> + maxItems: 4
>> + lane-polarities:
>> + $ref: /schemas/types.yaml#/definitions/uint32-array
>> + minItems: 1
>> + maxItems: 5
>> + items:
>> + enum: [0, 1]
>> + description: >
>> + Array of lane polarities starting with clock lane, followed by
>> + data lanes in the order given in data-lanes.
>> + 0 = normal (active high), 1 = inverted (active low).
>> + If omitted, all lanes are assumed normal (0).
>> + clock-noncontinuous:
>> + type: boolean
>> + description: >
>> + If present, allows MIPI DSI non-continuous clock mode
>> + (clock lane can be stopped between transmissions for power saving).
>> + required:
>> + - data-lanes
>> +
>> + port@2:
>> + $ref: /schemas/graph.yaml#/properties/port
>> + description: Audio input port (I2S; optional)
>> +
>> + port@3:
>> + $ref: /schemas/graph.yaml#/properties/port
>> + description: HDMI output port (optional)
>> +
>> + required:
>> + - port@1 # Only DSI-1 port is mandatory per your request
>
>per my request? What?
sorry, I did not check this comment generate by tools.
>Again, Don't repeat constraints in free form text.
>
>> +
>> +required:
>> + - compatible
>> + - reg
>> + - interrupts
>> + - ports
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> + - |
>> + #include <dt-bindings/gpio/gpio.h>
>> + #include <dt-bindings/interrupt-controller/irq.h>
>> +
>> + i2c {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + bridge@58 {
>> + compatible = "ite,it6162";
>> + reg = <0x58>;
>> +
>> + #sound-dai-cells = <0>;
>> +
>> + interrupt-parent = <&pio>;
>> + interrupts = <128 IRQ_TYPE_LEVEL_LOW>;
>> +
>> + pinctrl-names = "default";
>> + pinctrl-0 = <&it6162_pins>;
>> +
>> + reset-gpios = <&pio 127 GPIO_ACTIVE_LOW>;
>> +
>> + ivdd-supply = <&pp1000_hdmi_x>;
>> + ovdd-supply = <&pp3300_vio28_x>;
>> + ovdd1833-supply = <&pp1800_vcamio_x>;
>> +
>> + ite,support-hdcp; // HDCP enabled on this board
>> +
>> + ports {
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> +
>> + port@0 {
>> + reg = <0>;
>> + it6162_dsi0: endpoint {
>> + data-lanes = < 1 2 3 4>;
>> + remote-endpoint = <&dsi_0_out>;
>> + };
>> + };
>> +
>> + port@1 {
>> + reg = <1>;
>> + it6162_dsi1: endpoint {
>> + data-lanes = < 1 2 3 4>;
>> + remote-endpoint = <&dsi_1_out>;
>> + };
>> + };
>> +
>> + port@2 {
>> + reg = <2>;
>> + it6162_audio_in: endpoint {
>> + remote-endpoint = <&i2s0_out>;
>> + };
>> + };
>> +
>> + port@3 {
>> + reg = <3>;
>> + it6162_hdmi_out: endpoint {
>> + remote-endpoint = <&hdmi_connector_in>;
>> + };
>> + };
>> + };
>> + };
>> + };
>> \ No newline at end of file
>
>You have patch warnings.
>
>Write detailed changelog explaining WHY you ignore or drop people's review and WHY you are doing these changes.
>
>Best regards,
>Krzysztof
>
>
BR,
Hermes
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge
2026-03-10 8:57 ` Hermes.Wu
@ 2026-03-10 9:33 ` Krzysztof Kozlowski
0 siblings, 0 replies; 10+ messages in thread
From: Krzysztof Kozlowski @ 2026-03-10 9:33 UTC (permalink / raw)
To: Hermes.Wu
Cc: andrzej.hajda, neil.armstrong, rfoss, Laurent.pinchart, jonas,
jernej.skrabec, airlied, simona, maarten.lankhorst, mripard,
tzimmermann, robh, krzk+dt, conor+dt, Pet.Weng, Kenneth.Hung,
dri-devel, devicetree, linux-kernel
On 10/03/2026 09:57, Hermes.Wu@ite.com.tw wrote:
>
> Hi
>
>> On Mon, Mar 09, 2026 at 05:42:01PM +0800, Hermes Wu wrote:
>>> Add device tree binding documentation for the ITE IT6162 MIPI DSI to
>>> HDMI 2.0 bridge chip. The IT6162 is an I2C-controlled bridge that
>>> supports the following configurations:
>>>
>>> - Single MIPI DSI input: up to 4K @ 30Hz
>>> - Dual MIPI DSI input (combined): up to 4K @ 60Hz
>>>
>>> The chip also supports up to 8-channel audio output via 4 I2S data
>>> channels.
>>
>> <form letter>
>> This is a friendly reminder during the review process.
>>
>> It looks like you received a tag and forgot to add it.
>>
>> If you do not know the process, here is a short explanation:
>> Please add Acked-by/Reviewed-by/Tested-by tags when posting new versions of patchset, under or above your Signed-off-by tag, unless patch changed significantly (e.g. new properties added to the DT bindings). Tag is "received", when provided in a message replied to you on the mailing list. Tools like b4 can help here. However, there's no need to repost patches *only* to add the tags. The upstream maintainer will do that for tags received on the version they apply.
>
> new properties are add in this patch, so I removed the reviewed tag add by b4 tool.
So read the docs. Where did you document it?
>
>>
>> Please read:
>> https://elixir.bootlin.com/linux/v6.12-rc3/source/Documentation/process/submitting-patches.rst#L577
What is explained here?
>>
>> If a tag was not added on purpose, please state why and what changed.
>> </form letter>
>>
>>>
>>> Signed-off-by: Hermes Wu <Hermes.wu@ite.com.tw>
>>> ---
>>> .../bindings/display/bridge/ite,it6162.yaml | 216 +++++++++++++++++++++
>>> 1 file changed, 216 insertions(+)
>>>
>>> diff --git
>>> a/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>>> b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>>> new file mode 100644
>>> index
>>> 0000000000000000000000000000000000000000..01aa33110a20b8ad5e2946ab5e01
>>> 229dcb4cb5d3
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/display/bridge/ite,it6162.yaml
>>> @@ -0,0 +1,216 @@
>>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) %YAML 1.2
>>> +---
>>> +$id: http://devicetree.org/schemas/display/bridge/ite,it6162.yaml#
>>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>>> +
>>> +title: ITE IT6162 MIPI DSI to HDMI 2.0 Bridge
>>> +
>>> +maintainers:
>>> + - Hermes Wu <Hermes.Wu@ite.com.tw>
>>> +
>>> +description: |
>>> + The ITE IT6162 is a high-performance, low-power HDMI bridge that
>>> +converts
>>> + 2 MIPI DSI signals to 1 HDMI 2.0 output. It supports dual MIPI
>>> +D-PHY 2.0
>>> + links up to 10 Gbps each (20 Gbps total), compatible with DSI-2 v2.0.
>>> +
>>> + The HDMI transmitter supports resolutions up to 4Kx2K@60Hz and is
>>> + compliant with HDMI 2.0 specifications.
>>> +
>>> + For audio, it supports up to 8-channel LPCM via I2S (multi-line or
>>> + TDM mode), with optional S/PDIF or DSD (for SACD). Audio sampling
>>> + rates up to 192 kHz are supported.
>>> +
>>> +allOf:
>>> + - $ref: /schemas/sound/dai-common.yaml#
>>> +
>>> +properties:
>>> + compatible:
>>> + const: ite,it6162
>>> +
>>> + reg:
>>> + maxItems: 1
>>> +
>>> + interrupts:
>>> + maxItems: 1
>>> +
>>> + reset-gpios:
>>> + maxItems: 1
>>> +
>>> + ivdd-supply:
>>> + description: Core voltage supply
>>> +
>>> + ovdd-supply:
>>> + description: I/O voltage supply
>>> +
>>> + ovdd1833-supply:
>>> + description: Flexible I/O voltage supply (1.8V domain)
>>> +
>>> + "#sound-dai-cells":
>>> + const: 0
>>> +
>>> + ite,support-hdcp:
>>> + description: >
>>> + Boolean property indicating that HDCP (High-bandwidth Digital Content
>>> + Protection) is supported and enabled on this board/hardware instance.
>>> +
>>> + When present, the driver may initialize and enable HDCP functionality
>>> + (typically HDCP 1.4 or higher depending on chip/firmware). If absent,
>>> + HDCP support is considered disabled or not implemented/wired.
>>
>> How HDCP is being disabled in this chip? This does not look like property for this device.
>
> The HDCP is handled by FW inside the chip, and can be disabled.
>
>>> +
>>> + Presence enables support; the property value is ignored (use as flag:
>>> + `ite,support-hdcp;`).
>>
>> Drop, do not explain us how the DTS works.
>>
>>> + type: boolean
>>> +
>>> + ports:
>>> + $ref: /schemas/graph.yaml#/properties/ports
>>> +
>>> + properties:
>>> + port@0:
>>> + $ref: /schemas/graph.yaml#/$defs/port-base
>>> + unevaluatedProperties: false
>>> + description: Input port for MIPI DSI-0 (first DSI lane pair;
>>> + optional)
>>
>> schema defines what is optional or not. Don't repeat constraints in free form text.
>>
>>> +
>>> + properties:
>>> + endpoint:
>>> + $ref: /schemas/media/video-interfaces.yaml#
>>> + unevaluatedProperties: false
>>> + properties:
>>> + data-lanes:
>>> + minItems: 1
>>> + maxItems: 4
>>> + lane-polarities:
>>> + $ref: /schemas/types.yaml#/definitions/uint32-array
>>
>> No, what is happening with this patch? It wasn't here.
>>
>> None of these are correct, don't make random changes to the binding.
>
> this line will remove in v3
>
> the lane-polarities in video-interfaces.yaml, was use for Dn/Dp swap in driver
>
> should I also removed the description of properties that already exist in video-interfaces.yaml?
>
>>> + minItems: 1
>>> + maxItems: 5
>>> + items:
>>> + enum: [0, 1]
>>> + description: >
>>> + Array of lane polarities starting with clock lane, followed by
>>> + data lanes in the order given in data-lanes.
>>> + 0 = normal (active high), 1 = inverted (active low).
>>> + If omitted, all lanes are assumed normal (0).
>>> + clock-noncontinuous:
>>> + type: boolean
>>> + description: >
>>> + If present, allows MIPI DSI non-continuous clock mode
>>> + (clock lane can be stopped between transmissions for power saving).
>>> + required:
>>> + - data-lanes
>>> +
>>> + port@1:
>>> + $ref: /schemas/graph.yaml#/$defs/port-base
>>> + unevaluatedProperties: false
>>> + description: Input port for MIPI DSI-1 (second DSI lane pair;
>>> + required)
>>> +
>>> + properties:
>>> + endpoint:
>>> + $ref: /schemas/media/video-interfaces.yaml#
>>> + unevaluatedProperties: false
>>> + properties:
>>> + data-lanes:
>>> + minItems: 1
>>> + maxItems: 4
>>> + lane-polarities:
>>> + $ref: /schemas/types.yaml#/definitions/uint32-array
>>> + minItems: 1
>>> + maxItems: 5
>>> + items:
>>> + enum: [0, 1]
>>> + description: >
>>> + Array of lane polarities starting with clock lane, followed by
>>> + data lanes in the order given in data-lanes.
>>> + 0 = normal (active high), 1 = inverted (active low).
>>> + If omitted, all lanes are assumed normal (0).
>>> + clock-noncontinuous:
>>> + type: boolean
>>> + description: >
>>> + If present, allows MIPI DSI non-continuous clock mode
>>> + (clock lane can be stopped between transmissions for power saving).
>>> + required:
>>> + - data-lanes
>>> +
>>> + port@2:
>>> + $ref: /schemas/graph.yaml#/properties/port
>>> + description: Audio input port (I2S; optional)
>>> +
>>> + port@3:
>>> + $ref: /schemas/graph.yaml#/properties/port
>>> + description: HDMI output port (optional)
>>> +
>>> + required:
>>> + - port@1 # Only DSI-1 port is mandatory per your request
>>
>> per my request? What?
>
> sorry, I did not check this comment generate by tools.
I don't want to deal with output coming from your tools. You should deal
with the tools, not me.
Also, learn about assisted tag, so you mark this patch correctly and we
can safely ignore it, for example.
>
>> Again, Don't repeat constraints in free form text.
>>
>>> +
>>> +required:
>>> + - compatible
>>> + - reg
>>> + - interrupts
>>> + - ports
>>> +
>>> +unevaluatedProperties: false
>>> +
>>> +examples:
>>> + - |
>>> + #include <dt-bindings/gpio/gpio.h>
>>> + #include <dt-bindings/interrupt-controller/irq.h>
>>> +
>>> + i2c {
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> +
>>> + bridge@58 {
>>> + compatible = "ite,it6162";
>>> + reg = <0x58>;
>>> +
>>> + #sound-dai-cells = <0>;
>>> +
>>> + interrupt-parent = <&pio>;
>>> + interrupts = <128 IRQ_TYPE_LEVEL_LOW>;
>>> +
>>> + pinctrl-names = "default";
>>> + pinctrl-0 = <&it6162_pins>;
>>> +
>>> + reset-gpios = <&pio 127 GPIO_ACTIVE_LOW>;
>>> +
>>> + ivdd-supply = <&pp1000_hdmi_x>;
>>> + ovdd-supply = <&pp3300_vio28_x>;
>>> + ovdd1833-supply = <&pp1800_vcamio_x>;
>>> +
>>> + ite,support-hdcp; // HDCP enabled on this board
>>> +
>>> + ports {
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> +
>>> + port@0 {
>>> + reg = <0>;
>>> + it6162_dsi0: endpoint {
>>> + data-lanes = < 1 2 3 4>;
>>> + remote-endpoint = <&dsi_0_out>;
>>> + };
>>> + };
>>> +
>>> + port@1 {
>>> + reg = <1>;
>>> + it6162_dsi1: endpoint {
>>> + data-lanes = < 1 2 3 4>;
>>> + remote-endpoint = <&dsi_1_out>;
>>> + };
>>> + };
>>> +
>>> + port@2 {
>>> + reg = <2>;
>>> + it6162_audio_in: endpoint {
>>> + remote-endpoint = <&i2s0_out>;
>>> + };
>>> + };
>>> +
>>> + port@3 {
>>> + reg = <3>;
>>> + it6162_hdmi_out: endpoint {
>>> + remote-endpoint = <&hdmi_connector_in>;
>>> + };
>>> + };
>>> + };
>>> + };
>>> + };
>>> \ No newline at end of file
>>
>> You have patch warnings.
>>
>> Write detailed changelog explaining WHY you ignore or drop people's review and WHY you are doing these changes.
>>
>> Best regards,
>> Krzysztof
>>
>>
> BR,
> Hermes
>
Best regards,
Krzysztof
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2026-03-10 9:33 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-09 9:42 [PATCH v2 0/2] Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
2026-03-09 9:42 ` [PATCH v2 1/2] dt-bindings: display: bridge: Add ITE IT6162 MIPI DSI to HDMI bridge Hermes Wu via B4 Relay
2026-03-09 10:30 ` Rob Herring (Arm)
2026-03-10 8:08 ` Krzysztof Kozlowski
2026-03-10 8:57 ` Hermes.Wu
2026-03-10 9:33 ` Krzysztof Kozlowski
2026-03-09 9:42 ` [PATCH v2 2/2] drm/bridge: Add ITE IT6162 MIPI DSI to HDMI bridge driver Hermes Wu via B4 Relay
2026-03-09 15:23 ` kernel test robot
2026-03-09 22:26 ` kernel test robot
2026-03-10 8:18 ` Krzysztof Kozlowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox